<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"
    xmlns:dc="http://purl.org/dc/elements/1.1/">
    <channel>
        <title>nyuu.page</title>
        <link>https://nyuu.page</link>
        <description><![CDATA[your #1 source for nyuu.page]]></description>
        <atom:link href="https://nyuu.page/rss.xml" rel="self"
                   type="application/rss+xml" />
        <lastBuildDate>Fri, 20 Dec 2024 00:00:00 UT</lastBuildDate>
        <item>
    <title>Saving Nanocap Speculators From Themselves</title>
    <link>https://nyuu.page/posts/2024-12-20-solidity/</link>
    <description><![CDATA[<div class="dropcap dropcap-i">
<p>I spent the summer of the 2021 cryptocurrency bull market fascinated by a hive of foolishness and deception: <a href="https://old.reddit.com/r/cryptomoonshots">/r/cryptomoonshots</a> (and, to a lesser extent, its analogues on discord and telegram). People’d post a token address (typically Binance Smart Chain (“BSC”), occasionally Ethereum (“Eth”)) along with a pitch or maybe a website and an inducement: “buy right now!”. The (implicit) conceit was “you, the reader, may have ‘missed bitcoin’, and ‘missed dogecoin’, but you can still ‘100x’… by buying <em>my token!</em>”.</p>
</div>
<p>All of the posts were scams, in the sense that there was no serious intention of delivering on what was promised. Within this there was variation in <em>how</em> scammy: timeframe, level of sophistication, and mechanics used to stack the deck against buyers.</p>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/note.webp" class="admonition-icon" alt="" width="128" height="128" />Note</span>
<div class="admonition-content">
<p>The ecosystem of that era deserves a full ethnography and I’ll give it one <em>eventually</em>. For now I’ll leave it at this: what made these scams effective was the cultural context of 2021. Many of the people buying this stuff were interacting with cryptocurrency for the first time, via installing trustwallet and then tap-for-tap following instructions on how to purchase and then swap BNB on pancakeswap, provided to them <em>by the person scamming them</em>. Suffice to say these often were not people who were actually reading the contracts of the stuff they were buying.</p>
</div>
</div>
<p>I’d read the smart contracts of incoming posts, and post an explanation of what the scam was. I occasionally got comments or DMs from people thanking me for advising them away from a scam. That was always nice.</p>
<p>Some of these investigations were posted on discords or telegrams I’m no longer in. But a bunch are preserved on my <a href="https://www.reddit.com/user/nyuutsu/comments/">reddit account</a>. This post aggregates case studies and explanations of some of the more popular or interesting tricks.</p>
<p>There is an <a href="#appendix">appendix</a> that defines jargon and concepts used in the post.</p>
<h2 id="how-to-do-fraud"><a href="#how-to-do-fraud">How To Do Fraud?</a></h2>
<p>The BEP-20 standard doesn’t say much about what the required functions must do internally. So you can do fraud by writing functions that subtly (or unsubtly) misbehave, in such a way where you wouldn’t notice it when buying but will find yourself unable to meaningfully sell. Many methods boil down to this.</p>
<h3 id="the-least-clever-one-its-a-secret"><a href="#the-least-clever-one-its-a-secret">The Least Clever One: “It’s A Secret”</a></h3>
<p>If you create a token on BSC, the block explorer <a href="https://bscscan.com">bscscan</a> will notice it and let people view the creation transaction, distribution of holders, contract bytecode, etc.</p>
<p>You can, optionally, upload your contract source code. Bscscan will compile it, check whether what it compiles to matches the bytecode it read from the chain, and if so, it deems your contract “verified” and will show your source code with your contract. Any reputable contract that isn’t trying to hide something (and, many that <em>are</em> trying to hide something) will undergo this “verification”. The contract is now “verified” and you can, if so inclined, read what it does via the provided solidity.</p>
<p>The most basic way to do fraud is to write a patently unfair contract that says something like “buyers can never sell”, not upload your source code, and hope some rube buys it on your say-so. This is <em>boring</em> since nobody gets to see the implementation details. Not <em>easily</em>, anyway.</p>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/blobwizard.webp" class="admonition-icon" alt="" width="128" height="128" />Info</span>
<div class="admonition-content">
<p>It is possible to decompile this bytecode. There are tools that do it. But like all disassembler output: what you get is going to be technically correct but a slog to make sense of.</p>
</div>
</div>
<p>When I was tallying up my reddit posts exposing scams, I stopped counting posts about this problem after the fifteenth or so. Examples: <a href="https://www.reddit.com/r/CryptoMoonShots/comments/nmp9m2/vibes_dev_team_doxing_amazing_early_project_low/gzq153l/">1</a>
<a href="https://www.reddit.com/r/CryptoMoonShots/comments/nny2x0/stellaris_officially_fair_launched_low_market_cap/gzx3sag/">2</a>
<a href="https://www.reddit.com/r/CryptoMoonShots/comments/nny4jt/nipple_token_officially_fair_launched_1k_mcap/gzx3tk4/">3</a>
<a href="https://www.reddit.com/r/CryptoMoonShots/comments/nny6xj/alm_alium_creates_the_bridge_for_trades_across/gzx3wtj/">4</a>
<a href="https://www.reddit.com/r/CryptoMoonShots/comments/noeo19/akamai_is_on_the_air_low_market_cap_just_released/gzzknnb/">5</a>
<a href="https://www.reddit.com/r/CryptoMoonShots/comments/npd4fo/silkmoon_fairlaunch_in_5_minutes_starting_at_1k/h04ehi3/">6</a>
<a href="https://www.reddit.com/r/CryptoMoonShots/comments/nrojsi/to_the_moon_and_not_back_rocket_1500_giveawaaybuy/h0hnya8/">7</a>
<a href="https://www.reddit.com/r/CryptoMoonShots/comments/nrol0e/diamond_token_dla_just_launched_new_technology/h0horin/">8</a>
<a href="https://www.reddit.com/r/CryptoMoonShots/comments/nso04c/create_built_on_polkafoundry_to_optimize_for_nft/h0nk6yo/">9</a>
<a href="https://www.reddit.com/r/CryptoMoonShots/comments/nso9qm/threesome_18_nft_moonsafe_5000x_gem_audited/h0nln57/">10</a>
<a href="https://www.reddit.com/r/CryptoMoonShots/comments/nt1yk3/goldenshiba_gda_fair_launch_in_minutes_5th_june/h0pmro6/">11</a>
<a href="https://www.reddit.com/r/CryptoMoonShots/comments/nt5l7m/just_started_1_minute_ago_pancakeswap_moonboobsio/h0q7o12/">12</a>
<a href="https://www.reddit.com/r/CryptoMoonShots/comments/nsooni/squirt_adult_nfts_platform_read_gem_100x_easily/h0nod36/">13</a></p>
<p>Here’s a case study we can dig into: <code>0x8eb2877ef365bb520eceb3b34c0c18afd2058c57</code>. Here was the title of its r/cryptomoonshots thread:</p>
<blockquote>
<p>$SQUIRT - Adult NFTs Platform - Read Gem 100x Easily - LP Locked [Unrugable] - Safu</p>
</blockquote>
<p><a href="https://bscscan.com/token/0x8eb2877ef365bb520eceb3b34c0c18afd2058c57#code">The source code is not provided</a>, so, it is most likely impossible to sell.</p>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/note.webp" class="admonition-icon" alt="" width="128" height="128" />Note</span>
<div class="admonition-content">
<p>We can be confident about this because there is <em>no</em> legitimate reason to withold the source code. The <em>only</em> reason to do this is to try to hide that something is wrong. The main thing that can be wrong is “you can’t sell”.</p>
</div>
</div>
<p>We’ll first do some quick checks to make sure this is the case (to make sure this is a good candidate for study), then we’ll do some reverse engineering to study <em>why</em> it can’t be sold. The <a href="https://poocoin.app/tokens/0x8eb2877ef365bb520eceb3b34c0c18afd2058c57">chart</a> looks like nobody ever sold. The <a href="https://bscscan.com/address/0x8eb2877ef365bb520eceb3b34c0c18afd2058c57#tokentxns">transaction log</a> has no sales. The <a href="https://bscscan.com/token/0x9e0615d1897707DE81445658c4756634cC1c777f">lp transaction log</a> shows liquidity being removed after a while. All signs point to fraud, so we’re clear to decompile this thing to try to <em>classify</em> that fraud.</p>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/note.webp" class="admonition-icon" alt="" width="128" height="128" />Note</span>
<div class="admonition-content">
<p>The examples below are machine decompilations of solidity bytecode. It started out as solidity source code that we do not have access to. It was compiled to bytecode. It has now been decompiled. What we get isn’t Solidity (nor is it e.g. <a href="https://docs.soliditylang.org/en/latest/yul.html">Yul</a>,) and is <em>quite ugly</em>, but we can use it to figure out what the EVM is doing when it runs the bytecode.</p>
</div>
</div>
<p>Using <a href="https://ethervm.io/decompile">EtherVM decompiler</a>, we can trace the transfer function. First we find the entry point:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode solidity"><code class="sourceCode solidity"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="op">}</span> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>var0 <span class="op">==</span> <span class="bn">0xa9059cbb</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="co">// Dispatch table entry for transfer(address,uint256)</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>var1 <span class="op">=</span> <span class="bu">msg</span><span class="op">.</span>value<span class="op">;</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(</span>var1<span class="op">)</span> <span class="op">{</span> <span class="bu">revert</span><span class="op">(</span><span class="kw">memory</span><span class="op">[</span><span class="bn">0x00</span><span class="op">:</span><span class="bn">0x00</span><span class="op">]);</span> <span class="op">}</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>    var1 <span class="op">=</span> <span class="bn">0x033a</span><span class="op">;</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>    var2 <span class="op">=</span> <span class="bn">0x04</span><span class="op">;</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>    var3 <span class="op">=</span> <span class="bu">msg</span><span class="op">.</span>data<span class="op">.</span>length <span class="op">-</span> var2<span class="op">;</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(</span>var3 <span class="op">&lt;</span> <span class="bn">0x40</span><span class="op">)</span> <span class="op">{</span> <span class="bu">revert</span><span class="op">(</span><span class="kw">memory</span><span class="op">[</span><span class="bn">0x00</span><span class="op">:</span><span class="bn">0x00</span><span class="op">]);</span> <span class="op">}</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>    var temp27 <span class="op">=</span> var2<span class="op">;</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>    var2 <span class="op">=</span> <span class="bu">msg</span><span class="op">.</span>data<span class="op">[</span>temp27<span class="op">:</span>temp27 <span class="op">+</span> <span class="bn">0x20</span><span class="op">]</span> <span class="op">&amp;</span> <span class="op">(</span><span class="bn">0x01</span> <span class="op">&lt;&lt;</span> <span class="bn">0xa0</span><span class="op">)</span> <span class="op">-</span> <span class="bn">0x01</span><span class="op">;</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>    var3 <span class="op">=</span> <span class="bu">msg</span><span class="op">.</span>data<span class="op">[</span>temp27 <span class="op">+</span> <span class="bn">0x20</span><span class="op">:</span>temp27 <span class="op">+</span> <span class="bn">0x20</span> <span class="op">+</span> <span class="bn">0x20</span><span class="op">];</span></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a>    var4 <span class="op">=</span> <span class="bn">0x00</span><span class="op">;</span></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a>    var5 <span class="op">=</span> <span class="bn">0x0a46</span><span class="op">;</span></span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a>    var6 <span class="op">=</span> <span class="bn">0x10b2</span><span class="op">;</span></span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a>    var6 <span class="op">=</span> func_17A8<span class="op">();</span></span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a>    func_10B2<span class="op">(</span>var2<span class="op">,</span> var3<span class="op">,</span> var6<span class="op">);</span></span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a>    goto label_0A46<span class="op">;</span></span>
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>This is the entry point for calling <code>transfer</code>, which calls <code>func_10B2</code>, which in turn calls <code>func_1898</code> aka <code>_transfer</code>:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode solidity"><code class="sourceCode solidity"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="cf">function</span> func_10B2<span class="op">(</span>var arg0<span class="op">,</span> var arg1<span class="op">,</span> var arg2<span class="op">)</span> <span class="op">{</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>    var var0 <span class="op">=</span> arg0<span class="op">;</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>    var var1 <span class="op">=</span> arg1<span class="op">;</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>    func_1898<span class="op">(</span>arg2<span class="op">,</span> var0<span class="op">,</span> var1<span class="op">);</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>    <span class="co">// Error: Could not resolve method call return address!</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>This calls through to func_1898. First, it checks some error guards:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode solidity"><code class="sourceCode solidity"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="cf">function</span> func_1898<span class="op">(</span>var arg0<span class="op">,</span> var arg1<span class="op">,</span> var arg2<span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> <span class="op">(!(</span>arg0 <span class="op">&amp;</span> <span class="op">(</span><span class="bn">0x01</span> <span class="op">&lt;&lt;</span> <span class="bn">0xa0</span><span class="op">)</span> <span class="op">-</span> <span class="bn">0x01</span><span class="op">))</span> <span class="op">{</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>    var temp28 <span class="op">=</span> <span class="kw">memory</span><span class="op">[</span><span class="bn">0x40</span><span class="op">:</span><span class="bn">0x60</span><span class="op">];</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">memory</span><span class="op">[</span>temp28<span class="op">:</span>temp28 <span class="op">+</span> <span class="bn">0x20</span><span class="op">]</span> <span class="op">=</span> <span class="bn">0x461bcd</span> <span class="op">&lt;&lt;</span> <span class="bn">0xe5</span><span class="op">;</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>    var temp29 <span class="op">=</span> temp28 <span class="op">+</span> <span class="bn">0x04</span><span class="op">;</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>    var temp30 <span class="op">=</span> temp29 <span class="op">+</span> <span class="bn">0x20</span><span class="op">;</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">memory</span><span class="op">[</span>temp29<span class="op">:</span>temp29 <span class="op">+</span> <span class="bn">0x20</span><span class="op">]</span> <span class="op">=</span> temp30 <span class="op">-</span> temp29<span class="op">;</span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>    <span class="kw">memory</span><span class="op">[</span>temp30<span class="op">:</span>temp30 <span class="op">+</span> <span class="bn">0x20</span><span class="op">]</span> <span class="op">=</span> <span class="bn">0x25</span><span class="op">;</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a>    var temp31 <span class="op">=</span> temp30 <span class="op">+</span> <span class="bn">0x20</span><span class="op">;</span></span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a>    <span class="kw">memory</span><span class="op">[</span>temp31<span class="op">:</span>temp31 <span class="op">+</span> <span class="bn">0x25</span><span class="op">]</span> <span class="op">=</span> code<span class="op">[</span><span class="bn">0x289a</span><span class="op">:</span><span class="bn">0x28bf</span><span class="op">];</span></span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a>    var temp32 <span class="op">=</span> <span class="kw">memory</span><span class="op">[</span><span class="bn">0x40</span><span class="op">:</span><span class="bn">0x60</span><span class="op">];</span></span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a>    <span class="bu">revert</span><span class="op">(</span><span class="kw">memory</span><span class="op">[</span>temp32<span class="op">:</span>temp32 <span class="op">+</span> <span class="op">(</span>temp31 <span class="op">+</span> <span class="bn">0x40</span><span class="op">)</span> <span class="op">-</span> temp32<span class="op">]);</span></span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a><span class="op">}</span> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(!(</span>arg1 <span class="op">&amp;</span> <span class="op">(</span><span class="bn">0x01</span> <span class="op">&lt;&lt;</span> <span class="bn">0xa0</span><span class="op">)</span> <span class="op">-</span> <span class="bn">0x01</span><span class="op">))</span> <span class="op">{</span></span>
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true" tabindex="-1"></a>    var temp23 <span class="op">=</span> <span class="kw">memory</span><span class="op">[</span><span class="bn">0x40</span><span class="op">:</span><span class="bn">0x60</span><span class="op">];</span></span>
<span id="cb3-15"><a href="#cb3-15" aria-hidden="true" tabindex="-1"></a>    <span class="kw">memory</span><span class="op">[</span>temp23<span class="op">:</span>temp23 <span class="op">+</span> <span class="bn">0x20</span><span class="op">]</span> <span class="op">=</span> <span class="bn">0x461bcd</span> <span class="op">&lt;&lt;</span> <span class="bn">0xe5</span><span class="op">;</span></span>
<span id="cb3-16"><a href="#cb3-16" aria-hidden="true" tabindex="-1"></a>    var temp24 <span class="op">=</span> temp23 <span class="op">+</span> <span class="bn">0x04</span><span class="op">;</span></span>
<span id="cb3-17"><a href="#cb3-17" aria-hidden="true" tabindex="-1"></a>    var temp25 <span class="op">=</span> temp24 <span class="op">+</span> <span class="bn">0x20</span><span class="op">;</span></span>
<span id="cb3-18"><a href="#cb3-18" aria-hidden="true" tabindex="-1"></a>    <span class="kw">memory</span><span class="op">[</span>temp24<span class="op">:</span>temp24 <span class="op">+</span> <span class="bn">0x20</span><span class="op">]</span> <span class="op">=</span> temp25 <span class="op">-</span> temp24<span class="op">;</span></span>
<span id="cb3-19"><a href="#cb3-19" aria-hidden="true" tabindex="-1"></a>    <span class="kw">memory</span><span class="op">[</span>temp25<span class="op">:</span>temp25 <span class="op">+</span> <span class="bn">0x20</span><span class="op">]</span> <span class="op">=</span> <span class="bn">0x23</span><span class="op">;</span></span>
<span id="cb3-20"><a href="#cb3-20" aria-hidden="true" tabindex="-1"></a>    var temp26 <span class="op">=</span> temp25 <span class="op">+</span> <span class="bn">0x20</span><span class="op">;</span></span>
<span id="cb3-21"><a href="#cb3-21" aria-hidden="true" tabindex="-1"></a>    <span class="kw">memory</span><span class="op">[</span>temp26<span class="op">:</span>temp26 <span class="op">+</span> <span class="bn">0x23</span><span class="op">]</span> <span class="op">=</span> code<span class="op">[</span><span class="bn">0x2708</span><span class="op">:</span><span class="bn">0x272b</span><span class="op">];</span></span>
<span id="cb3-22"><a href="#cb3-22" aria-hidden="true" tabindex="-1"></a>    var temp27 <span class="op">=</span> <span class="kw">memory</span><span class="op">[</span><span class="bn">0x40</span><span class="op">:</span><span class="bn">0x60</span><span class="op">];</span></span>
<span id="cb3-23"><a href="#cb3-23" aria-hidden="true" tabindex="-1"></a>    <span class="bu">revert</span><span class="op">(</span><span class="kw">memory</span><span class="op">[</span>temp27<span class="op">:</span>temp27 <span class="op">+</span> <span class="op">(</span>temp26 <span class="op">+</span> <span class="bn">0x40</span><span class="op">)</span> <span class="op">-</span> temp27<span class="op">]);</span></span>
<span id="cb3-24"><a href="#cb3-24" aria-hidden="true" tabindex="-1"></a><span class="op">}</span> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>arg2 <span class="op">&lt;=</span> <span class="bn">0x00</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-25"><a href="#cb3-25" aria-hidden="true" tabindex="-1"></a>    var temp18 <span class="op">=</span> <span class="kw">memory</span><span class="op">[</span><span class="bn">0x40</span><span class="op">:</span><span class="bn">0x60</span><span class="op">];</span></span>
<span id="cb3-26"><a href="#cb3-26" aria-hidden="true" tabindex="-1"></a>    <span class="kw">memory</span><span class="op">[</span>temp18<span class="op">:</span>temp18 <span class="op">+</span> <span class="bn">0x20</span><span class="op">]</span> <span class="op">=</span> <span class="bn">0x461bcd</span> <span class="op">&lt;&lt;</span> <span class="bn">0xe5</span><span class="op">;</span></span>
<span id="cb3-27"><a href="#cb3-27" aria-hidden="true" tabindex="-1"></a>    var temp19 <span class="op">=</span> temp18 <span class="op">+</span> <span class="bn">0x04</span><span class="op">;</span></span>
<span id="cb3-28"><a href="#cb3-28" aria-hidden="true" tabindex="-1"></a>    var temp20 <span class="op">=</span> temp19 <span class="op">+</span> <span class="bn">0x20</span><span class="op">;</span></span>
<span id="cb3-29"><a href="#cb3-29" aria-hidden="true" tabindex="-1"></a>    <span class="kw">memory</span><span class="op">[</span>temp19<span class="op">:</span>temp19 <span class="op">+</span> <span class="bn">0x20</span><span class="op">]</span> <span class="op">=</span> temp20 <span class="op">-</span> temp19<span class="op">;</span></span>
<span id="cb3-30"><a href="#cb3-30" aria-hidden="true" tabindex="-1"></a>    <span class="kw">memory</span><span class="op">[</span>temp20<span class="op">:</span>temp20 <span class="op">+</span> <span class="bn">0x20</span><span class="op">]</span> <span class="op">=</span> <span class="bn">0x29</span><span class="op">;</span></span>
<span id="cb3-31"><a href="#cb3-31" aria-hidden="true" tabindex="-1"></a>    var temp21 <span class="op">=</span> temp20 <span class="op">+</span> <span class="bn">0x20</span><span class="op">;</span></span>
<span id="cb3-32"><a href="#cb3-32" aria-hidden="true" tabindex="-1"></a>    <span class="kw">memory</span><span class="op">[</span>temp21<span class="op">:</span>temp21 <span class="op">+</span> <span class="bn">0x29</span><span class="op">]</span> <span class="op">=</span> code<span class="op">[</span><span class="bn">0x2828</span><span class="op">:</span><span class="bn">0x2851</span><span class="op">];</span></span>
<span id="cb3-33"><a href="#cb3-33" aria-hidden="true" tabindex="-1"></a>    var temp22 <span class="op">=</span> <span class="kw">memory</span><span class="op">[</span><span class="bn">0x40</span><span class="op">:</span><span class="bn">0x60</span><span class="op">];</span></span>
<span id="cb3-34"><a href="#cb3-34" aria-hidden="true" tabindex="-1"></a>    <span class="bu">revert</span><span class="op">(</span><span class="kw">memory</span><span class="op">[</span>temp22<span class="op">:</span>temp22 <span class="op">+</span> <span class="op">(</span>temp21 <span class="op">+</span> <span class="bn">0x40</span><span class="op">)</span> <span class="op">-</span> temp22<span class="op">]);</span></span>
<span id="cb3-35"><a href="#cb3-35" aria-hidden="true" tabindex="-1"></a><span class="op">}</span> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>arg2 <span class="op">&lt;=</span> <span class="kw">storage</span><span class="op">[</span><span class="bn">0x16</span><span class="op">])</span> <span class="op">{</span></span>
<span id="cb3-36"><a href="#cb3-36" aria-hidden="true" tabindex="-1"></a><span class="co">// extremely long rest of function is past this point</span></span></code></pre></div>
<p>This if else block is checking</p>
<ul>
<li><p>to addr must not be 0</p></li>
<li><p>from addr must not be 0</p></li>
<li><p>amount must be above 0</p></li>
<li><p>amount must be smaller than value in slot 0x16</p></li>
</ul>
<p>0x16 is set by <code>setMaxTxAmount</code>:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode solidity"><code class="sourceCode solidity"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="cf">function</span> setMaxTxAmount<span class="op">(</span>var arg0<span class="op">,</span> var arg1<span class="op">)</span> <span class="op">{</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>    arg0 <span class="op">=</span> <span class="bu">msg</span><span class="op">.</span>data<span class="op">[</span>arg0<span class="op">:</span>arg0 <span class="op">+</span> <span class="bn">0x20</span><span class="op">];</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>    arg1 <span class="op">=</span> <span class="bn">0x1296</span><span class="op">;</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>    arg1 <span class="op">=</span> func_17A8<span class="op">();</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>    var temp0 <span class="op">=</span> <span class="op">(</span><span class="bn">0x01</span> <span class="op">&lt;&lt;</span> <span class="bn">0xa0</span><span class="op">)</span> <span class="op">-</span> <span class="bn">0x01</span><span class="op">;</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(</span>arg1 <span class="op">&amp;</span> temp0 <span class="op">==</span> temp0 <span class="op">&amp;</span> <span class="kw">storage</span><span class="op">[</span><span class="bn">0x00</span><span class="op">])</span> <span class="op">{</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>        <span class="kw">storage</span><span class="op">[</span><span class="bn">0x16</span><span class="op">]</span> <span class="op">=</span> arg0<span class="op">;</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span><span class="op">;</span></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a>        var temp1 <span class="op">=</span> <span class="kw">memory</span><span class="op">[</span><span class="bn">0x40</span><span class="op">:</span><span class="bn">0x60</span><span class="op">];</span></span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a>        <span class="kw">memory</span><span class="op">[</span>temp1<span class="op">:</span>temp1 <span class="op">+</span> <span class="bn">0x20</span><span class="op">]</span> <span class="op">=</span> <span class="bn">0x461bcd</span> <span class="op">&lt;&lt;</span> <span class="bn">0xe5</span><span class="op">;</span></span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a>        <span class="kw">memory</span><span class="op">[</span>temp1 <span class="op">+</span> <span class="bn">0x04</span><span class="op">:</span>temp1 <span class="op">+</span> <span class="bn">0x04</span> <span class="op">+</span> <span class="bn">0x20</span><span class="op">]</span> <span class="op">=</span> <span class="bn">0x20</span><span class="op">;</span></span>
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a>        <span class="kw">memory</span><span class="op">[</span>temp1 <span class="op">+</span> <span class="bn">0x24</span><span class="op">:</span>temp1 <span class="op">+</span> <span class="bn">0x24</span> <span class="op">+</span> <span class="bn">0x20</span><span class="op">]</span> <span class="op">=</span> <span class="bn">0x20</span><span class="op">;</span></span>
<span id="cb4-15"><a href="#cb4-15" aria-hidden="true" tabindex="-1"></a>        var temp2 <span class="op">=</span> <span class="kw">memory</span><span class="op">[</span><span class="bn">0x00</span><span class="op">:</span><span class="bn">0x20</span><span class="op">];</span></span>
<span id="cb4-16"><a href="#cb4-16" aria-hidden="true" tabindex="-1"></a>        <span class="kw">memory</span><span class="op">[</span><span class="bn">0x00</span><span class="op">:</span><span class="bn">0x20</span><span class="op">]</span> <span class="op">=</span> code<span class="op">[</span><span class="bn">0x2808</span><span class="op">:</span><span class="bn">0x2828</span><span class="op">];</span></span>
<span id="cb4-17"><a href="#cb4-17" aria-hidden="true" tabindex="-1"></a>        var temp3 <span class="op">=</span> <span class="kw">memory</span><span class="op">[</span><span class="bn">0x00</span><span class="op">:</span><span class="bn">0x20</span><span class="op">];</span></span>
<span id="cb4-18"><a href="#cb4-18" aria-hidden="true" tabindex="-1"></a>        <span class="kw">memory</span><span class="op">[</span><span class="bn">0x00</span><span class="op">:</span><span class="bn">0x20</span><span class="op">]</span> <span class="op">=</span> temp2<span class="op">;</span></span>
<span id="cb4-19"><a href="#cb4-19" aria-hidden="true" tabindex="-1"></a>        <span class="kw">memory</span><span class="op">[</span>temp1 <span class="op">+</span> <span class="bn">0x44</span><span class="op">:</span>temp1 <span class="op">+</span> <span class="bn">0x44</span> <span class="op">+</span> <span class="bn">0x20</span><span class="op">]</span> <span class="op">=</span> temp3<span class="op">;</span></span>
<span id="cb4-20"><a href="#cb4-20" aria-hidden="true" tabindex="-1"></a>        var temp4 <span class="op">=</span> <span class="kw">memory</span><span class="op">[</span><span class="bn">0x40</span><span class="op">:</span><span class="bn">0x60</span><span class="op">];</span></span>
<span id="cb4-21"><a href="#cb4-21" aria-hidden="true" tabindex="-1"></a>        <span class="bu">revert</span><span class="op">(</span><span class="kw">memory</span><span class="op">[</span>temp4<span class="op">:</span>temp4 <span class="op">+</span> temp1 <span class="op">-</span> temp4 <span class="op">+</span> <span class="bn">0x64</span><span class="op">]);</span></span>
<span id="cb4-22"><a href="#cb4-22" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb4-23"><a href="#cb4-23" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>So it’s an owner-settable transaction size limit. Which is suspicious since the owner <em>could</em> set it to 0 or some extremely low value. It’d be weird for the contract’s owner to have set it to anything <em>other</em> than “the maximum sell size is zero” since their goal is to prevent selling.</p>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/blobwizard.webp" class="admonition-icon" alt="" width="128" height="128" />Info</span>
<div class="admonition-content">
<p>The owner profits by inflating the proportion of the LP pair that <em>isn’t</em> $SQUIRT, and then withdrawing the LP tokens and converting them back into, in this case, a bunch of $BNB and a tiny amount of $SQUIRT</p>
</div>
</div>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/note.webp" class="admonition-icon" alt="" width="128" height="128" />Note</span>
<div class="admonition-content">
<p>Alyssa, my fiancé and proofreader, suggests I clarify that the owner is the person / address that created and controls the contract. More detail: contracts tend to have a function that transfers ownership. and one common pattern is to transfer ownership to the zero address. This is done to publicly and provably abandon ownership (so people know, or think they know, you can’t cheat them)</p>
</div>
</div>
<p>However, reading storage slot 0x16 reveals this is actually a red herring:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> { Web3 } <span class="op">=</span> <span class="pp">require</span>(<span class="st">&quot;web3&quot;</span>)<span class="op">;</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> web3 <span class="op">=</span> <span class="kw">new</span> <span class="fu">Web3</span>(<span class="st">&quot;https://bsc-dataseed1.binance.org&quot;</span>)<span class="op">;</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> address <span class="op">=</span> <span class="st">&quot;0x8eb2877ef365bb520eceb3b34c0c18afd2058c57&quot;</span><span class="op">;</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a><span class="kw">async</span> <span class="kw">function</span> <span class="fu">getMaxTx</span>() {</span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> value <span class="op">=</span> <span class="cf">await</span> web3<span class="op">.</span><span class="at">eth</span><span class="op">.</span><span class="fu">getStorageAt</span>(address<span class="op">,</span> <span class="st">&quot;0x16&quot;</span>)<span class="op">;</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> maxTx <span class="op">=</span> <span class="bu">BigInt</span>(value)<span class="op">;</span></span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a>  <span class="bu">console</span><span class="op">.</span><span class="fu">log</span>(<span class="vs">`Maximum transaction size: </span><span class="sc">${</span>maxTx<span class="sc">}</span><span class="vs">`</span>)<span class="op">;</span></span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a>}</span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a><span class="fu">getMaxTx</span>()<span class="op">.</span><span class="fu">catch</span>(<span class="bu">console</span><span class="op">.</span><span class="fu">error</span>)<span class="op">;</span></span></code></pre></div>
<div class="sourceCode" id="cb6"><pre class="sourceCode sh"><code class="sourceCode bash"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="ex">❯</span> node getMaxTx.js</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="ex">Maximum</span> transaction size: 90000000000000000000000000000000</span></code></pre></div>
<p>Compare this value to the total supply, which is <a href="https://bscscan.com/token/0x8eb2877ef365bb520eceb3b34c0c18afd2058c57">683,737,126,103.036588
SQUIRT</a></p>
<p>90,000,000,000,000,000,000,000,000,000,000 is larger than 683,737,126,103, so this maximum transaction size check doesn’t actually do anything.</p>
<p>We’ll continue tracing the chain of calls involved in a transfer.</p>
<p>There’s a check to determine whether the transfer is a typical wallet to wallet transfer, or is a dex transaction. If it is a dex transaction, then we check a <em>time gate</em>.</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode solidity"><code class="sourceCode solidity"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> <span class="op">(</span><span class="co">/* this is a wallet to wallet transfer */</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="co">/* basic but longwinded wallet transfer logic goes here */</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a><span class="kw">memory</span><span class="op">[</span><span class="bn">0x00</span><span class="op">:</span><span class="bn">0x20</span><span class="op">]</span> <span class="op">=</span> arg0 <span class="op">&amp;</span> <span class="op">(</span><span class="bn">0x01</span> <span class="op">&lt;&lt;</span> <span class="bn">0xa0</span><span class="op">)</span> <span class="op">-</span> <span class="bn">0x01</span><span class="op">;</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a><span class="kw">memory</span><span class="op">[</span><span class="bn">0x20</span><span class="op">:</span><span class="bn">0x40</span><span class="op">]</span> <span class="op">=</span> <span class="bn">0x07</span><span class="op">;</span></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>var4 <span class="op">=</span> <span class="kw">storage</span><span class="op">[</span><span class="bn">0x08</span><span class="op">]</span> <span class="op">+</span> <span class="kw">storage</span><span class="op">[</span><span class="bu">keccak256</span><span class="op">(</span><span class="kw">memory</span><span class="op">[</span><span class="bn">0x00</span><span class="op">:</span><span class="bn">0x40</span><span class="op">])]</span> <span class="op">&lt;</span> <span class="bu">block</span><span class="op">.</span>timestamp<span class="op">;</span></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> <span class="op">(!</span>var4<span class="op">)</span> <span class="op">{</span></span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a><span class="kw">memory</span><span class="op">[</span><span class="bn">0x00</span><span class="op">:</span><span class="bn">0x20</span><span class="op">]</span> <span class="op">=</span> arg0 <span class="op">&amp;</span> <span class="op">(</span><span class="bn">0x01</span> <span class="op">&lt;&lt;</span> <span class="bn">0xa0</span><span class="op">)</span> <span class="op">-</span> <span class="bn">0x01</span><span class="op">;</span></span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a><span class="kw">memory</span><span class="op">[</span><span class="bn">0x20</span><span class="op">:</span><span class="bn">0x40</span><span class="op">]</span> <span class="op">=</span> <span class="bn">0x07</span><span class="op">;</span></span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> <span class="op">(!</span><span class="kw">storage</span><span class="op">[</span><span class="bu">keccak256</span><span class="op">(</span><span class="kw">memory</span><span class="op">[</span><span class="bn">0x00</span><span class="op">:</span><span class="bn">0x40</span><span class="op">])])</span> <span class="op">{</span></span>
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true" tabindex="-1"></a>goto label_1CF8<span class="op">;</span></span>
<span id="cb7-12"><a href="#cb7-12" aria-hidden="true" tabindex="-1"></a><span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb7-13"><a href="#cb7-13" aria-hidden="true" tabindex="-1"></a>goto label_1CB8<span class="op">;</span></span>
<span id="cb7-14"><a href="#cb7-14" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb7-15"><a href="#cb7-15" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>This</p>
<ul>
<li><p>Uses storage slot 0x07 + address to store timestamps</p></li>
<li><p>Checks current time against stored timestamp + delay (storage[0x08])</p></li>
<li><p>Probably determines that it is too soon for us to be allowed to sell and directs us to <code>label_1CB8</code>, which probably describes the failed-to-sell behavior</p></li>
</ul>
<p>We’ll now check what is in 0x08.</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> { Web3 } <span class="op">=</span> <span class="pp">require</span>(<span class="st">&quot;web3&quot;</span>)<span class="op">;</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> web3 <span class="op">=</span> <span class="kw">new</span> <span class="fu">Web3</span>(<span class="st">&quot;https://bsc-dataseed1.binance.org&quot;</span>)<span class="op">;</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> address <span class="op">=</span> <span class="st">&quot;0x8eb2877ef365bb520eceb3b34c0c18afd2058c57&quot;</span><span class="op">;</span></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> slot <span class="op">=</span> <span class="st">&quot;0x08&quot;</span><span class="op">;</span></span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a>web3<span class="op">.</span><span class="at">eth</span></span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a>  <span class="op">.</span><span class="fu">getStorageAt</span>(address<span class="op">,</span> slot)</span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a>  <span class="op">.</span><span class="fu">then</span>((value) <span class="kw">=&gt;</span> {</span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a>    <span class="bu">console</span><span class="op">.</span><span class="fu">log</span>(<span class="st">&quot;Raw value:&quot;</span><span class="op">,</span> value)<span class="op">;</span></span>
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a>    <span class="bu">console</span><span class="op">.</span><span class="fu">log</span>(<span class="st">&quot;Decimal:&quot;</span><span class="op">,</span> <span class="pp">parseInt</span>(value))<span class="op">;</span></span>
<span id="cb8-12"><a href="#cb8-12" aria-hidden="true" tabindex="-1"></a>    <span class="bu">console</span><span class="op">.</span><span class="fu">log</span>(<span class="st">&quot;Days:&quot;</span><span class="op">,</span> <span class="pp">parseInt</span>(value) <span class="op">/</span> <span class="dv">86400</span>)<span class="op">;</span></span>
<span id="cb8-13"><a href="#cb8-13" aria-hidden="true" tabindex="-1"></a>  })</span>
<span id="cb8-14"><a href="#cb8-14" aria-hidden="true" tabindex="-1"></a>  <span class="op">.</span><span class="fu">catch</span>((err) <span class="kw">=&gt;</span> {</span>
<span id="cb8-15"><a href="#cb8-15" aria-hidden="true" tabindex="-1"></a>    <span class="bu">console</span><span class="op">.</span><span class="fu">error</span>(<span class="st">&quot;Error:&quot;</span><span class="op">,</span> err)<span class="op">;</span></span>
<span id="cb8-16"><a href="#cb8-16" aria-hidden="true" tabindex="-1"></a>  })<span class="op">;</span></span></code></pre></div>
<div class="sourceCode" id="cb9"><pre class="sourceCode sh"><code class="sourceCode bash"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="ex">❯</span> node get0x08.js</span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a><span class="ex">Raw</span> value: 0x00000000000000000000000000000000000000000000000000000000001baf80</span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a><span class="ex">Decimal:</span> 1814400</span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a><span class="ex">Days:</span> 21</span></code></pre></div>
<p>21 days! It checks when you bought and if you’re trying to sell within 21 days, you get sent to <code>label_1CB8</code>. Let’s go there now.</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode solidity"><code class="sourceCode solidity"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a>label_1CB8<span class="op">:</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>var temp12 <span class="op">=</span> <span class="kw">memory</span><span class="op">[</span><span class="bn">0x40</span><span class="op">:</span><span class="bn">0x60</span><span class="op">];</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a><span class="kw">memory</span><span class="op">[</span>temp12<span class="op">:</span>temp12 <span class="op">+</span> <span class="bn">0x20</span><span class="op">]</span> <span class="op">=</span> <span class="bn">0x461bcd</span> <span class="op">&lt;&lt;</span> <span class="bn">0xe5</span><span class="op">;</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a><span class="kw">memory</span><span class="op">[</span>temp12 <span class="op">+</span> <span class="bn">0x04</span><span class="op">:</span>temp12 <span class="op">+</span> <span class="bn">0x04</span> <span class="op">+</span> <span class="bn">0x20</span><span class="op">]</span> <span class="op">=</span> <span class="bn">0x20</span><span class="op">;</span></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a><span class="kw">memory</span><span class="op">[</span>temp12 <span class="op">+</span> <span class="bn">0x24</span><span class="op">:</span>temp12 <span class="op">+</span> <span class="bn">0x24</span> <span class="op">+</span> <span class="bn">0x20</span><span class="op">]</span> <span class="op">=</span> <span class="bn">0x11</span><span class="op">;</span></span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a><span class="kw">memory</span><span class="op">[</span>temp12 <span class="op">+</span> <span class="bn">0x44</span><span class="op">:</span>temp12 <span class="op">+</span> <span class="bn">0x44</span> <span class="op">+</span> <span class="bn">0x20</span><span class="op">]</span> <span class="op">=</span> <span class="bn">0x546f6f20736f6f6e20746f2073656c6c21</span> <span class="op">&lt;&lt;</span> <span class="bn">0x78</span><span class="op">;</span></span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a>var temp13 <span class="op">=</span> <span class="kw">memory</span><span class="op">[</span><span class="bn">0x40</span><span class="op">:</span><span class="bn">0x60</span><span class="op">];</span></span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a><span class="bu">revert</span><span class="op">(</span><span class="kw">memory</span><span class="op">[</span>temp13<span class="op">:</span>temp13 <span class="op">+</span> temp12 <span class="op">-</span> temp13 <span class="op">+</span> <span class="bn">0x64</span><span class="op">]);</span></span></code></pre></div>
<p><code>0x546f6f20736f6f6e20746f2073656c6c21</code> is actually an ascii string. <a href="https://www.freecodecamp.org/news/ascii-table-hex-to-ascii-value-character-code-chart-2/">54=T, 6F=o</a>, etc. It decodes as follows:</p>
<blockquote>
<p>Too soon to sell!</p>
</blockquote>
<p>A would-be seller gets sent here and is shown this message as their transaction is reverted. Mystery solved!</p>
<p>From this point onwards we’ll only be looking at solidity written by and for humans, rather than at decompilations of solidity bytecode (thank god).</p>
<h4 id="variation-automated-at-scale"><a href="#variation-automated-at-scale">Variation: Automated &amp; At Scale</a></h4>
<p>There are trading bots that monitor the newly created tokens on a given chain and then either buy a little of <em>all</em> of them, or have some strategy to choose which subset to buy into. Either way, this is an imperfect process and sufficiently dumb trading bots can be gamed into buying unsellable junk.</p>
<p>Long ago, there was some guy or outfit making [EMOJI]SWAP tokens. Stuff like LEMONSWAP, SEEDLINGSWAP, etc. The contract was always unverified and untradable, and the liquidity was always <em>rather high</em>, roughly $100,000 per token. I can only assume this was quite profitable since they kept this up for months on end.</p>
<h3 id="bad-approve-function"><a href="#bad-approve-function">Bad <code>approve</code> Function</a></h3>
<p>Example: <a href="https://www.reddit.com/r/CryptoMoonShots/comments/nmmytk/fairmoon_cash_fairc_healing_the_wounds_of/gzpphjd/">1</a>.</p>
<p>This post’s title isn’t as fun:</p>
<blockquote>
<p>Fairmoon Cash ($FAIRC) – Healing the Wounds of Fairmoon Victims (Just launched)</p>
</blockquote>
<p>The OP deleted their post (and thus easy access to the contract and its address). My comment remains:</p>
<blockquote>
<p>the approval function is jank check this out:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode solidity"><code class="sourceCode solidity"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="op">[...]{</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(</span>_excluded<span class="op">[</span>owner<span class="op">])</span> <span class="op">{</span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>        _allowances<span class="op">[</span>owner<span class="op">][</span>spender<span class="op">]</span> <span class="op">=</span> amount<span class="op">;</span></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a>        _allowances<span class="op">[</span>owner<span class="op">][</span>spender<span class="op">]</span> <span class="op">=</span> <span class="dv">0</span><span class="op">;</span></span>
<span id="cb11-10"><a href="#cb11-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-11"><a href="#cb11-11" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb11-12"><a href="#cb11-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-13"><a href="#cb11-13" aria-hidden="true" tabindex="-1"></a>    <span class="cf">emit</span> Approval<span class="op">(</span>owner<span class="op">,</span> spender<span class="op">,</span> amount<span class="op">);</span></span>
<span id="cb11-14"><a href="#cb11-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-15"><a href="#cb11-15" aria-hidden="true" tabindex="-1"></a><span class="op">}[...]</span></span></code></pre></div>
</blockquote>
<p>I was able to <em>track down</em> the contract thanks to bscscan. Here it is: <a href="https://bscscan.com/token/0x55a544b41e4dcbf6b39646e92ca3c0a8c4e01e58?a=0x94af4b4bfe447fa36d1254d02011046c16b1c0a1#code"><code>0x55A544B41E4DCbF6b39646e92ca3c0a8c4E01E58</code></a></p>
<p>Here is the unabridged function:</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode solidity"><code class="sourceCode solidity"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="cf">function</span> _approve<span class="op">(</span><span class="dt">address</span> owner<span class="op">,</span> <span class="dt">address</span> spender<span class="op">,</span> <span class="dt">uint256</span> amount<span class="op">)</span> <span class="kw">private</span> <span class="op">{</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>    <span class="bu">require</span><span class="op">(</span>owner <span class="op">!=</span> <span class="dt">address</span><span class="op">(</span><span class="dv">0</span><span class="op">),</span> <span class="st">&quot;BEP20: approve from the zero address&quot;</span><span class="op">);</span></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>    <span class="bu">require</span><span class="op">(</span>spender <span class="op">!=</span> <span class="dt">address</span><span class="op">(</span><span class="dv">0</span><span class="op">),</span> <span class="st">&quot;BEP20: approve to the zero address&quot;</span><span class="op">);</span></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(</span>_excluded<span class="op">[</span>owner<span class="op">])</span> <span class="op">{</span></span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a>        _allowances<span class="op">[</span>owner<span class="op">][</span>spender<span class="op">]</span> <span class="op">=</span> amount<span class="op">;</span></span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a>        _allowances<span class="op">[</span>owner<span class="op">][</span>spender<span class="op">]</span> <span class="op">=</span> <span class="dv">0</span><span class="op">;</span></span>
<span id="cb12-9"><a href="#cb12-9" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb12-10"><a href="#cb12-10" aria-hidden="true" tabindex="-1"></a>    <span class="cf">emit</span> Approval<span class="op">(</span>owner<span class="op">,</span> spender<span class="op">,</span> amount<span class="op">);</span></span>
<span id="cb12-11"><a href="#cb12-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/blobwizard.webp" class="admonition-icon" alt="" width="128" height="128" />Info</span>
<div class="admonition-content">
<p>One common pattern in ERC-20 implementations is to have public interface functions (e.g. approve) that call internal helper functions (e.g. _approve) to handle the core logic. The public functions often add access controls or validation, while the internal functions contain the actual implementation. However, if the internal functions aren’t properly protected, malicious contracts that inherit from the token contract might be able to bypass the intended restrictions by calling these internal functions directly.</p>
<p>Many exploits involve directly constructing transactions to call “internal” functions that weren’t meant to be called directly. If I ever write about more <em>conventional</em> security concerns (i.e. “help: I am writing a contract for my DAO; how do I avoid it getting robbed?”) I’ll have cause to write about this and there is <em>much</em> to say about it.</p>
</div>
</div>
<p>The ERC-20 approval function lets a token holder (the owner) authorize another address (the spender) to</p>
<ol type="1">
<li><p>spend tokens on its behalf</p></li>
<li><p>up to a specified amount</p></li>
</ol>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/note.webp" class="admonition-icon" alt="" width="128" height="128" />Note</span>
<div class="admonition-content">
<p>Though in practice that amount is often “unlimited”</p>
</div>
</div>
<p>This is used for, among other things, interacting with DEXes, since internally what is happening when you swap a thing for another thing, is the DEX is “spending” your token.</p>
<p>The way a typical user is interfacing with a DEX approval function is something like:</p>
<ol type="1">
<li><p>They click the “approve” button in their dex app, which is linked to their wallet</p></li>
<li><p>Their wallet extension opens a window asking them if they want to approve</p></li>
<li><p>If they agree, their wallet, taking direction from the dex, constructs and attempts to execute an approve transaction</p></li>
<li><p>A few seconds later the wallet issues a notification reporting a result</p></li>
</ol>
<p>That UI notification from the last step, can lie. Under the hood, the “notification reporting a result” comes from your wallet listening for an event. ERC-20 standard says you have to emit events when doing certain things, such as approving or transferring. Info:</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode solidity"><code class="sourceCode solidity"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a>interface IERC20 <span class="op">{</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>    <span class="co">// Required events</span></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">event</span> Transfer<span class="op">(</span><span class="dt">address</span> <span class="kw">indexed</span> <span class="kw">from</span><span class="op">,</span> <span class="dt">address</span> <span class="kw">indexed</span> to<span class="op">,</span> <span class="dt">uint256</span> value<span class="op">);</span></span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">event</span> Approval<span class="op">(</span><span class="dt">address</span> <span class="kw">indexed</span> owner<span class="op">,</span> <span class="dt">address</span> <span class="kw">indexed</span> spender<span class="op">,</span> <span class="dt">uint256</span> value<span class="op">);</span></span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a>    <span class="co">// Required functions that emit these events</span></span>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a>    <span class="cf">function</span> transfer<span class="op">(</span><span class="dt">address</span> to<span class="op">,</span> <span class="dt">uint256</span> value<span class="op">)</span> <span class="kw">external</span> <span class="kw">returns</span> <span class="op">(</span><span class="dt">bool</span><span class="op">);</span></span>
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a>    <span class="cf">function</span> approve<span class="op">(</span><span class="dt">address</span> spender<span class="op">,</span> <span class="dt">uint256</span> value<span class="op">)</span> <span class="kw">external</span> <span class="kw">returns</span> <span class="op">(</span><span class="dt">bool</span><span class="op">);</span></span>
<span id="cb13-9"><a href="#cb13-9" aria-hidden="true" tabindex="-1"></a>    <span class="cf">function</span> transferFrom<span class="op">(</span><span class="dt">address</span> <span class="kw">from</span><span class="op">,</span> <span class="dt">address</span> to<span class="op">,</span> <span class="dt">uint256</span> value<span class="op">)</span> <span class="kw">external</span> <span class="kw">returns</span> <span class="op">(</span><span class="dt">bool</span><span class="op">);</span></span>
<span id="cb13-10"><a href="#cb13-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>It’s possible to break from the spec by not emitting stuff. Doing so would confuse everyone, including tools like bscscan. Doing this is uncommon since it is unnecessary. If a competent malicious author wants to trick people, they’re either going to just make fake emit messages or they’re going to do something vastly more complicated than anything described in this post.</p>
<p>Emitted events are supposed to report what actually happened but this is not enforced. They are arbitrary text and can be made to lie. Look again at our function:</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode solidity"><code class="sourceCode solidity"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="cf">function</span> _approve<span class="op">(</span><span class="dt">address</span> owner<span class="op">,</span> <span class="dt">address</span> spender<span class="op">,</span> <span class="dt">uint256</span> amount<span class="op">)</span> <span class="kw">private</span> <span class="op">{</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a>    <span class="bu">require</span><span class="op">(</span>owner <span class="op">!=</span> <span class="dt">address</span><span class="op">(</span><span class="dv">0</span><span class="op">),</span> <span class="st">&quot;BEP20: approve from the zero address&quot;</span><span class="op">);</span></span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a>    <span class="bu">require</span><span class="op">(</span>spender <span class="op">!=</span> <span class="dt">address</span><span class="op">(</span><span class="dv">0</span><span class="op">),</span> <span class="st">&quot;BEP20: approve to the zero address&quot;</span><span class="op">);</span></span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a>    <span class="co">// If owner is &quot;excluded&quot;</span></span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(</span>_excluded<span class="op">[</span>owner<span class="op">])</span> <span class="op">{</span></span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a>        <span class="co">// Set the requested amount</span></span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a>        _allowances<span class="op">[</span>owner<span class="op">][</span>spender<span class="op">]</span> <span class="op">=</span> amount<span class="op">;</span></span>
<span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a>    <span class="co">// If owner is not &quot;excluded&quot;</span></span>
<span id="cb14-9"><a href="#cb14-9" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb14-10"><a href="#cb14-10" aria-hidden="true" tabindex="-1"></a>        <span class="co">// Set it to zero</span></span>
<span id="cb14-11"><a href="#cb14-11" aria-hidden="true" tabindex="-1"></a>        _allowances<span class="op">[</span>owner<span class="op">][</span>spender<span class="op">]</span> <span class="op">=</span> <span class="dv">0</span><span class="op">;</span></span>
<span id="cb14-12"><a href="#cb14-12" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb14-13"><a href="#cb14-13" aria-hidden="true" tabindex="-1"></a>    <span class="co">// Either way, emit the requested amount</span></span>
<span id="cb14-14"><a href="#cb14-14" aria-hidden="true" tabindex="-1"></a>    <span class="cf">emit</span> Approval<span class="op">(</span>owner<span class="op">,</span> spender<span class="op">,</span> amount<span class="op">);</span></span>
<span id="cb14-15"><a href="#cb14-15" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Regardless, the “exploit” here is to making it so that for most or all sellers, their approval transactions either fail or come out approved for incorrectly low or zero amounts.</p>
<p>One crude way to do this, which was done in this example, is to have a list of “excluded” (i.e. allowed to transact normally) addresses, and add the contract owner to that list.</p>
<p>This is easy to grasp, easy to implement, and could still get some people to buy in, but it’s <em>trivial</em> to detect. If the would-be buyer is checking <em>anything</em>, they will check the approve and _approve functions, and will bail if they do not look something like this:</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode solidity"><code class="sourceCode solidity"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="cf">function</span> approve<span class="op">(</span><span class="dt">address</span> spender<span class="op">,</span> <span class="dt">uint256</span> amount<span class="op">)</span> <span class="kw">public</span> <span class="kw">returns</span> <span class="op">(</span><span class="dt">bool</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>_approve<span class="op">(</span><span class="bu">msg</span><span class="op">.</span>sender<span class="op">,</span> spender<span class="op">,</span> amount<span class="op">);</span></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a><span class="cf">return</span> <span class="kw">true</span><span class="op">;</span></span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a><span class="cf">function</span> _approve<span class="op">(</span><span class="dt">address</span> owner<span class="op">,</span> <span class="dt">address</span> spender<span class="op">,</span> <span class="dt">uint256</span> amount<span class="op">)</span> <span class="kw">internal</span> <span class="op">{</span></span>
<span id="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a><span class="bu">require</span><span class="op">(</span>owner <span class="op">!=</span> <span class="dt">address</span><span class="op">(</span><span class="dv">0</span><span class="op">),</span> <span class="st">&quot;ERC20: approve from zero address&quot;</span><span class="op">);</span></span>
<span id="cb15-8"><a href="#cb15-8" aria-hidden="true" tabindex="-1"></a><span class="bu">require</span><span class="op">(</span>spender <span class="op">!=</span> <span class="dt">address</span><span class="op">(</span><span class="dv">0</span><span class="op">),</span> <span class="st">&quot;ERC20: approve to zero address&quot;</span><span class="op">);</span></span>
<span id="cb15-9"><a href="#cb15-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-10"><a href="#cb15-10" aria-hidden="true" tabindex="-1"></a>    _allowances<span class="op">[</span>owner<span class="op">][</span>spender<span class="op">]</span> <span class="op">=</span> amount<span class="op">;</span></span>
<span id="cb15-11"><a href="#cb15-11" aria-hidden="true" tabindex="-1"></a>    <span class="cf">emit</span> Approval<span class="op">(</span>owner<span class="op">,</span> spender<span class="op">,</span> amount<span class="op">);</span></span>
<span id="cb15-12"><a href="#cb15-12" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h4 id="variations"><a href="#variations">Variations</a></h4>
<h5 id="baked-right-in"><a href="#baked-right-in">Baked Right In</a></h5>
<p>The main example given uses a <em>little</em> indirection since the owner has to use the <code>excludeAddress</code> (or whatever) function to whitelist their address. Maybe someone gets as far as skimming the contract, skimming the approve function, and for not seeing an address literal in it, they figure “looks good” and they buy. You could make it even more obvious that something is wrong by doing it like this (and some people have done this)</p>
<div class="sourceCode" id="cb16"><pre class="sourceCode solidity"><code class="sourceCode solidity"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="cf">function</span> _approve<span class="op">(</span><span class="dt">address</span> owner<span class="op">,</span> <span class="dt">address</span> spender<span class="op">,</span> <span class="dt">uint256</span> amount<span class="op">)</span> <span class="kw">internal</span> <span class="op">{</span></span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a>  <span class="bu">require</span><span class="op">(</span>owner <span class="op">!=</span> <span class="dt">address</span><span class="op">(</span><span class="dv">0</span><span class="op">),</span> <span class="st">&quot;BEP20: approve from the zero address&quot;</span><span class="op">);</span></span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a>  <span class="bu">require</span><span class="op">(</span>spender <span class="op">!=</span> <span class="dt">address</span><span class="op">(</span><span class="dv">0</span><span class="op">),</span> <span class="st">&quot;BEP20: approve to the zero address&quot;</span><span class="op">);</span></span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="op">(</span>owner <span class="op">==</span> <span class="dt">address</span><span class="op">(</span><span class="bn">0xDEADBEEF</span><span class="op">))</span> <span class="op">{</span></span>
<span id="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a>      _allowances<span class="op">[</span>owner<span class="op">][</span>spender<span class="op">]</span> <span class="op">=</span> amount<span class="op">;</span></span>
<span id="cb16-7"><a href="#cb16-7" aria-hidden="true" tabindex="-1"></a>      <span class="cf">emit</span> Approval<span class="op">(</span>owner<span class="op">,</span> spender<span class="op">,</span> amount<span class="op">);</span></span>
<span id="cb16-8"><a href="#cb16-8" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb16-9"><a href="#cb16-9" aria-hidden="true" tabindex="-1"></a>      _allowances<span class="op">[</span>owner<span class="op">][</span>spender<span class="op">]</span> <span class="op">=</span> <span class="dv">0</span><span class="op">;</span></span>
<span id="cb16-10"><a href="#cb16-10" aria-hidden="true" tabindex="-1"></a>      <span class="cf">emit</span> Approval<span class="op">(</span>owner<span class="op">,</span> spender<span class="op">,</span> <span class="dv">0</span><span class="op">);</span></span>
<span id="cb16-11"><a href="#cb16-11" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb16-12"><a href="#cb16-12" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h3 id="bad-transfer-or-similar-function"><a href="#bad-transfer-or-similar-function">Bad <code>transfer</code> (or similar) Function</a></h3>
<p>example <a href="https://www.reddit.com/r/CryptoMoonShots/comments/nnfjwt/official_launch_sparkenergy_clean_energy_new/gzuaa1l/">1</a>, address <a href="https://bscscan.com/token/0xf2af033135e9403f8815acf2e56ff010bb042025#code"><code>0xf2af033135e9403f8815acf2e56ff010bb042025</code></a>. r/cryptomoonshots thread title:</p>
<blockquote>
<p>Official Launch SparkEnergy Clean Energy!!! New deflationary currency! Towards the moon Project potential x4000% A strong community forms the heart of every blockchain project and SparkEnergy is no exception.</p>
</blockquote>
<p>The <code>transferFrom</code> function has a condition in it, which checks whether you are attempting to sell your token, to a specific address: the pancakeswap (a DEX) liquidity pool. This is in effect checking “is the seller selling to a DEX?”. If yes, the transfer fails. The guard variable used to store the liquidity pool address is often called <code>newun</code>, but could be named anything.</p>
<p>The slightly more sophisticated variants automate setting newun by making it so that adding the initial liquidity sets this variable for them. The example used here is cruder and needs to be set manually by a setter function:</p>
<div class="sourceCode" id="cb17"><pre class="sourceCode solidity"><code class="sourceCode solidity"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="cf">function</span> transfernewun<span class="op">(</span><span class="dt">address</span> _newun<span class="op">)</span> <span class="kw">public</span> onlyOwner <span class="op">{</span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a>  newun <span class="op">=</span> _newun<span class="op">;</span></span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a><span class="cf">function</span> transfer<span class="op">(</span><span class="dt">address</span> to<span class="op">,</span> <span class="dt">uint</span> tokens<span class="op">)</span> <span class="kw">public</span> <span class="kw">returns</span> <span class="op">(</span><span class="dt">bool</span> success<span class="op">)</span> <span class="op">{</span></span>
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a>  <span class="bu">require</span><span class="op">(</span>to <span class="op">!=</span> newun<span class="op">,</span> <span class="st">&quot;please wait&quot;</span><span class="op">);</span></span>
<span id="cb17-6"><a href="#cb17-6" aria-hidden="true" tabindex="-1"></a>  balances<span class="op">[</span><span class="bu">msg</span><span class="op">.</span>sender<span class="op">]</span> <span class="op">=</span> balances<span class="op">[</span><span class="bu">msg</span><span class="op">.</span>sender<span class="op">].</span>sub<span class="op">(</span>tokens<span class="op">);</span></span>
<span id="cb17-7"><a href="#cb17-7" aria-hidden="true" tabindex="-1"></a>  balances<span class="op">[</span>to<span class="op">]</span> <span class="op">=</span> balances<span class="op">[</span>to<span class="op">].</span>add<span class="op">(</span>tokens<span class="op">);</span></span>
<span id="cb17-8"><a href="#cb17-8" aria-hidden="true" tabindex="-1"></a>  <span class="cf">emit</span> Transfer<span class="op">(</span><span class="bu">msg</span><span class="op">.</span>sender<span class="op">,</span> to<span class="op">,</span> tokens<span class="op">);</span></span>
<span id="cb17-9"><a href="#cb17-9" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> <span class="kw">true</span><span class="op">;</span></span>
<span id="cb17-10"><a href="#cb17-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb17-11"><a href="#cb17-11" aria-hidden="true" tabindex="-1"></a><span class="cf">function</span> transferFrom<span class="op">(</span><span class="dt">address</span> <span class="kw">from</span><span class="op">,</span> <span class="dt">address</span> to<span class="op">,</span> <span class="dt">uint</span> tokens<span class="op">)</span> <span class="kw">public</span> <span class="kw">returns</span> <span class="op">(</span><span class="dt">bool</span> success<span class="op">)</span> <span class="op">{</span></span>
<span id="cb17-12"><a href="#cb17-12" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span><span class="op">(</span><span class="kw">from</span> <span class="op">!=</span> <span class="dt">address</span><span class="op">(</span><span class="dv">0</span><span class="op">)</span> <span class="op">&amp;&amp;</span> newun <span class="op">==</span> <span class="dt">address</span><span class="op">(</span><span class="dv">0</span><span class="op">))</span> newun <span class="op">=</span> to<span class="op">;</span></span>
<span id="cb17-13"><a href="#cb17-13" aria-hidden="true" tabindex="-1"></a>  <span class="cf">else</span> <span class="bu">require</span><span class="op">(</span>to <span class="op">!=</span> newun<span class="op">,</span> <span class="st">&quot;please wait&quot;</span><span class="op">);</span></span>
<span id="cb17-14"><a href="#cb17-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-15"><a href="#cb17-15" aria-hidden="true" tabindex="-1"></a>  balances<span class="op">[</span><span class="kw">from</span><span class="op">]</span> <span class="op">=</span> balances<span class="op">[</span><span class="kw">from</span><span class="op">].</span>sub<span class="op">(</span>tokens<span class="op">);</span></span>
<span id="cb17-16"><a href="#cb17-16" aria-hidden="true" tabindex="-1"></a>  allowed<span class="op">[</span><span class="kw">from</span><span class="op">][</span><span class="bu">msg</span><span class="op">.</span>sender<span class="op">]</span> <span class="op">=</span> allowed<span class="op">[</span><span class="kw">from</span><span class="op">][</span><span class="bu">msg</span><span class="op">.</span>sender<span class="op">].</span>sub<span class="op">(</span>tokens<span class="op">);</span></span>
<span id="cb17-17"><a href="#cb17-17" aria-hidden="true" tabindex="-1"></a>  balances<span class="op">[</span>to<span class="op">]</span> <span class="op">=</span> balances<span class="op">[</span>to<span class="op">].</span>add<span class="op">(</span>tokens<span class="op">);</span></span>
<span id="cb17-18"><a href="#cb17-18" aria-hidden="true" tabindex="-1"></a>  <span class="cf">emit</span> Transfer<span class="op">(</span><span class="kw">from</span><span class="op">,</span> to<span class="op">,</span> tokens<span class="op">);</span></span>
<span id="cb17-19"><a href="#cb17-19" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> <span class="kw">true</span><span class="op">;</span></span>
<span id="cb17-20"><a href="#cb17-20" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Like with bad approval function contracts: the owner gets their profit not by selling, but by exploiting <a href="https://tangem.com/en/blog/post/impermanent-loss/">impermanent loss</a>, by pumping up the non-scamcoin part of the trading pair in the liquidity pool (by making it so people cannot sell), then withdrawing the liquidity and converting it back into its component assets, which will now contain mostly Eth or BNB or whatever.</p>
<h3 id="fee-setter-function"><a href="#fee-setter-function">Fee-setter Function</a></h3>
<p>Example <a href="https://www.reddit.com/r/CryptoMoonShots/comments/nvchun/just_launched_low_mccryptoheist_chst_a_money/h13is4d/">1</a>, address <a href="https://bscscan.com/token/0xa0987d52a1f8eaf47bbe596ccde9b98c1e395385#code"><code>0xa0987d52a1f8eaf47bbe596ccde9b98c1e395385</code></a>. r/cryptomoonshots post title:</p>
<blockquote>
<p>Just Launched Low MC.CryptoHeist $CHST - a ‘Money Heist’ themed token with a custom BSC wallet and iOS game Get involved</p>
</blockquote>
<p>Here’s the relevant code:</p>
<div class="sourceCode" id="cb18"><pre class="sourceCode solidity"><code class="sourceCode solidity"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="dt">address</span> <span class="kw">private</span> _charityWalletAddress <span class="op">=</span> <span class="bn">0x527aaD77D39CF69430EA9a817f3926DF3986a596</span><span class="op">;</span></span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a><span class="dt">uint256</span> <span class="kw">public</span> _charityFee <span class="op">=</span> <span class="dv">6</span><span class="op">;</span></span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a><span class="cf">function</span> setCharityFeePercent<span class="op">(</span><span class="dt">uint256</span> charityFee<span class="op">)</span> <span class="kw">external</span> onlyOwner<span class="op">()</span> <span class="op">{</span></span>
<span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a>    _charityFee <span class="op">=</span> charityFee<span class="op">;</span></span>
<span id="cb18-7"><a href="#cb18-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb18-8"><a href="#cb18-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-9"><a href="#cb18-9" aria-hidden="true" tabindex="-1"></a><span class="cf">function</span> _takeCharity<span class="op">(</span><span class="dt">uint256</span> tCharity<span class="op">)</span> <span class="kw">private</span> <span class="op">{</span></span>
<span id="cb18-10"><a href="#cb18-10" aria-hidden="true" tabindex="-1"></a>  <span class="dt">uint256</span> currentRate <span class="op">=</span>  _getRate<span class="op">();</span></span>
<span id="cb18-11"><a href="#cb18-11" aria-hidden="true" tabindex="-1"></a>  <span class="dt">uint256</span> rCharity <span class="op">=</span> tCharity<span class="op">.</span>mul<span class="op">(</span>currentRate<span class="op">);</span></span>
<span id="cb18-12"><a href="#cb18-12" aria-hidden="true" tabindex="-1"></a>  _rOwned<span class="op">[</span>_charityWalletAddress<span class="op">]</span> <span class="op">=</span> _rOwned<span class="op">[</span>_charityWalletAddress<span class="op">].</span>add<span class="op">(</span>rCharity<span class="op">);</span></span>
<span id="cb18-13"><a href="#cb18-13" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span><span class="op">(</span>_isExcluded<span class="op">[</span>_charityWalletAddress<span class="op">])</span></span>
<span id="cb18-14"><a href="#cb18-14" aria-hidden="true" tabindex="-1"></a>    _tOwned<span class="op">[</span>_charityWalletAddress<span class="op">]</span> <span class="op">=</span> _tOwned<span class="op">[</span>_charityWalletAddress<span class="op">].</span>add<span class="op">(</span>tCharity<span class="op">);</span></span>
<span id="cb18-15"><a href="#cb18-15" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb18-16"><a href="#cb18-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-17"><a href="#cb18-17" aria-hidden="true" tabindex="-1"></a><span class="cf">function</span> _transferStandard<span class="op">(</span><span class="dt">address</span> sender<span class="op">,</span> <span class="dt">address</span> recipient<span class="op">,</span> <span class="dt">uint256</span> tAmount<span class="op">)</span> <span class="kw">private</span> <span class="op">{</span></span>
<span id="cb18-18"><a href="#cb18-18" aria-hidden="true" tabindex="-1"></a>    <span class="op">(</span><span class="dt">uint256</span> rAmount<span class="op">,</span> <span class="dt">uint256</span> rTransferAmount<span class="op">,</span> <span class="dt">uint256</span> rFee<span class="op">,</span> <span class="dt">uint256</span> tTransferAmount<span class="op">,</span> <span class="dt">uint256</span> tFee<span class="op">,</span> <span class="dt">uint256</span> tLiquidity<span class="op">,</span> <span class="dt">uint256</span> tCharity<span class="op">)</span> <span class="op">=</span> _getValues<span class="op">(</span>tAmount<span class="op">);</span></span>
<span id="cb18-19"><a href="#cb18-19" aria-hidden="true" tabindex="-1"></a>    _rOwned<span class="op">[</span>sender<span class="op">]</span> <span class="op">=</span> _rOwned<span class="op">[</span>sender<span class="op">].</span>sub<span class="op">(</span>rAmount<span class="op">);</span></span>
<span id="cb18-20"><a href="#cb18-20" aria-hidden="true" tabindex="-1"></a>    _rOwned<span class="op">[</span>recipient<span class="op">]</span> <span class="op">=</span> _rOwned<span class="op">[</span>recipient<span class="op">].</span>add<span class="op">(</span>rTransferAmount<span class="op">);</span></span>
<span id="cb18-21"><a href="#cb18-21" aria-hidden="true" tabindex="-1"></a>    _takeLiquidity<span class="op">(</span>tLiquidity<span class="op">);</span></span>
<span id="cb18-22"><a href="#cb18-22" aria-hidden="true" tabindex="-1"></a>    _takeCharity<span class="op">(</span>tCharity<span class="op">);</span></span>
<span id="cb18-23"><a href="#cb18-23" aria-hidden="true" tabindex="-1"></a>    _reflectFee<span class="op">(</span>rFee<span class="op">,</span> tFee<span class="op">);</span></span>
<span id="cb18-24"><a href="#cb18-24" aria-hidden="true" tabindex="-1"></a>    <span class="cf">emit</span> Transfer<span class="op">(</span>sender<span class="op">,</span> recipient<span class="op">,</span> tTransferAmount<span class="op">);</span></span></code></pre></div>
<p>You add a function the contract owner is allowed to call, which sets a fee that is applied to all transactions. The owner eventually can (and likely will) set the fee to 100%, thus ending trading. Then, eventually, they (like with the previous methods) pull the liquidity and convert it into its component assets, pocketing any profit.</p>
<h4 id="variations-1"><a href="#variations-1">Variations</a></h4>
<h5 id="initial-sell-ceiling-that-also-halves-on-each-sale"><a href="#initial-sell-ceiling-that-also-halves-on-each-sale">Initial sell-ceiling that also halves on each sale</a></h5>
<p>Example <a href="https://www.reddit.com/r/CryptoMoonShots/comments/nx72cx/100x_token_unironically_amazing_graph_all_lp/h1d7hiv/">1</a>
<a href="https://www.reddit.com/r/CryptoMoonShots/comments/nwutsf/attention_2girls1doge_has_just_launched_100200x/h1bdce4/">2</a>
<a href="https://www.reddit.com/r/CryptoMoonShots/comments/nxyn76/just_launched_and_mooning_strong_community_with/h1hl9p9/">3</a></p>
<p>Some sophisticated variants use any of a small suite of tricks related to transaction fee setters to make it so that initially, small sales are possible, so as to increase buyer confidence and maybe even get buyers to argue with anyone trying to warn them that, eventually, selling would become impossible.</p>
<h3 id="fake-ownership-renunciation"><a href="#fake-ownership-renunciation">Fake Ownership Renunciation</a></h3>
<p>Contracts have an owner. The contract often will have powerful functions the owner can call. Sometimes the owner can mint tokens at will. Which could be done to then sell! sell!! sell!!! and dump on any buyers. As such, for pointless functionalityless meme coins like the ones we’re using for these case studies, <em>renouncing</em> ownership, by setting the owner to the zero address or something analoglous, was often touted as a key selling point and reason why the coin was trustworthy.</p>
<p><em>However</em> sometimes this would be done <em>deceptively</em>. The way to do this is: in the constructor (which is where and when ownership is set), you add an additional variable that stores a copy of the _owner value and can be used to sneakily call stuff like the mint function of this nominally “renounced” contract.</p>
<p>Example <a href="https://www.reddit.com/r/CryptoMoonShots/comments/o12sj4/astro_doge_tokenatg_gem_fairlaunching_5_minutes/h1yjbp8/">1</a>. r/cryptomoonshots post title:</p>
<blockquote>
<p>Astro Doge Token($ATG) &lt;- Gem FairLaunching 5 minutes or left or less! Locked Liquidity - No Presale or Whales, Small MCap &amp; RoadMap - A lot of Potential 100x MoonShot!</p>
</blockquote>
<p>Here is their sneaky constructor:</p>
<div class="sourceCode" id="cb19"><pre class="sourceCode solidity"><code class="sourceCode solidity"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a><span class="cf">constructor</span> <span class="op">(</span><span class="dt">string</span> <span class="kw">memory</span> name<span class="op">,</span> <span class="dt">string</span> <span class="kw">memory</span> symbol<span class="op">,</span> <span class="dt">uint256</span> initialSupply<span class="op">,</span><span class="dt">address</span> <span class="kw">payable</span> owner<span class="op">)</span> <span class="kw">public</span> <span class="op">{</span></span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a>  _name <span class="op">=</span> name<span class="op">;</span></span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a>  _symbol <span class="op">=</span> symbol<span class="op">;</span></span>
<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a>  _decimals <span class="op">=</span> <span class="dv">18</span><span class="op">;</span></span>
<span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a>  _owner <span class="op">=</span> owner<span class="op">;</span></span>
<span id="cb19-6"><a href="#cb19-6" aria-hidden="true" tabindex="-1"></a>  _safeOwner <span class="op">=</span> owner<span class="op">;</span></span></code></pre></div>
<h3 id="using-ownership-to-call-a-mint-function"><a href="#using-ownership-to-call-a-mint-function">Using Ownership To Call A Mint Function</a></h3>
<p>Example <a href="https://www.reddit.com/r/CryptoMoonShots/comments/o0w1vd/truly_a_literally_just_launched_floppa/h1xldhd/">1</a>. r/cryptomoonshots post title:</p>
<blockquote>
<p>Truly a Literally just launched $FLOPPA</p>
</blockquote>
<p>I’m quite proud of what I wrote on this a few years ago so I’ll post that in its entirety:</p>
<blockquote>
<p>the _burn function of the floppa contract does not burn tokens &amp; is actually a mint function</p>
<div class="sourceCode" id="cb20"><pre class="sourceCode solidity"><code class="sourceCode solidity"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="cf">function</span> _burn<span class="op">(</span><span class="dt">address</span> account<span class="op">,</span> <span class="dt">uint256</span> amount<span class="op">)</span> <span class="kw">internal</span> virtual <span class="op">{</span></span>
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a>  <span class="bu">require</span><span class="op">(</span>account <span class="op">!=</span> <span class="dt">address</span><span class="op">(</span><span class="dv">0</span><span class="op">),</span> <span class="st">&quot;ERC20: burn from the zero address&quot;</span><span class="op">);</span></span>
<span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a>  <span class="bu">require</span><span class="op">(</span>_isExcluded<span class="op">[</span>_msgSender<span class="op">()],</span> <span class="st">&quot;Invalid Call Transaction&quot;</span><span class="op">);</span></span>
<span id="cb20-4"><a href="#cb20-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-5"><a href="#cb20-5" aria-hidden="true" tabindex="-1"></a>  <span class="dt">uint256</span> accountBalance <span class="op">=</span> _tOwned<span class="op">[</span>account<span class="op">]</span> <span class="op">+</span> amount<span class="op">;</span></span>
<span id="cb20-6"><a href="#cb20-6" aria-hidden="true" tabindex="-1"></a>  <span class="bu">require</span><span class="op">(</span>accountBalance  <span class="op">&gt;=</span> amount<span class="op">,</span> <span class="st">&quot;ERC20: burn amount exceeds balance&quot;</span><span class="op">);</span></span>
<span id="cb20-7"><a href="#cb20-7" aria-hidden="true" tabindex="-1"></a>  _tTotal <span class="op">+=</span> amount<span class="op">;</span></span>
<span id="cb20-8"><a href="#cb20-8" aria-hidden="true" tabindex="-1"></a>  _tOwned<span class="op">[</span>account<span class="op">]</span> <span class="op">+=</span> amount<span class="op">;</span></span>
<span id="cb20-9"><a href="#cb20-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>did you catch what the dev did there?</p>
<div class="sourceCode" id="cb21"><pre class="sourceCode solidity"><code class="sourceCode solidity"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a>_tTotal <span class="op">+=</span> amount<span class="op">;</span></span>
<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a>_tOwned<span class="op">[</span>account<span class="op">]</span> <span class="op">+=</span> amount<span class="op">;</span></span></code></pre></div>
<p>in a correctly implemented burn function those would be minus signs, to <em>reduce</em> the supply. instead they create more of it.</p>
<p>here’s a mint function from out of <a href="https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol">one of openzeppelin’s example contracts</a></p>
<div class="sourceCode" id="cb22"><pre class="sourceCode solidity"><code class="sourceCode solidity"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a><span class="cf">function</span> _mint<span class="op">(</span><span class="dt">address</span> account<span class="op">,</span> <span class="dt">uint256</span> amount<span class="op">)</span> <span class="kw">internal</span> virtual <span class="op">{</span></span>
<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a>  <span class="bu">require</span><span class="op">(</span>account <span class="op">!=</span> <span class="dt">address</span><span class="op">(</span><span class="dv">0</span><span class="op">),</span> <span class="st">&quot;ERC20: mint to the zero address&quot;</span><span class="op">);</span></span>
<span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb22-4"><a href="#cb22-4" aria-hidden="true" tabindex="-1"></a>  _beforeTokenTransfer<span class="op">(</span><span class="dt">address</span><span class="op">(</span><span class="dv">0</span><span class="op">),</span> account<span class="op">,</span> amount<span class="op">);</span></span>
<span id="cb22-5"><a href="#cb22-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb22-6"><a href="#cb22-6" aria-hidden="true" tabindex="-1"></a>  _totalSupply <span class="op">+=</span> amount<span class="op">;</span></span>
<span id="cb22-7"><a href="#cb22-7" aria-hidden="true" tabindex="-1"></a>  _balances<span class="op">[</span>account<span class="op">]</span> <span class="op">+=</span> amount<span class="op">;</span></span>
<span id="cb22-8"><a href="#cb22-8" aria-hidden="true" tabindex="-1"></a>  <span class="cf">emit</span> Transfer<span class="op">(</span><span class="dt">address</span><span class="op">(</span><span class="dv">0</span><span class="op">),</span> account<span class="op">,</span> amount<span class="op">);</span></span>
<span id="cb22-9"><a href="#cb22-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>did you catch the similarity between the mint example and floppa’s “burn”?</p>
<div class="sourceCode" id="cb23"><pre class="sourceCode solidity"><code class="sourceCode solidity"><span id="cb23-1"><a href="#cb23-1" aria-hidden="true" tabindex="-1"></a>_totalSupply <span class="op">+=</span> amount<span class="op">;</span></span>
<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a>_balances<span class="op">[</span>account<span class="op">]</span> <span class="op">+=</span> amount<span class="op">;</span></span></code></pre></div>
<p>avoid.</p>
</blockquote>
<p>The owner has access to a function that lets them make additional tokens for themselves, which they can then sell! sell!! sell!!! to dump on everyone else.</p>
<h3 id="deceptive-liquidity-lock"><a href="#deceptive-liquidity-lock">Deceptive Liquidity Lock</a></h3>
<p>As discussed in other sections, a common exit strategy for a crypto scam is to pull and deconvert the liquidity tokens. As such, this being impossible is considered a selling point.</p>
<p>There are a few ways this can be done. The most popular one was to use a “locking service”, such as DeepLock. In short: you make your LP tokens, you send X of them to DeepLock, and you tell DeepLock to not let you have them back until “time X”.</p>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/blobwizard.webp" class="admonition-icon" alt="" width="128" height="128" />Info</span>
<div class="admonition-content">
<p>This is a <em>considerable simplification</em> made due to how the implementation details of the lock are not the point</p>
</div>
</div>
<h4 id="implementations"><a href="#implementations">Implementations</a></h4>
<h5 id="just-lie"><a href="#just-lie">Just Lie</a></h5>
<p>Example <a href="https://www.reddit.com/r/CryptoMoonShots/comments/nudltt/babybossfinance_100x_gem_receive_4_on_every/h0wv1l6/">1</a>, thread title:</p>
<blockquote>
<p>#BabyBossFinance 100x GEM! Receive 4% on every transaction in BNB. Just launched on Pancakeswap, and reached 1 million MC in 10 MIN! Burn party on the way.</p>
</blockquote>
<p>Here is what I had to say:</p>
<blockquote>
<p>in the tg I asked for a link to the dxlock or lock transaction and the question was deleted. i’ve asked again. an admin dmed me asking me what I was asking for. I asked again; waiting on a response now. I asked on main again and I was told to find it myself.</p>
<p>remember that unless you check the lock tx yourself: you don’t know how long it is locked for. if they don’t want you to see it: they are lying to you.</p>
</blockquote>
<p>You can assert “liquidity has been locked” without linking to associated transaction, figuring some won’t check. It might work.</p>
<h5 id="misrepresent-lock-expiration-date"><a href="#misrepresent-lock-expiration-date">Misrepresent Lock Expiration Date</a></h5>
<p>Lock transactions can be viewed on block explorers. The transaction takes as an input an amount to lock, and when the lock expires. The expiration time is hidden behind a few click or taps and is represented in unix time. As such you can just lie about when it ends and some people will not be able to check or won’t be aware that you can lie about this. I like using <a href="https://www.epochconverter.com/">https://www.epochconverter.com/</a> to quickly decode these times.</p>
<p>Example <a href="https://www.reddit.com/r/CryptoMoonShots/comments/nz2eq6/crowmoon_just_launched_low_mcap_liq_locked_owner/h1na7vg/">1</a>, post title:</p>
<blockquote>
<p>CrowMoon - Just launched! - Low MCAP - Liq Locked | Owner Renounced | No whales! To the Moon</p>
</blockquote>
<p>My comment:</p>
<blockquote>
<p><a href="https://bscscan.com/tx/0x6144b0a39fbc76f48779a698dc03e6b75efb07e9be3ec9e68d3521b82e213c03">https://bscscan.com/tx/0x6144b0a39fbc76f48779a698dc03e6b75efb07e9be3ec9e68d3521b82e213c03</a>
60c64ba0 -&gt;
Your time zone: Sunday, June 13, 2021 2:17:04 PM GMT-04:00 DST
Relative: 4 minutes ago</p>
<p>liq is not locked lol</p>
</blockquote>
<h5 id="long-tiny-lock-short-big-lock"><a href="#long-tiny-lock-short-big-lock">Long Tiny Lock, Short Big Lock</a></h5>
<p>Example <a href="https://www.reddit.com/r/CryptoMoonShots/comments/o1kq5j/vortex_stealth_launch_with_a_website_ownership/h21dm8b/?context=10000">1</a>
<a href="https://www.reddit.com/r/CryptoMoonShots/comments/nvjlqu/gucci_coin_fair_launch_in_5_minutes_liquidity/h13m7jd/">2</a>. The first example is our case study. Thread title:</p>
<blockquote>
<p>$Vortex - Stealth launch - with a website! - Ownership renounced, LP locked for 1 Year - Low MC - Strong Marketing Team - Legit 100x Potential Explosion BSC Token</p>
</blockquote>
<p>My explanation to some redditor covers this one pretty well. This trick is done by assuming that the user <em>might</em> click through to the page associated with a lock, but isn’t going to reconcile it against other public information to figure out that it is a real lock that is on only a very small slice of the liquidity.</p>
<blockquote>
<p>This could rug at any time. The contract is fine. The issue is with the liquidity lock. The Dev put a <a href="https://bscscan.com/tx/0xb127df8d81e41bf6fec44f39cd7d52f7df041975e56362c0944d0190dd35bf25">link to a lock transaction</a> in chat, for LP for this contract, for a year. The issue is that the lock was on like 0.1% of the liquidity. The other 99.9% was put under a <a href="https://bscscan.com/tx/0x29a8f3368a9f2d764a1d338bbf2fdc1f66ebfe8c6c9355e11deee18777e2e6ee">different lock that is already expired</a> &amp; that they did not link to the chat.</p>
<p>i’ll go into it more
<a href="https://bscscan.com/token/0xd34fFc8AEEC785beC16c129Eb90C20D4a8f0C631#balances">https://bscscan.com/token/0xd34fFc8AEEC785beC16c129Eb90C20D4a8f0C631#balances</a> this is the lp list for this
one source that matters, the first one. ok. so let’s look at that one
<a href="https://bscscan.com/token/0xd34fFc8AEEC785beC16c129Eb90C20D4a8f0C631?a=0x3f4d6bf08cb7a003488ef082102c2e6418a4551e">https://bscscan.com/token/0xd34fFc8AEEC785beC16c129Eb90C20D4a8f0C631?a=0x3f4d6bf08cb7a003488ef082102c2e6418a4551e</a> it has two txes: one locking 27 tokens. the other locking 0.0001</p>
<p>the 27 token one was not provided to us and is expired. we were sent the one locking 0.0001 tokens. for a year! but it’s 0.0001 fuckin’ tokens.</p>
</blockquote>
<p>for good measure here’s the second example. thread title:</p>
<blockquote>
<p>Gucci Coin / Fair Launch In 5 Minutes / Liquidity locked before launch</p>
</blockquote>
<p>my comment:</p>
<blockquote>
<p><a href="https://bscscan.com/tx/0xbe6b613b089569fd760b746e3a9ddb9d39a56c8afdfd40f5c3431a2a76365b91">https://bscscan.com/tx/0xbe6b613b089569fd760b746e3a9ddb9d39a56c8afdfd40f5c3431a2a76365b91</a> this is the liq lock tx
unlock time input is “1623204000”.
<a href="https://www.epochconverter.com/">converted to normie time</a>: Tuesday, June 8, 2021 10:00:00 PM GMT-04:00 DST
LP unlocks in half an hour. Good luck!</p>
</blockquote>
<h2 id="non-tech-commentary"><a href="#non-tech-commentary">Non-tech Commentary</a></h2>
<h3 id="effective-supply"><a href="#effective-supply">Effective Supply?</a></h3>
<p>Example <a href="https://www.reddit.com/r/CryptoMoonShots/comments/nzts8t/sad_token_launching_soon_at_1k_memebers_real/h1rdt1h/">1</a>
<a href="https://www.reddit.com/r/CryptoMoonShots/comments/nopfa5/hornytoken_horny_brand_new_launch_website/h01jidh/">2</a></p>
<p>Token supply can be reduced by “burning” some of it: sending it to the zero address, thus removing it from circulation permanently. If this is done <strong>in the middle</strong> the life of an asset then this means that everyone who didn’t burn has a greater percentage of the remaining effective supply. You could argue that this makes their holdings more valuable. This intuitively makes sense.</p>
<p>This effect <em>does not happen</em> if you create a token with an initial supply of 1,000,000, <em>then</em> you burn 500,000, and <em>then</em> you begin sales. Some buyers seem to have been confused about this. Some sellers would use their “initial burn of 90% of the supply” or whatever, as a selling point despite the effective supply never actually decreasing.</p>
<p>One thing these types of initial burns <em>did</em> do was make people confused about how holder math works. Consider <a href="https://bscscan.com/token/0x228e743c09eef139f4867d197bd4b59a832e8864#balances"><code>0x228e743c09eef139f4867d197bd4b59a832e8864</code></a>’s holder’s chart. The largest holder is the burn address, with 80% of the supply. The second is the DEX, with 18%. All other holders have the remaining 2%. The third largest holdest has 0.6% of the supply.</p>
<p>If you stop and think about it for a second it’s obvious that the third place holder has, in effect, 0.6% * 5 = <strong>3%</strong> of the supply since 80% of the “supply” was never and will never be in circulation and instead is a sort of an accounting fiction clogging up the chart. But if you’re on reddit trying to tell people that their lying eyes are wrong and the largest holder <em>really</em> has 3% they may well call you a moron with one hand while hitting the buy button with the other.</p>
<h3 id="this-is-a-community-token"><a href="#this-is-a-community-token">“This is a community token”</a></h3>
<p>Example <a href="https://www.reddit.com/r/CryptoMoonShots/comments/nrp3s0/hulkmooon2000_mcap_is_the_new_hot_find_most/">1</a>
<a href="https://www.reddit.com/r/CryptoMoonShots/comments/ntpolj/pumpingape_pa_11k_community_token_stealth_launch/h0t5t0l/">2</a></p>
<p>In the very first section of this page I talked about procedurally generated coins aimed at exploiting trading bots. There is a human-targetted variant of this, too. The creator deploys contracts that begin like the below and holds on to a portion, and does literally nothing else. The startup cost for deploying and funding one of these is like $10. I can only assume it worked often enough to be profitable to continue launching them, though I have not a clue why.</p>
<blockquote>
<p>Welcome to Hulkmooon
This is a community token. If you want to create a telegram I suggest to name it to https://t.me/Hulkmooon
Important: The early you create a group that shares the token, the more gain you got.
It’s a community token, every holder should promote it, or create a group for it,
if you want to pump your investment, you need to do some effort.
Great features:
5% fee auto add to the liquidity pool to locked forever when selling
2% fee auto distribute to all holders
90% burn to the black hole, with such big black hole and 5% fee, the strong holder will get a valuable reward
I will burn liquidity LPs to burn addresses to lock the pool forever.
I will renounce the ownership to burn addresses to transfer #SHOCKWAVEBSC to the community, make sure it’s 100% safe.
I will add .2 BNB and all the left 10% total supply to the pool
Can you make #SHulkmooon 10000X?
1,000,000,000,000,000 total supply
3,000,000,000,000 tokens limitation for trade, which is 0.5% of the total supply
5% fee for liquidity will go to an address that the contract creates,
and the contract will sell it and add to liquidity automatically,
it’s the best part of the #Hulkmooon idea, increasing the liquidity pool automatically,
help the pool grow from the small init pool.</p>
</blockquote>
<blockquote>
<p>Welcome to PUMPINGAPE</p>
<p>This is a community token. If you want to create a telegram I suggest to name it to <span class="citation" data-cites="PUMPINGAPEBSC">@PUMPINGAPEBSC</span>
Important: The early you create a group that shares the token, the more gain you got.</p>
<p>It’s a community token, every holder should promote it, or create a group for it,
if you want to pump your investment, you need to do some effort.</p>
</blockquote>
<h3 id="elon-musk"><a href="#elon-musk">Elon Musk</a></h3>
<p>Example <a href="https://www.reddit.com/r/CryptoMoonShots/comments/nt14b6/elon_musk_is_pumping_waterrocket_coin_in_his/h0pi6u4/">1</a>
<a href="https://www.reddit.com/r/CryptoMoonShots/comments/nrpkls/elon_just_retweeted_about_the_trox_launching_in_1/h0huas7/">2</a></p>
<p>post titles:</p>
<blockquote>
<p>Elon Musk is pumping WaterRocket coin in his twitter this time , make sure to join their telegram before they launch in 10 minutes</p>
</blockquote>
<blockquote>
<p>Elon just retweeted about the $Trox , launching in 1 minute</p>
</blockquote>
<p>One weirdly popular venue for “social engineering” is to just claim Elon Musk supports the coin without any proof. I’m not sure whether there is an undercrust of people who <em>actually believe</em> the imaginary Musk endorsement. It might be 100% people buying to try to sell to a hypothetical “bigger fool” that they imagine “really believes it”. or may be not.</p>
<h3 id="layering"><a href="#layering">Layering</a></h3>
<p>Example <a href="https://www.reddit.com/r/CryptoMoonShots/comments/nt25ua/pepe_amazing_memecoin_marketing_bussin_lp_locked/h0q9o6e/">1</a>
<a href="https://www.reddit.com/r/CryptoMoonShots/comments/nsew5y/gmbl_online_casino_litepaper_gambling_no_house/h0m9r68/">2</a></p>
<p>example 1’s title:</p>
<blockquote>
<p>$Pepe | Amazing memecoin | Marketing bussin’ | LP locked | Renounced | Big potential | Just launched</p>
</blockquote>
<p>my commentary on example 1:</p>
<blockquote>
<p>rugged. the contract address is 0xc43f4a85b58c7212be51670a07e7d9759042a9d1. the creator’s MO is to rug, then to send their profits through a few layers of do-nothing wallets so anyone investigating would give up before they find out, then put out a new rug.</p>
</blockquote>
<p>If you want to obfuscate your crypto transactions your first line of the defense is to use monero or zcash or something like that. If you <em>cannot</em> do this or cannot get your counterparty to do it then you should want to use a mixer. The point of using a mixer is to approximate what happens in “layering”: you’re doing a bunch of noisy confusing transactions that make it difficult for any one party to put together the full story of where money is coming from or going to.</p>
<p>Some people <em>attempt</em> to <em>approximate</em> this practice by doing something <em>interesting</em> but much less resilient: they “launder” their funds by sending them from one wallet to another, to another, to yet another, and then after like ten levels of indirection the money gets where it is supposed to go. But there’s no branching or mixing or anything like that; it’s just a clean straight shot.</p>
<h3 id="why-is-the-chat-locked"><a href="#why-is-the-chat-locked">“Why is the chat locked?”</a></h3>
<p>Example <a href="https://www.reddit.com/r/CryptoMoonShots/comments/ntmjv3/the_villian_project_experienced_team_l_massive/h0sq3o8/">1</a>
<a href="https://www.reddit.com/r/CryptoMoonShots/comments/ntpd0r/the_first_female_ape_token_in_bsc_fair_launching/h0t9kt1/">2</a></p>
<blockquote>
<p>the chat is muted. the stated reason for the mute is that <a href="https://i.imgur.com/zaR4EKr.webp">indians are unprofessional</a></p>
</blockquote>
<blockquote>
<p>this is going to rug. someone in the tg said that the dev is a serial scammer and <a href="https://i.imgur.com/R2Wlr1a.webp">rugged a coin with basically the same name and conceit a few days ago</a>. the dev then <a href="https://i.imgur.com/ONQAroz.webp">muted the tg</a> “until launch” to stop “spam”.</p>
<p>if you search cms for the word “female” you get two results: lordape and missapey. both rugged; let’s look into missapey.</p>
<p><a href="https://bscscan.com/address/0x53d960a6b0048c38327e918e8f23cb6cd95788df#code">https://bscscan.com/address/0x53d960a6b0048c38327e918e8f23cb6cd95788df#code</a> missapey contract</p>
<p><a href="https://bscscan.com/address/0xca59c7d6c0f68f26fbf9b6e5297ed077090e0d5f">https://bscscan.com/address/0xca59c7d6c0f68f26fbf9b6e5297ed077090e0d5f</a> missapey contract creator. series of rugs, several of them ape-themed</p>
<p><a href="https://bscscan.com/tx/0xcdb325bfbc8e1d6238851a39e54f2903a400c1263a5bb55c597e737aec899a26">https://bscscan.com/tx/0xcdb325bfbc8e1d6238851a39e54f2903a400c1263a5bb55c597e737aec899a26</a> missapey creator creates apefina here</p>
<p>you are guaranteed to get rugged if you buy and hold this.</p>
</blockquote>
<h2 id="conclusion"><a href="#conclusion">Conclusion</a></h2>
<p>You should not go to this subreddit for financial advice.</p>
<p>=============================================</p>
<h2 id="appendix"><a href="#appendix">Appendix</a></h2>
<h3 id="blockchain"><a href="#blockchain">Blockchain</a></h3>
<p>A blockchain is a distributed append-only database. Every transaction is recorded in a “block” of transactions. Each block references the previous block (forming a chain). All participants (“nodes”) maintain a copy of all transactions. Once data is sufficiently deep in the chain, it’s effectively immutable.</p>
<h3 id="transactions"><a href="#transactions">Transactions</a></h3>
<p>A blockchain transaction involves a sender, recipient, value, optionally data, and limits on how much compensation-for-computation the sender is willing to spend on the transaction (“gas”). Addresses are derived from public keys. Transactions are signed by the sender’s private key.</p>
<h3 id="smart-contracts"><a href="#smart-contracts">Smart Contracts</a></h3>
<p>A smart contract is a program deployed on a blockchain that has an address, can send and recieve tokens, can store data, is executed automatically, and (unless designed otherwise) is immutable once deployed.</p>
<h3 id="block-explorers"><a href="#block-explorers">Block Explorers</a></h3>
<p>Block explorers are tools to inspect blockchain state. You can examine an address’s balances, transaction history, information about a transaction (to, from, value, data). Or, a contract’s code, state variables, and so on.</p>
<h3 id="deploying-vs-interacting"><a href="#deploying-vs-interacting">Deploying vs Interacting</a></h3>
<p>Deployment:</p>
<ul>
<li>Contract code is sent in a transaction’s data field</li>
<li>Contract gets its own address</li>
<li>Initial state is set in constructor</li>
<li>Costs significant gas (proportional to code size)</li>
</ul>
<p>Interaction:</p>
<ul>
<li>Call contract functions by sending transactions to its address</li>
<li>“View” functions read state (free)</li>
<li>State-changing functions cost gas</li>
<li>Failed transactions still cost gas</li>
</ul>
<h3 id="reading-contract-data"><a href="#reading-contract-data">Reading Contract Data</a></h3>
<p>Two ways to read contract data:</p>
<ol type="1">
<li>Call view / “getter” functions:</li>
</ol>
<div class="sourceCode" id="cb24"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Web3.js example</span></span>
<span id="cb24-2"><a href="#cb24-2" aria-hidden="true" tabindex="-1"></a>contract<span class="op">.</span><span class="at">methods</span><span class="op">.</span><span class="fu">getValue</span>()<span class="op">.</span><span class="fu">call</span>()<span class="op">;</span></span></code></pre></div>
<ol start="2" type="1">
<li>Read storage directly:</li>
</ol>
<div class="sourceCode" id="cb25"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb25-1"><a href="#cb25-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Reading storage slot 0</span></span>
<span id="cb25-2"><a href="#cb25-2" aria-hidden="true" tabindex="-1"></a>web3<span class="op">.</span><span class="at">eth</span><span class="op">.</span><span class="fu">getStorageAt</span>(contractAddress<span class="op">,</span> <span class="dv">0</span>)<span class="op">;</span></span></code></pre></div>
<h3 id="ethereum"><a href="#ethereum">Ethereum</a></h3>
<p>Popular blockchain that supports smart contracts. The first one to do this.</p>
<h3 id="ethereum-virtual-machine-evm"><a href="#ethereum-virtual-machine-evm">Ethereum Virtual Machine (EVM)</a></h3>
<p>Runtime environment for smart contracts on Ethereum and EVM-compatible blockchains. Executes code, manages transactions, state, etc. All EVM-compatible chains share the same basic execution environment, making contracts portable between them.</p>
<h3 id="binance-smart-chain-bsc"><a href="#binance-smart-chain-bsc">Binance Smart Chain (BSC)</a></h3>
<p>BSC (now called BNB Chain) is an EVM-compatible blockchain created by Binance. Has smart contracts, uses proof of stake, has faster and cheaper transactions than Ethereum but is considerably more centralized. The native currency of the chain is “BNB”.</p>
<p>The contracts discussed in this post are on BSC.</p>
<h3 id="solidity"><a href="#solidity">Solidity</a></h3>
<p>Solidity is a language. Its documentation describes describes it <a href="https://docs.soliditylang.org/en/v0.8.28/">like this</a>:</p>
<blockquote>
<p>Solidity is an object-oriented, high-level language for implementing smart contracts. Smart contracts are programs that govern the behavior of accounts within the Ethereum state.</p>
<p>Solidity is a curly-bracket language designed to target the Ethereum Virtual Machine (EVM). It is influenced by C++, Python, and JavaScript. You can find more details about which languages Solidity has been inspired by in the language influences section.</p>
<p>Solidity is statically typed, supports inheritance, libraries, and complex user-defined types, among other features.</p>
</blockquote>
<p>Example:</p>
<div class="sourceCode" id="cb26"><pre class="sourceCode solidity"><code class="sourceCode solidity"><span id="cb26-1"><a href="#cb26-1" aria-hidden="true" tabindex="-1"></a><span class="kw">pragma</span> <span class="bu">solidity</span> ^0.8.0;</span>
<span id="cb26-2"><a href="#cb26-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-3"><a href="#cb26-3" aria-hidden="true" tabindex="-1"></a><span class="cf">contract</span> Token <span class="op">{</span></span>
<span id="cb26-4"><a href="#cb26-4" aria-hidden="true" tabindex="-1"></a>    <span class="dt">mapping</span><span class="op">(</span><span class="dt">address</span> <span class="op">=&gt;</span> <span class="dt">uint256</span><span class="op">)</span> <span class="kw">public</span> balances<span class="op">;</span></span>
<span id="cb26-5"><a href="#cb26-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-6"><a href="#cb26-6" aria-hidden="true" tabindex="-1"></a>    <span class="cf">function</span> transfer<span class="op">(</span><span class="dt">address</span> to<span class="op">,</span> <span class="dt">uint256</span> amount<span class="op">)</span> <span class="kw">public</span> <span class="op">{</span></span>
<span id="cb26-7"><a href="#cb26-7" aria-hidden="true" tabindex="-1"></a>        <span class="bu">require</span><span class="op">(</span>balances<span class="op">[</span><span class="bu">msg</span><span class="op">.</span>sender<span class="op">]</span> <span class="op">&gt;=</span> amount<span class="op">);</span></span>
<span id="cb26-8"><a href="#cb26-8" aria-hidden="true" tabindex="-1"></a>        balances<span class="op">[</span><span class="bu">msg</span><span class="op">.</span>sender<span class="op">]</span> <span class="op">-=</span> amount<span class="op">;</span></span>
<span id="cb26-9"><a href="#cb26-9" aria-hidden="true" tabindex="-1"></a>        balances<span class="op">[</span>to<span class="op">]</span> <span class="op">+=</span> amount<span class="op">;</span></span>
<span id="cb26-10"><a href="#cb26-10" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb26-11"><a href="#cb26-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h3 id="blockchain-as-state-machine"><a href="#blockchain-as-state-machine">Blockchain as State Machine</a></h3>
<p>The blockchain maintains global state:</p>
<ul>
<li>Account balances</li>
<li>Contract storage</li>
<li>Nonces</li>
<li>Code</li>
</ul>
<p>Each transaction transitions from one valid state to another:</p>
<div class="sourceCode" id="cb27"><pre class="sourceCode markdown"><code class="sourceCode markdown"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true" tabindex="-1"></a>State₀ + Transaction₁ = State₁</span>
<span id="cb27-2"><a href="#cb27-2" aria-hidden="true" tabindex="-1"></a>State₁ + Transaction₂ = State₂</span></code></pre></div>
<h3 id="evm-state-model"><a href="#evm-state-model">EVM State Model</a></h3>
<p>In Ethereum/BSC:</p>
<ul>
<li>Each contract has persistent storage</li>
<li>Storage organized in 32-byte slots</li>
<li>State variables map to storage slots</li>
<li>Complex data structures use hashing for slot allocation</li>
</ul>
<h3 id="erc-20bep-20-interface"><a href="#erc-20bep-20-interface">ERC-20/BEP-20 Interface</a></h3>
<p>BEP-20 is BSC’s token standard, essentially identical to Ethereum’s ERC-20. The interface remains the same as ERC-20, just deployed on BSC instead of Ethereum. Many contracts are ported from Ethereum and have comments referring to ERC-20, Ether, etc (rather than the BSC equivalents: BEP-20, BNB)</p>
<p>The core interface that tokens must implement:</p>
<div class="sourceCode" id="cb28"><pre class="sourceCode solidity"><code class="sourceCode solidity"><span id="cb28-1"><a href="#cb28-1" aria-hidden="true" tabindex="-1"></a>interface IERC20 <span class="op">{</span></span>
<span id="cb28-2"><a href="#cb28-2" aria-hidden="true" tabindex="-1"></a>    <span class="cf">function</span> totalSupply<span class="op">()</span> <span class="kw">external</span> <span class="kw">view</span> <span class="kw">returns</span> <span class="op">(</span><span class="dt">uint256</span><span class="op">);</span></span>
<span id="cb28-3"><a href="#cb28-3" aria-hidden="true" tabindex="-1"></a>    <span class="cf">function</span> balanceOf<span class="op">(</span><span class="dt">address</span> account<span class="op">)</span> <span class="kw">external</span> <span class="kw">view</span> <span class="kw">returns</span> <span class="op">(</span><span class="dt">uint256</span><span class="op">);</span></span>
<span id="cb28-4"><a href="#cb28-4" aria-hidden="true" tabindex="-1"></a>    <span class="cf">function</span> transfer<span class="op">(</span><span class="dt">address</span> to<span class="op">,</span> <span class="dt">uint256</span> amount<span class="op">)</span> <span class="kw">external</span> <span class="kw">returns</span> <span class="op">(</span><span class="dt">bool</span><span class="op">);</span></span>
<span id="cb28-5"><a href="#cb28-5" aria-hidden="true" tabindex="-1"></a>    <span class="cf">function</span> allowance<span class="op">(</span><span class="dt">address</span> owner<span class="op">,</span> spender<span class="op">)</span> <span class="kw">external</span> <span class="kw">view</span> <span class="kw">returns</span> <span class="op">(</span><span class="dt">uint256</span><span class="op">);</span></span>
<span id="cb28-6"><a href="#cb28-6" aria-hidden="true" tabindex="-1"></a>    <span class="cf">function</span> approve<span class="op">(</span><span class="dt">address</span> spender<span class="op">,</span> <span class="dt">uint256</span> amount<span class="op">)</span> <span class="kw">external</span> <span class="kw">returns</span> <span class="op">(</span><span class="dt">bool</span><span class="op">);</span></span>
<span id="cb28-7"><a href="#cb28-7" aria-hidden="true" tabindex="-1"></a>    <span class="cf">function</span> transferFrom<span class="op">(</span><span class="dt">address</span> <span class="kw">from</span><span class="op">,</span> <span class="dt">address</span> to<span class="op">,</span> <span class="dt">uint256</span> amount<span class="op">)</span> <span class="kw">external</span> <span class="kw">returns</span> <span class="op">(</span><span class="dt">bool</span><span class="op">);</span></span>
<span id="cb28-8"><a href="#cb28-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb28-9"><a href="#cb28-9" aria-hidden="true" tabindex="-1"></a>    <span class="kw">event</span> Transfer<span class="op">(</span><span class="dt">address</span> <span class="kw">indexed</span> <span class="kw">from</span><span class="op">,</span> <span class="dt">address</span> <span class="kw">indexed</span> to<span class="op">,</span> <span class="dt">uint256</span> value<span class="op">);</span></span>
<span id="cb28-10"><a href="#cb28-10" aria-hidden="true" tabindex="-1"></a>    <span class="kw">event</span> Approval<span class="op">(</span><span class="dt">address</span> <span class="kw">indexed</span> owner<span class="op">,</span> <span class="kw">indexed</span> spender<span class="op">,</span> <span class="dt">uint256</span> value<span class="op">);</span></span>
<span id="cb28-11"><a href="#cb28-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h3 id="decentralized-exchanges"><a href="#decentralized-exchanges">Decentralized Exchanges</a></h3>
<p>A Decentralized Exchange (DEX) is a cryptocurrency exchange that operates without a central authority. It uses smart contracts to enable direct peer-to-peer cryptocurrency trading. Unlike centralized exchanges, DEXs don’t hold user funds or require identity verification. They typically use automated market maker (AMM) protocols, where liquidity is provided by users who deposit pairs of tokens into liquidity pools in exchange for trading fees.</p>
<p>“PancakeSwap” was (and might still be) the most popular DEX on BSC.</p>
<h3 id="amms"><a href="#amms">AMMs</a></h3>
<p>Automated Market Makers use a mathematical formula to price assets:</p>
<pre><code>x * y = k
where:
x = amount of token A
y = amount of token B
k = constant</code></pre>
<p>Example:</p>
<pre><code>Pool starts with:
100 ETH * 200,000 USDC = 20,000,000 (k)

To buy 10 ETH:
90 ETH * y = 20,000,000
y = 222,222 USDC

User must pay: 222,222 - 200,000 = 22,222 USDC</code></pre>
<h3 id="liquidity-pools"><a href="#liquidity-pools">Liquidity Pools</a></h3>
<p>A liquidity pool is a blob of two cryptocurrencies or tokens that are locked in a smart contract. Traders using an AMM can swap between these two currencies directly from this pool, rather than needing to find another person to trade with.</p>
<h3 id="lp-tokens"><a href="#lp-tokens">LP Tokens</a></h3>
<p>Liquidity Provider (LP) tokens are issued to users who provide liquidity to decentralized exchanges. When someone deposits a pair of tokens into a DEX’s liquidity pool, they receive LP tokens representing their share of the pool. These tokens can be redeemed later to withdraw the original assets plus any accumulated trading fees.</p>
<h3 id="impermanent-loss"><a href="#impermanent-loss">Impermanent Loss</a></h3>
<p>When token prices change after providing liquidity:</p>
<p>Starting position:</p>
<ul>
<li>1 ETH ($2000)</li>
<li>2000 USDC</li>
<li>k = 1 * 2000 = 2000</li>
</ul>
<p>If ETH price doubles ($4000):</p>
<ul>
<li>New ratio forced by arbitrage</li>
<li>x * y must still = 2000</li>
<li>New position:
<ul>
<li>~0.707 ETH ($2828)</li>
<li>~2828 USDC</li>
</ul></li>
<li>Value: $5656</li>
<li>Hold value: $6000</li>
<li>IL ≈ 5.7%</li>
</ul>
<p>Formula:</p>
<div class="sourceCode" id="cb31"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb31-1"><a href="#cb31-1" aria-hidden="true" tabindex="-1"></a>IL <span class="op">=</span> <span class="dv">2</span> <span class="op">*</span> <span class="fu">sqrt</span>(P) <span class="op">/</span> (<span class="dv">1</span> <span class="op">+</span> P) <span class="op">-</span> <span class="dv">1</span></span>
<span id="cb31-2"><a href="#cb31-2" aria-hidden="true" tabindex="-1"></a>where P <span class="op">=</span> price_new <span class="op">/</span> price_old</span></code></pre></div>
<p>This mechanic is crucial for understanding scams because:</p>
<ol type="1">
<li><p>Price changes affect pool composition</p></li>
<li><p>Preventing sells concentrates value in the “good” token</p></li>
<li><p>Removing liquidity captures this value</p></li>
<li><p>Buyers are left with worthless tokens they can’t sell</p></li>
</ol>]]></description>
    <pubDate>Fri, 20 Dec 2024 00:00:00 UT</pubDate>
    <guid>https://nyuu.page/posts/2024-12-20-solidity/</guid>
    <dc:creator>nyuu</dc:creator>
</item>
<item>
    <title>Romhack Research</title>
    <link>https://nyuu.page/posts/2024-10-15-romhack/</link>
    <description><![CDATA[<p>This post is about making an English translation patch for <em>Yu-Gi-Oh! Duel Monsters 4</em>, a Game Boy Color game from 2000 that—at the time I started—had no official English localization.</p>
<figure>
<img src="/images/romhack/DuelMonsters4.jpg" width="720" height="303" alt="Box art of Yu-Gi-Oh! Duel Monsters 4: Battle of Great Duelist, showing the three version covers (Yugi, Kaiba, Joey)" />
<figcaption>Yu-Gi-Oh! Duel Monsters 4: Battle of Great Duelist</figcaption>
</figure>
<div class="admonition" style="--adm-bg: #66512c; --adm-border: #ffcc00" role="note">
<span class="admonition-title"><img src="/images/icons/blobnervous.webp" class="admonition-icon" alt="" width="128" height="128" />Warning</span>
<div class="admonition-content">
<p>This project is ongoing. More posts to come.</p>
</div>
</div>
<h3 id="motivation"><a href="#motivation">Motivation</a></h3>
<p>As a kid, I had this game: <a href="https://yugipedia.com/wiki/Yu-Gi-Oh!_Dark_Duel_Stories">“Yu-Gi-Oh! Dark Duel Stories”</a></p>
<figure>
<img src="/images/romhack/DM3E-boxart.webp" width="640" height="642" alt="Box art of Yu-Gi-Oh! Dark Duel Stories for Gameboy Color" />
<figcaption>It isn’t very good. I played the crap out of it. It was supposed to come with three tie-in/promo cards, but mine didn’t have them, possibly due to retail theft. Alas.</figcaption>
</figure>
<p>It’s a card battler <em>loosely</em> based on the Yu-Gi-Oh card game. It’s the third of a four-game series and the only one in that series released in English. I wanted to try the fourth game: <a href="https://yugipedia.com/wiki/Yu-Gi-Oh!_Duel_Monsters_4:_Battle_of_Great_Duelist">Yu-Gi-Oh! Duel Monsters 4: Battle of Great Duelist</a></p>
<figure>
<img src="/images/romhack/DM4K-boxart.webp" width="584" height="680" alt="Box art of Yu-Gi-Oh! Duel Monsters 4: Battle of Great Duelist, Kaiba Version" />
<figcaption>It might be better!</figcaption>
</figure>
<p>I wanted to do so in English. This post is about how I made that possible.</p>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/note.webp" class="admonition-icon" alt="" width="128" height="128" />Note</span>
<div class="admonition-content">
<p>Alyssa (my fiancé and proofreader) told me it was a good idea to explain <em>everything</em>. Longwinded explanations will go in asides like this one.</p>
</div>
</div>
<p>That first part, <span class="greentext">try the game</span>, is easy enough: go find the rom.</p>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/blobwizard.webp" class="admonition-icon" alt="" width="128" height="128" />Info</span>
<div class="admonition-content">
<p>In this context a ROM (read-only memory) is a digital copy of a video game, extracted from the cartridge (or whatever media it came on, e.g. a disc). They are used to play the game on modern devices using console emulators, which are programs that simulate the console’s hardware &amp; so allow playing that console’s games.</p>
</div>
</div>
<p>The second part, <span class="greentext">do so in English</span>, proved harder. I looked the game up on <a href="https://romhacking.net">romhacking.net</a>.</p>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/blobwizard.webp" class="admonition-icon" alt="" width="128" height="128" />Info</span>
<div class="admonition-content">
<p>A romhack is a modified version of a game[’s ROM]. This might be to add levels, change graphics, change the script, etc. Some fans of games make these.</p>
<p>These modified games usually aren’t distributed <em>directly</em>. This is due to the ROMs being copyrighted and publishers being litigous (or at least <em>DMCA takedown request</em>-happy). Instead, players are given a <em>patch</em>. A patch is a file that contains or describes the <em>changes</em> that need to be made to the ROM, to turn it into the romhack. Finding the rom and combining it with the patch is left as an exercise for the player.</p>
<p><a href="https://romhacking.net">romhacking.net</a> is one of the larger general-purpose venues for sharing [patches for] romhacks.</p>
</div>
</div>
<p>I found <a href="https://www.romhacking.net/translations/558/">one patch</a> for the game. And it’s a translation! Let’s look at its specs:</p>
<blockquote>
<p>Status: Unfinished</p>
<p>Release Date: <strong>01 May 2002</strong></p>
</blockquote>
<p>That is not what we like to see! We wanted to see if there was a translation, and there is, but it’s unfinished, and if it has been over twenty years then the translator probably isn’t going to finish it.</p>
<p>Still, the provided example screenshots look promising enough.</p>
<figure>
<img src="/images/romhack/DM4J-E1.webp" class="gbc" width="160" height="144" alt="Judah translation of Meteor B. Dragon: Meteor B. Dragon 8★ Dragon/Pyro Hot meteor body evaporates enemies ⚔⚔3500/🛡🛡2000" />
<figcaption>Meteor B. Dragon</figcaption>
</figure>
<figure>
<img src="/images/romhack/DM4J-E2.webp" class="gbc" width="160" height="144" alt="Judah translation of Pot of Greed: Pot of Greed Magic Draw up to 2 cards if hand allows it" />
<figcaption>Pot of Greed</figcaption>
</figure>
<p>This is all in English and is understandable, if a bit stiff.</p>
<p>So, we grab the patch, patch the rom, yada yada, and then run the patched game. We have growing concerns:</p>
<figure>
<img src="/images/romhack/DM4J-Title.webp" class="gbc" width="160" height="144" alt="Title screen for the game with Judah&#39;s patch applied, identical to the base game. There is a splash screen and options to continue or to new game" />
<figcaption>Title Screen</figcaption>
</figure>
<p>This is in Japanese. It would be <em>nice</em> if this was translated, but, most likely editing this is done by different means than editing the script and figuring out how to do it would have been a huge pain. And it would be for no real benefit since if you’ve gotten this far, you already know the game’s title, and can figure out “push some buttons; one of them will let me proceed”.</p>
<figure>
<img src="/images/romhack/DM4J-Menu.webp" class="gbc" width="160" height="144" alt="Main menu for the game with Judah&#39;s patch applied, identical to the base game" />
<figcaption>Main Menu</figcaption>
</figure>
<p>This is in Japanese. It would be <em>more nice</em> if this was translated. It likely wasn’t for the same reason the title wasn’t. There are a mere five choices, so, the player can figure out which is which and just remember. So this too is fine.</p>
<p><em>Incidentally, most of these options are just transliterated English words! Learning the kana and sounding stuff out is a much lower bar than outright learning Japanese. So if you burn to read these you could in short order.</em></p>
<figure>
<img src="/images/romhack/DM4J-Mako.webp" class="gbc" width="160" height="144" alt="Judah garbled dialogue with Mako Tsunami, reading: ワ・Z CfYデュ. n&amp;ト :・&quot;!nxCP L̈v!📄📄" />
<figcaption>Ẉ̶̈́h̶̗͘ŏ̶͈ä̶́ͅ</figcaption>
</figure>
<p>I had excuses for the other two screens not needing to be translated but this <em>garbled</em> text is absolutely getting in the way of my enjoyment. This translation has the in-battle text done, but, that’s not quite enough for a cozy experience since menuing is unavoidable.</p>
<p>I wanted to play the game and to do so in English. It looks like doing so will require translating the game myself, so I decide to do just that. It’ll be fun!</p>
<h2 id="lets-make-a-romhack"><a href="#lets-make-a-romhack">Let’s make a romhack!</a></h2>
<p>I want to open up the game, pull out all the text, translate, and put it back. If possible, I also want to figure out how “non-text” assets are stored, and if it’s practical, edit these into being translated as well.</p>
<h3 id="lets-inspect-the-rom-in-our-hex-editor"><a href="#lets-inspect-the-rom-in-our-hex-editor">Let’s inspect the rom in our hex editor</a></h3>
<p>First, let’s just dive right in with our <a href="https://en.wikipedia.org/wiki/Hex_editor">hex editor</a> and see if we can spot anything.</p>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/blobwizard.webp" class="admonition-icon" alt="" width="128" height="128" />Info</span>
<div class="admonition-content">
<p>A hex editor is a tool to view and modify the “raw data” of a file. That is, the 1s and 0s. To make this a bit easier to look at and reason about, this tool represents these 1s and 0s in base 16 (hexadecimal, “hex”).</p>
<p>It is used to make low-level changes to files, such as our ROM.</p>
</div>
</div>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/blobwizard.webp" class="admonition-icon" alt="" width="128" height="128" />Info</span>
<div class="admonition-content">
<p>In hex, the “digits” are as follows: 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F. Each digit represents four binary bits. for example, the hex digit “6” corresponds to the binary sequence “0110”. This shorthand makes it simpler to work with the binary data by condensing it into a more readable form.</p>
<p>To make it <em>unambigous</em> that you are talking about a hex value, you can prepend a <code>0x</code>. This distinction can matter! <code>10</code> = <code>10</code>, whereas <code>0x10</code> = <code>16</code>.</p>
</div>
</div>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/blobwizard.webp" class="admonition-icon" alt="" width="128" height="128" />Info</span>
<div class="admonition-content">
<p>One way to think about files is that there are two kinds of files: “binary” and “text”.</p>
<p>“Text” is anything where there is a (usually universal) standard for how to interpret the 1s and 0s as characters. Examples of standards include: ASCII, UTF-8. Examples of common types of files that are text: <code>.txt</code>, <code>.html</code>. Text data follows a predictable <em>encoding scheme</em> that <em>maps</em> specific, publicly known binary patterns to characters. For example, in ASCII-encoded text, the character <code>q</code> is mapped to decimal <code>113</code>, which in turn corresponds to binary <code>01110001</code>.</p>
<p>“Binary” files are basically anything that is not intended to be human-readable. Examples include images (e.g. <code>.bmp</code>), executables, and ROMs.</p>
<p>Binary files can have <em>subregions</em> that are “text”. Sometimes that text is encoded in a common way, such as ASCII, in which case it can be quite easy to spot. Sometimes it is encoded in a <em>weird, bespoke</em> way, in which case tracking it down can be tough. This will matter later.</p>
</div>
</div>
<p>I pop the game open in a hex editor and quickly find it <em>nigh-totally incomprehensible</em>.</p>
<figure>
<img src="/images/romhack/imhex-rawbytes.webp" width="720" height="201" alt="Hex editor view of the start of the file" />
<figcaption>The first few hundred bytes of the unpatched game</figcaption>
</figure>
<p>I see that somewhere around byte 130 there is some text, stored in ASCII, such that my editor can detect and decode it. It’s <code>YUGIOUDM4K</code>, which is probably the internal name of the game. It looks like it’s an abbreviation of “Yugioh Duel Monsters 4: Kaiba”. That’s neat.</p>
<p>But, when I scroll down through the rest of the rom, I don’t see more text. It’s either hidden or not there at all. I go googlin’ to try to find help.</p>
<p><span class="greentext"><span class="emoji"><img src="/images/emoji/1f50e.svg" class="emoji-img" draggable="false" alt="🔎" /><span class="emoji-text" aria-hidden="true">🔎</span></span> how to romhack ↵</span></p>
<p>Some games have quite active fan/rom-hacking communities. I had hoped this would mean there is a ton of deeply detailed general-purpose guides out there that would handhold me through a lot of it. Such guides might exist, but I didn’t find them. What I did find was this <em>extremely useful</em> post: <a href="https://datacrystal.tcrf.net/wiki/Text_Table">Data Crystal, on Text Tables</a>.</p>
<blockquote>
<p>A Text Table or <code>.TBL</code> file describes to a hex editor how to convert a ROM’s text format into readable text.</p>
</blockquote>
<p>It gives this example:</p>
<blockquote>
<p>Simple case</p>
<p>This is a purely made up example and don’t came from any game that I know of.</p>
<p>Using this TBL:</p>
<pre class="tbl"><code>00=
01=A
02=B
03=C
04=D</code></pre>
<p>This sequence <code>0x02</code>, <code>0x01</code>, <code>0x04</code>, <code>0x00</code>, <code>0x03</code>, <code>0x01</code>, <code>0x02</code>
Is decoded as <code>BAD CAB</code></p>
</blockquote>
<p>I learn that:</p>
<p><span class="emoji"><img src="/images/emoji/2705.svg" class="emoji-img" draggable="false" alt="✅" /><span class="emoji-text" aria-hidden="true">✅</span></span> I am now <em>sure</em> that what we want to do is to edit the ROM directly, byte by byte, rather than e.g. decompiling it</p>
<p><span class="emoji"><img src="/images/emoji/2705.svg" class="emoji-img" draggable="false" alt="✅" /><span class="emoji-text" aria-hidden="true">✅</span></span> The correct way to do this is to examine and edit it in a hex editor, as we are doing</p>
<p><span class="emoji"><img src="/images/emoji/2705.svg" class="emoji-img" draggable="false" alt="✅" /><span class="emoji-text" aria-hidden="true">✅</span></span> The first step of doing <em>that</em> is to figure out how text is represented</p>
<p><span class="emoji"><img src="/images/emoji/2705.svg" class="emoji-img" draggable="false" alt="✅" /><span class="emoji-text" aria-hidden="true">✅</span></span> Doing that is one and the same as building a <code>.tbl</code> file for the game.</p>
<p><span class="emoji"><img src="/images/emoji/2705.svg" class="emoji-img" draggable="false" alt="✅" /><span class="emoji-text" aria-hidden="true">✅</span></span> There is a solid chance that the developers did little or no obfuscation of how the text is encoded. The answer is <em>probably</em> about as simple as the example <code>.tbl</code> file above.</p>
<p><span class="emoji"><img src="/images/emoji/2705.svg" class="emoji-img" draggable="false" alt="✅" /><span class="emoji-text" aria-hidden="true">✅</span></span> I’m gonna want a hex editor with good support for <code>.tbl</code> files so I can apply them to the rom and see what I can find. I’m told <a href="https://github.com/WerWolv/ImHex">ImHex</a> is good, so, I install that.</p>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/note.webp" class="admonition-icon" alt="" width="128" height="128" />Note</span>
<div class="admonition-content">
<p>You may notice that the first hex editor screenshot, ostensibly from before I have imhex, was clearly taken in imhex! That is because I started writing this liveblog midway through the project and I don’t feel like reconstructing my early environment to a t. seeing as how doing that isn’t fun and doesn’t benefit anyone.</p>
</div>
</div>
<p>At this point I have a <em>guess</em> as to why Mako’s textbox was all garbled. Which we’ll address later. I make a few weakass attempts at figuring out anything at all about the table using “guessing”, “probability analysis”, etc. I am unsuccessful. So, I go back to datacrystal for any further infos. What we find is <em>quite a lot</em> of info about each game in the series.</p>
<p>There are four games in the series. Some of them are helpful in figuring out what to do. So I can discuss them without ambiguity, I’ll name them based on their release order: DM1, DM2, DM3, DM4.</p>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/blobwizard.webp" class="admonition-icon" alt="" width="128" height="128" />Info</span>
<div class="admonition-content">
<p>DM4 is actually <em>three games</em>. Much like how, say, generation 1 pokemon has Red, Blue, and Yellow: there are three DM4s: Kaiba, Yugi, Joey. For almost all purposes this doesn’t matter and we’ll just focus on the Kaiba variant. Set the other two aside until the very end.</p>
</div>
</div>
<ul>
<li>Game Boy
<ul>
<li><a href="https://datacrystal.tcrf.net/wiki/Yu-Gi-Oh!_Duel_Monsters">Yu-Gi-Oh! Duel Monsters</a> → DM1</li>
</ul></li>
<li>Game Boy Color
<ul>
<li><a href="https://datacrystal.tcrf.net/wiki/Yu-Gi-Oh!_Duel_Monsters_II:_Dark_Duel_Stories">Yu-Gi-Oh! Duel Monsters II: Dark Duel Stories</a> → DM2</li>
<li><a href="https://datacrystal.tcrf.net/wiki/Yu-Gi-Oh!_Dark_Duel_Stories">Yu-Gi-Oh! “Dark Duel Stories”</a> → DM3</li>
<li><a href="https://datacrystal.tcrf.net/wiki/Yu-Gi-Oh!_Duel_Monsters_4:_Kaiba_Deck">Yu-Gi-Oh! Duel Monsters 4: Kaiba Deck</a> → DM4</li>
</ul></li>
</ul>
<p>DM1, DM2, and DM4 were only released in Japanese. DM2’s title is “Yu-Gi-Oh! Duel Monsters II: Dark Duel Stories”.</p>
<p>DM3 was released in Japanese and in English. In Japanese, DM3’s title is “Yu-Gi-Oh! Duel Monsters III: Tri-Holy God Advent”. In English, its title is… “Yu-Gi-Oh! Dark Duel Stories”.</p>
<p>I’ll refer to the English translation of DM3 as DM3-English, and the Japanese translation as DM3-Japanese.</p>
<p>I’ll call the unmodified, Japanese DM4 game “DM4”. DM4 has an incomplete fan translation. The translator/hacker goes by Chris Judah. I’ll refer to his game as DM4-Judah. Similarly if I need to refer to my game i’ll call it DM4-nyuu.</p>
<h3 id="finding-dm4s-text-table"><a href="#finding-dm4s-text-table">Finding DM4’s text table</a></h3>
<p><a href="https://github.com/WerWolv/ImHex">imhex</a> allows loading table files alongside ROMs, so you can quickly see what the stuff in the ROM decodes to, given that table.</p>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/note.webp" class="admonition-icon" alt="" width="128" height="128" />Note</span>
<div class="admonition-content">
<p>I am going to use “text table” and “.tbl file” interchangably. Strictly speaking: the text table is the map of bytes to characters, and the .tbl file is a file a text table is stored in. But this distinction is pedantic and should be ignored.</p>
</div>
</div>
<p>For a given ROM, there often is a “correct” table that, when applied, allows you to read text stored in the ROM. Our goal is to figure out what it is, which could involve trial and error via trying out tables we make up and seeing if we get anything text-like from them.
Here is a demonstration of the sort of thing you might see while doing this:</p>
<figure>
<img src="/images/romhack/imhex-incorrect-text-table.webp" width="964" height="377" alt="ImHex view with wrong text table loaded" />
<figcaption aria-hidden="true">ImHex view with wrong text table loaded</figcaption>
</figure>
<p>The bytes are the contents of the rom. The “ASCII” column is builtin. The “example-table-file” column is a demonstration of what you get when you feed imhex a <code>.tbl</code> file: an at-a-glance view of what that table decodes the bytes into. In this example it’s the <em>wrong</em> table for this ROM, so we get gibberish.”</p>
<p>DM1 already has a publicly known <a href="https://datacrystal.tcrf.net/wiki/Yu-Gi-Oh!_Duel_Monsters/TBL">text table</a>. Here’s an excerpt:</p>
<blockquote>
<div class="sourceCode" id="cb2"><pre class="sourceCode markdown"><code class="sourceCode markdown"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a>00=</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>01=０</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>02=１</span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="co">[</span><span class="ot">...excerpted...</span><span class="co">]</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>0B=あ</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>0C=い</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a><span class="co">[</span><span class="ot">...excerpted...</span><span class="co">]</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>AE=ペ</span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>AF=ポ</span></code></pre></div>
</blockquote>
<p>This looks pretty “generic”. Like, if the team I was working on handled their text encoding in this way in one game, I would not be all that surprised if they also did it in other, similar games. And these games seem superficially pretty similar to each other, and it is quick and free to try out tables. So we try this one.</p>
<p>Here is our status so far:</p>
<p><span class="emoji"><img src="/images/emoji/2705.svg" class="emoji-img" draggable="false" alt="✅" /><span class="emoji-text" aria-hidden="true">✅</span></span> We have a table</p>
<p><span class="emoji"><img src="/images/emoji/2753.svg" class="emoji-img" draggable="false" alt="❓" /><span class="emoji-text" aria-hidden="true">❓</span></span>We don’t know where to look to see if it likely means anything</p>
<p>What we want is to find a location that contains text. Ideally it contains text that uses a large percentage of characters present in the script so we can solve as much of it as possible here.</p>
<p>The ROM is 4MiB, which is pretty small in most context, but in <em>our</em> context it is kinda large since that means there are 4,194,304 bytes. We’d rather not have to scroll through the entire thing.</p>
<p><em>Fortunately</em> we do not have to do that. The data miners over at datacrystal (we aren’t done with them yet!) have already figured out where a lot of stuff is stored. Their findings on “where in the ROM are various things” is a “ROM map”.</p>
<p>I can only imagine that constructing the map must have been arduous. Thank you, people involved <span class="emoji"><img src="/images/emoji/1f64f.svg" class="emoji-img" draggable="false" alt="🙏" /><span class="emoji-text" aria-hidden="true">🙏</span></span></p>
<p>We can consult their rom map, which says addresses <a href="https://datacrystal.tcrf.net/wiki/Yu-Gi-Oh!_Duel_Monsters_4:_Kaiba_Deck/ROM_map#Cards_texts"><code>0x3F8002-0x3FFE87</code></a> store “Cards Text”. That is, they’re where the flavor and/or rules text on the cards, as is displayed during gameplay, is stored.</p>
<figure>
<img src="/images/romhack/imhex-example-encoded-text.webp" width="720" height="256" alt="ImHex at 0x3F8002" />
<figcaption>This is the start of the section of the ROM we care about</figcaption>
</figure>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/blobwizard.webp" class="admonition-icon" alt="" width="128" height="128" />Info</span>
<div class="admonition-content">
<p>This infobox is trivia and can be skipped.</p>
<p>The <em>internal</em> representation of the data could be in an order completely unrelated to the order you’d see it in when playing the game. Pokemon assigns numbers to all the creatures. Bulbasaur is #1, Pikachu is #25, etc. <em>Internally</em> however: things are a bit different. <a href="https://tcrf.net/Pok%C3%A9mon_Red_and_Blue/Internal_Index_Number">(In generation 1), Rhydon comes first</a>. They’re listed in the order in which they were programmed into the game, which is unrelated to their player-facing “dex number”. There’s also a bunch of “blank spaces” that probably correspond to Pokemon that got cut during development. If we are truly fortunate, maybe we’ll discover something similar here. A humanizing touch in the data, a hint that it’s all the handiwork of real people.</p>
<p>Anyway: <a href="https://yugipedia.com/wiki/List_of_Yu-Gi-Oh!_Duel_Monsters_4:_Battle_of_Great_Duelist_cards">externally, DM4 cards are ordered like this</a>. First “Blue-Eyes White Dragon”, then “Holy Elf”, and so on. It’d be pretty plausible for them to be stored in that order internally too. We’ll find that out in a moment.</p>
</div>
</div>
<p>What we expect we’ll find, when decoded, is a big block of text containing all the card texts one after the other. <em>Probably</em> either each card text will be the exact same length (that is, any unused space is actually represented by spaces), or, it’ll be one big run-on sentence and the demarcations are defined in a pointer table somewhere else.</p>
<p><em>Anyway</em>, here is what I see after loading the DM1 table at the start of the card text area:</p>
<figure>
<img src="/images/romhack/promising-findings.webp" width="985" height="351" alt="ImHex view of decoded Japanese card names" />
<figcaption>𝔇𝔞𝔪𝔫.</figcaption>
</figure>
<p>That is definitely the card text, which is great. It looks like the internal ordering is the same as the external ordering, which is convenient since it’s one less thing to keep track of when yoinking data out or putting it back in at the end.</p>
<p>The first card is <a href="https://yugipedia.com/wiki/B.eye_White_Dragon_(DM4)"><span lang="ja">ブルーアイズ・ホワイトドラゴン</span></a>. Its flavor text is supposed to be <span lang="ja">たかいこうげきりょくをほこるでんせつのドラゴン</span>, which is what we see in the decoding we get from our <code>.tbl</code>.</p>
<figure>
<img src="/images/romhack/promising-findings-smol.webp" width="280" height="126" alt="ImHex view of decoded flavor text" />
<figcaption>It’s the text at the very start of the decoded segment</figcaption>
</figure>
<p>So the table <em>might</em> be 100% correct. It’s definitely correct enough to get the kana right, which is enough to let us get started on making sense of and extracting this stuff.</p>
<h3 id="lets-learn-about-how-the-card-text-is-stored"><a href="#lets-learn-about-how-the-card-text-is-stored">Let’s learn about how the card text is stored</a></h3>
<p>The list of card texts has a bunch of empty spaces between the entries.</p>
<p>The first text excerpt is represented like this:</p>
<blockquote>
<p><span class="game"><span lang="ja">たかいこうげきりょくをほこる　　　　でんせつのドラゴン　　　　　　　　　</span></span></p>
</blockquote>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/note.webp" class="admonition-icon" alt="" width="128" height="128" />Note</span>
<div class="admonition-content">
<p>For visual clarity, we’re decorating strings from the game with an underline when the whitespace is significant. From this point on we’ll also, where applicable, insert a newline.</p>
</div>
</div>
<p>And <a href="https://yugipedia.com/wiki/B.eye_White_Dragon_(DM4)">here</a> is what is seen in-game:</p>
<figure>
<img src="/images/romhack/DM4K-BEWD.webp" class="gbc" width="160" height="144" alt="DM4K&#39;s B.eye White Dragon: ブルーアイズ・ホワイトドラゴン 9★ ドラゴン/しろまぞく ⚔⚔3000/🛡🛡2500 たかいこうげきりょくをほこる でんせつのドラゴン" />
<figcaption><span class="emoji"><img src="/images/emoji/2705.svg" class="emoji-img" draggable="false" alt="✅" /><span class="emoji-text" aria-hidden="true">✅</span></span> It’s a match</figcaption>
</figure>
<p>This singlehandedly probably tells us everything we need to know about how this is structured. In-game, card text looks like it is allowed to be up to 36 characters long, and has a linebreak in the exact middle. It looks like it’s probably stored in these 36 byte segments, spaces and all. We’ll check a few more to be sure though.</p>
<p>Here’s the second</p>
<blockquote>
<p><span class="game"><span lang="ja">せいなるいのりで　みかたのブルーアイ</span></span></p>
<p><span class="game"><span lang="ja">ズ・ホワイトドラゴンをパワーアップ　</span></span></p>
</blockquote>
<p>This fits the space constraints. It also aligns with <a href="https://yugipedia.com/wiki/Mystical_Elf_(DM4)">what we see in-game</a>:</p>
<figure>
<img src="/images/romhack/DM4K-Mystical_Elf.webp" class="gbc" width="160" height="144" alt="DM4K&#39;s Mystical Elf: ホーリー・エルフ 6★ まほうつかい ⚔⚔800/🛡🛡2000 せいなるいのりで みかたのブルーアイズ・ホワイトドラゴンをパワーアップ" />
<figcaption><span class="emoji"><img src="/images/emoji/2705.svg" class="emoji-img" draggable="false" alt="✅" /><span class="emoji-text" aria-hidden="true">✅</span></span> It’s a match</figcaption>
</figure>
<p>Let’s check one more to be sure. Skipping ahead a bit, we find this rather decisive example:</p>
<blockquote>
<p><span class="game"><span lang="ja">なんぼんももっているハサミを　　　　</span></span></p>
<p><span class="game"><span lang="ja">きようにうごかし　あいてをきりきざむ</span></span></p>
</blockquote>
<p>Compare with what we <a href="https://yugipedia.com/wiki/Brave_Scizzar_(DM4)">see in-game</a>:</p>
<figure>
<img src="/images/romhack/DM4K-Brave_Scizzar.webp" class="gbc" width="160" height="144" alt="DM4K&#39;s Brave Scizzar: ブレイブ・シザー 4★ きかい/あくままぞく ⚔⚔1300/🛡🛡1000 なんぼんももっているハサミを きようにうごかし あいてをきりきざむ" />
<figcaption><span class="emoji"><img src="/images/emoji/2705.svg" class="emoji-img" draggable="false" alt="✅" /><span class="emoji-text" aria-hidden="true">✅</span></span> It’s a match</figcaption>
</figure>
<p>Now that we know how it’s stored, we know how to put it back when we’re done changing it. So, now we copy the stuff from <code>0x3F8002-0x3FFE87</code> as decoded by our table, for later translation.</p>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/note.webp" class="admonition-icon" alt="" width="128" height="128" />Note</span>
<div class="admonition-content">
<p>ImHex has a “bookmark” feature that lets you indicate ranges of bytes and what they’re for. We’ll bookmark this and any other relevant locations as we discover them. I don’t want to have to describe it each time I bookmark something, so this is the last i’ll say about it. You should be bookmarking extensively if you’re trying this yourself.</p>
</div>
</div>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/blobwizard.webp" class="admonition-icon" alt="" width="128" height="128" />Info</span>
<div class="admonition-content">
<p>What we’re trying to do at the moment is get info out so we can work on translating it. We’re also trying to build a mental model of how it is structured. Knowing how it is packed (namely that every 36th character is the start of another card) is useful for knowing how we can go about processing this blob of info later. Most of it will end up populating a gigantic .csv file.</p>
</div>
</div>
<p>I try editing one of these card texts and the change is reflected in-game. Check it:</p>
<figure>
<img src="/images/romhack/1337.webp" class="gbc" width="160" height="144" alt="DM4K&#39;s Blue Eyes White Dragon with flavor text edited to read: １３３７！！！？　　　　　　　　　　おはよ インターネット" />
<figcaption>𝔑𝔢𝔞𝔱.</figcaption>
</figure>
<p>We didn’t use any clever tooling here; we just manually looked at the table to find which byte represented each symbol we wanted. Then went to the part of the rom that defines what we want to change. In our example, we picked <span lang="ja">ブルーアイズ・ホワイトドラゴン</span>’s flavor text. Then we edit those bytes so they now spell out whatever we wanted to say.</p>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/note.webp" class="admonition-icon" alt="" width="128" height="128" />Note</span>
<div class="admonition-content">
<p>html has this really cool element: <code>&lt;ruby&gt;</code>. Per MDN:</p>
<blockquote>
<p>The <code>&lt;ruby&gt;</code> HTML element represents small annotations that are rendered above, below, or next to base text, usually used for showing the pronunciation of East Asian characters. It can also be used for annotating other kinds of text, but this usage is less common.</p>
</blockquote>
<p>I’ll be using this as appropriate to make it easier to follow along. And sometimes when it is unnecessary but fun.</p>
</div>
</div>
<p>here is what it now says:</p>
<blockquote>
<p><span class="game"><span lang="ja">１３３７！！！？　　　　　　　　　　</span></span></p>
<p><span class="game"><span lang="ja"><ruby>お<rt>O</rt></ruby><ruby>は<rt>ha</rt></ruby><ruby>よ<rt>yō</rt></ruby>　<ruby>イン<rt>in</rt></ruby><ruby>ター<rt>tā</rt></ruby><ruby>ネッ<rt>net</rt></ruby><ruby>ト<rt>to</rt></ruby>　　　　　　　</span></span></p>
</blockquote>
<p>The second line means “hello internet”.</p>
<h3 id="lets-much-more-quickly-learn-about-how-card-names-are-stored"><a href="#lets-much-more-quickly-learn-about-how-card-names-are-stored">Let’s <em>much more quickly</em> learn about how card names are stored</a></h3>
<p>The <a href="https://datacrystal.tcrf.net/wiki/Yu-Gi-Oh!_Duel_Monsters_4:_Kaiba_Deck/ROM_map#Cards_names">aforementioned rom map tells us card names are stored in <code>0x60014-0x63F4F</code></a>. This is wrong, actually!</p>
<figure>
<img src="/images/romhack/imhex-DM4K-nothing.webp" width="899" height="167" alt="ImHex of DM4K at 0x60014" />
<figcaption>There is nothing at 0x60014 or anything similar</figcaption>
</figure>
<p>I was able to find it, though. It’s actually stored in <code>0x38870-0x3a66d</code>:</p>
<figure>
<img src="/images/romhack/imhex-cardnames.webp" width="986" height="178" alt="ImHex of DM4K at 0x38870" />
<figcaption>That’s more like it</figcaption>
</figure>
<p>Now, let’s figure out how it’s structured. We know (because of observation, testing, etc) that card names may be up to 18 characters long.</p>
<p>Looking at the first couple of bytes, we have:</p>
<blockquote>
<p><a href="https://yugipedia.com/wiki/B.eye_White_Dragon_(DM4)"><span lang="ja"><ruby>ブルー<rt>Blue</rt></ruby><ruby>アイズ<rt>Eyes</rt></ruby>・<ruby>ホワイト<rt>White</rt></ruby><ruby>ドラゴン<rt>Dragon</rt></ruby></span></a><a href="https://yugipedia.com/wiki/Mystical_Elf_(DM4)"><span lang="ja"><ruby>ホーりー<rt>Holy</rt></ruby>・<ruby>エルフ<rt>Elf</rt></ruby></span></a><a href="https://yugipedia.com/wiki/Hitotsu-me_Giant_(DM4)"><span lang="ja"><ruby>サイクロプス<rt>Cyclops</rt></ruby></span></a><a href="https://yugipedia.com/wiki/Baby_Dragon_(DM4)"><span lang="ja"><ruby>ベビー<rt>Baby</rt></ruby>・<ruby>ドラゴン<rt>Dragon</rt></ruby></span></a><a href="https://yugipedia.com/wiki/Ryu-kishin_(DM4)"><span lang="ja"><ruby>ガーゴイル<rt>Gargoyle</rt></ruby></span></a></p>
</blockquote>
<p>The good news is this is legible. The bad news is it appears to be unstructured. We have a big chunk of memory where all the card names are stored one after another without any separators.</p>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/blobwizard.webp" class="admonition-icon" alt="" width="128" height="128" />Info</span>
<div class="admonition-content">
<p>It’s pretty likely that, internally, the way the game pulls up card text is, it goes “we want card id #3. card texts are always 36 bytes long. card id #1’s text begins at [wherever]. so, to get to id 3, we just skip n 36-byte chunks forward, read the next 36 bytes, then stop”. This sort of approach does not work if there is no consistent pattern to work off of. As such, the game must be figuring out where to look for a specific card’s name, from somewhere else.</p>
</div>
</div>
<p>Before this chunk, we have a list of <a href="https://en.wikipedia.org/wiki/Pointer_(computer_programming)">pointers</a> that tell us where each card name starts relative to a base address. This region is: <code>0x38152-0x3885d.</code></p>
<figure>
<img src="/images/romhack/imhex-og-pointer-table.webp" width="983" height="235" alt="ImHex of DM4K at 0x38152" />
<figcaption>Cursor is on 0x38152</figcaption>
</figure>
<p>The pointers are stored in a compact form, using 2 bytes each, and they represent how far away each card name is from the base address.</p>
<p>We realized this because when we looked at the data, the numbers didn’t make sense as absolute positions, but when we subtracted a certain base number, they lined up perfectly with where the card names actually start.</p>
<p>As it is, if we want to change the card names we’ll need to also be allowed to change the <em>length</em> of a card name. If we change the length of any card name, the starting positions of all the following names shift. To fix this, we need to recalculate the pointers.</p>
<p>Doing so involves figuring out how the game is turning the two-byte sequences into the memory locations, so we can, in conjunction with our list of new names, do what the game is doing, in reverse, to get the new pointers.</p>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/blobwizard.webp" class="admonition-icon" alt="" width="128" height="128" />Info</span>
<div class="admonition-content">
<p>The <em>internal representation</em> of your data is in binary. Which we usually think about in terms of bytes rather than individual 1s or 0s. <em>Endianness</em> is how we <em>order</em> the bytes. You can order them “most significant byte, first”, aka “big-endian”. Or “least significant byte, first”, aka “little-endian”.</p>
<figure>
<img src="/images/romhack/endianness_infographic.webp" width="636" height="297" alt="Visual representation of the endianness explanation" />
<figcaption>Here’s a quick illustration</figcaption>
</figure>
<p>I am told that each approach has advantages but I don’t know enough about this to ramble authoritatively on it and it is outside the scope of the stuff I want to talk about.</p>
</div>
</div>
<p>To find the actual memory address of each card name, we use the following formula: Actual Address=Base Address+(Pointer Value−Base Offset)</p>
<ol type="1">
<li><p>Read pointer value</p>
<ol type="1">
<li>Extract a pair of bytes</li>
<li>Interpret as a little-endian integer</li>
</ol></li>
<li><p>Subtract the base offset (<code>0x4870</code>)</p></li>
<li><p>Add the base address (<code>0x38870</code>)</p></li>
</ol>
<p><em>However</em> there is a complication. Here’s our data: <code>5E4870487F4887488D489548</code>. To skip ahead a little: if we pull out the first pair of bytes <code>5E48</code> and apply our steps to it, we do <em>not</em> get a memory location corresponding to a card at all. Instead what we get is a pointer to the endpoint of the pointer table: <code>0x3885E</code>!</p>
<figure>
<img src="/images/romhack/imhex-end-of-pointer-table.webp" width="978" height="253" alt="ImHex of DM4K at 0x3885E" />
<figcaption>0x3885E is the red one</figcaption>
</figure>
<p>Everything before <code>0x3885E</code> is the pointers. Then there’s some padding, then everything past that is the card names. As such we can be pretty sure that this is a data structure. Such as a way of indicating when the list of pointers <em>ends</em>. Regardless of the why: we’re going to set aside <code>5E48</code> for now since it is a different kind of thing. Here’s our <em>real</em> data: <code>70487F4887488D489548</code>.</p>
<h4 id="applying-the-process"><a href="#applying-the-process">Applying the process</a></h4>
<h5 id="extract-pairs-of-bytes"><a href="#extract-pairs-of-bytes">1. extract pairs of bytes</a></h5>
<p><code>70 48</code>, <code>7F 48</code>, <code>87 48</code>, <code>8D 48</code>, <code>95 48</code></p>
<h5 id="interpret-as-little-endian-values"><a href="#interpret-as-little-endian-values">2. interpret as little-endian values</a></h5>
<p><code>0x4870</code>, <code>0x487F</code>, <code>0x4887</code>, <code>0x488D</code>, <code>0x4895</code></p>
<h5 id="subtract-base-offset"><a href="#subtract-base-offset">3. subtract base offset</a></h5>
<p>Our values are <em>spaced correctly</em> but their absolute values are wrong. Normalize them to 0.</p>
<p><code>0x4870 - 0x4870</code> = <code>0x0</code></p>
<p><code>0x487F - 0x4870</code> = <code>0xF</code></p>
<p><code>0x4887 - 0x4870</code> = <code>0x17</code></p>
<p><code>0x488D - 0x4870</code> = <code>0x1D</code></p>
<p><code>0x4895 - 0x4870</code> = <code>0x25</code></p>
<h5 id="add-base-address"><a href="#add-base-address">4. add base address</a></h5>
<p>Our values are spaced correctly and normalized. The data is supposed to start at <code>0x38870</code>, so add that to each value</p>
<p><code>0 + 0x38870</code> = <code>0x38870</code></p>
<p><code>0xF + 0x38870</code> = <code>0x3887F</code></p>
<p><code>0x17 + 0x38870</code> = <code>0x38887</code></p>
<p><code>0x1D + 0x38870</code> = <code>0x3888D</code></p>
<p><code>0x25 + 0x38870</code> = <code>0x38895</code></p>
<p>You could combine the “base offset” and “base address” arithmetic into a single step. However, splitting them out makes it clearer <em>why</em> it works.</p>
<p>Applying our process gets us the memory locations <code>0x38870</code>, <code>0x3887f</code>, <code>0x38887</code>, <code>0x3888d</code>, and <code>0x38895</code>. These should be the beginnings of the first five card names. Let’s see how we did.</p>
<figure>
<img src="/images/romhack/imhex-decoded-names.webp" width="986" height="134" alt="ImHex of DM4K at 0x38870, 0x3887f, 0x38887, 0x3888d, and 0x38895" />
<figcaption>The aforementioned locations are indicated in blue</figcaption>
</figure>
<p>Here i’ll misuse <code>&lt;ruby&gt;</code> to make the point. The ruby is the memory location. The text is the segment of text demarcated by that memory location.</p>
<blockquote>
<p><a href="https://yugipedia.com/wiki/B.eye_White_Dragon_(DM4)"><span lang="ja"><ruby>ブ<rt>0x38870</rt></ruby>ルーアイズ・ホワイトドラゴン</span></a><a href="https://yugipedia.com/wiki/Mystical_Elf_(DM4)"><span lang="ja"><ruby>ホ<rt>0x3887F</rt></ruby>ーりー・エルフ</span></a><a href="https://yugipedia.com/wiki/Hitotsu-me_Giant_(DM4)"><span lang="ja"><ruby>サ<rt>0x38887</rt></ruby>イクロプス</span></a><a href="https://yugipedia.com/wiki/Baby_Dragon_(DM4)"><span lang="ja"><ruby>ベ<rt>0x3888D</rt></ruby>ビー・ドラゴン</span></a><a href="https://yugipedia.com/wiki/Ryu-kishin_(DM4)"><span lang="ja"><ruby>ガ<rt>0x38895</rt></ruby>ーゴイル</span></a></p>
</blockquote>
<p>Those are the actual first five card names! If you’re curious which ones, click on each and you can confirm. So we have a process. Do that in reverse and you can generate the pointers.</p>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/note.webp" class="admonition-icon" alt="" width="128" height="128" />Note</span>
<div class="admonition-content">
<p>So, one of the steps in my build process is taking a list of card names vs card ids, and using the length of the card names to generate the corresponding pointer table, then inserting that table into the rom. Anything similarly automable should be assumed to be automated; doing so is worthwhile but is not part of the process of discovery so it isn’t going to be described here.</p>
</div>
</div>
<p>Now, let’s set aside the base DM4 for a bit. We are going to talk about <em>fonts</em>.</p>
<h3 id="messing-with-dm4-judah"><a href="#messing-with-dm4-judah">Messing with DM4-Judah</a></h3>
<p>Here is what I said, earlier:</p>
<blockquote>
<p>At this point I have a <em>guess</em> as to why Mako’s textbox was all garbled. Which we’ll address later.</p>
</blockquote>
<p>It is now “later”. Judah was able to expand or replace the in-game font. The thing that would make the most sense, would be if he replaced the original font, or parts of it. So, any text that he <em>didn’t edit at all</em>, became wrong, since some of the characters in it got swapped out for random English letters and punctuation.</p>
<figure>
<img src="/images/romhack/DM4J-Mako.webp" class="gbc" width="160" height="144" alt="Judah garbled dialogue with Mako Tsunami, reading: ワ・Z CfYデュ. n&amp;ト :・&quot;!nxCP L̈v!📄📄" />
<figcaption>Which would explain what happened to poor Mako</figcaption>
</figure>
<p>Let’s see if we can check whether that’s true. In the process of doing so, we’ll also work on the related matters of developing a font and of how the game matches the values in the <code>.tbl</code> to an image it draws on the screen.</p>
<p>To probe DM4-Judah for hints we’ll need to, much like the base DM4, have a way of getting text out of it. We’ll need a character table. Let’s start by seeing if we can get out of having to create it ourselves.</p>
<p>DM3-English has a <a href="https://datacrystal.tcrf.net/wiki/Yu-Gi-Oh!_Dark_Duel_Stories/TBL">text table</a>.</p>
<p>We can pop open his English DM4, load the English DM3 table, and check the same address as before.</p>
<figure>
<img src="/images/romhack/imhex-dm3-applied.webp" width="883" height="128" alt="ImHex applying the DM3 table to DM4-Judah" />
<figcaption>It appears to work!</figcaption>
</figure>
<p>What we see is his translation, of the first card. So, this table works. We’ll later find that this table isn’t a 100% match, but it is close enough for us to get started.</p>
<h4 id="character-maps"><a href="#character-maps">Character maps</a></h4>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/note.webp" class="admonition-icon" alt="" width="128" height="128" />Note</span>
<div class="admonition-content">
<p>Datacrystal refers to the document that maps bytes to characters as a “text table”. We’ve been referring to those as “text table”, “the table”, “<code>.tbl</code>”, etc. Datacrystal <em>also</em> refers to the section of the rom that contains/defines the font as a “text table”. For clarity we are not doing that. I’ll be calling the latter the “character map”, or the “font”.</p>
<p>We’re about to introduce the vram representation of the graphics. We’ll probably call that the “tilemap”.</p>
</div>
</div>
<p>The gameboy uses a portion of its memory, the vram (video ram), to store small bitmap tiles, which are the building blocks for what’s displayed on the screen. each of these tiles is defined in the rom and represents a tiny segment of the overall graphics. at any given moment, vram is filled with tiles that the gameboy can use to draw the current screen, like a “word bank” but for visual elements.</p>
<p>Since vram is limited, all of the tiles in the rom can’t be loaded at once. Instead, based on the context (e.g. whether you are “in battle”, “in a menu”, etc) the vram contents are updated to contain the right stuff.</p>
<p>Once in vram we know exactly how the contents will look once they’re onscreen. <a href="https://mgba.io/faq.html">mGBA</a> (like many other popular emulators) has a “view tiles” feature. This lets us see a visualization of the vram’s contents, like so:</p>
<figure>
<img src="/images/romhack/mgba-memview.webp" width="584" height="400" alt="Screenshot of mGBA tile viewer" />
<figcaption>The tile viewer in action</figcaption>
</figure>
<p>This tile data is the rom <em>somewhere</em>. We can’t, based merely on how it looks when loaded into vram, make any guarantees about how it is <em>represented</em> in the rom. If we could find it, and we knew how it was encoded, we could make changes to it, which would in turn change the “tile” in vram, which would in turn change the tile onscreen.</p>
<p>Let’s look at some tile maps.</p>
<h5 id="example-1-bladefly-dm4"><a href="#example-1-bladefly-dm4">Example 1: Bladefly (DM4)</a></h5>
<figure>
<img src="/images/romhack/bladefly-jp.webp" class="gbc" width="160" height="144" alt="DM4K&#39;s Bladefly: ブレードフライ 3★ こんちゅう/もりまぞく ⚔⚔600/🛡🛡700 するどい つるぎのようなうでを つきだして とんでくるハエ" />
<figcaption>Bladefly</figcaption>
</figure>
<figure>
<img src="/images/romhack/mgba-tiles-bladefly-jp.webp" width="582" height="404" alt="Screenshot of mGBA tile viewer for Bladefly" />
<figcaption>VRAM contents when displaying Bladefly</figcaption>
</figure>
<p>We see stuff in a nice logical order: the order found in the character table, or at least pretty close to it.</p>
<h5 id="example-2-bladefly-dm4-judah"><a href="#example-2-bladefly-dm4-judah">Example 2: Bladefly (DM4-Judah)</a></h5>
<figure>
<img src="/images/romhack/bladefly-en.webp" class="gbc" width="160" height="144" alt="DM4-Judah&#39;s Bladefly: Bladefly 3★ Insect/Forest ⚔⚔600/🛡🛡700 Flies at foe with sword-like arms" />
<figcaption>Bladefly</figcaption>
</figure>
<figure>
<img src="/images/romhack/mgba-tiles-bladefly-en.webp" width="585" height="403" alt="Screenshot of mGBA tile viewer for Bladefly" />
<figcaption>VRAM contents when displaying Bladefly</figcaption>
</figure>
<p>This is <em>quite similar</em> to the base DM4 vram contents. It still has a bunch of the kana in it! It looks like Judah found the font and replaced some of the characters to have the english alphabet and punctuation.</p>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/blobwizard.webp" class="admonition-icon" alt="" width="128" height="128" />Info</span>
<div class="admonition-content">
<p>We could have inferred this from comparing the <code>.tbl</code> files we’ve been using.</p>
</div>
</div>
<p>Notable: he puts a bunch of punctuation in slots that previously had kana in them. This is why Mako’s text was garbled. It was encoded using the DM4 character table and was being decoded using the DM4-Judah character table, resulting in showing the wrong stuff.</p>
<p>Now, let us once again be carried by the extremely helpful articles on datacrystal. The font is stored at <a href="https://datacrystal.tcrf.net/wiki/Yu-Gi-Oh!_Duel_Monsters_4:_Kaiba_Deck/ROM_map#Graphics_2"><code>0x20100-0x20510</code></a>.</p>
<p>Here’s the first 256 bytes, <code>0x20100-0x201FF</code>, from DM4-Judah:</p>
<figure>
<img src="/images/romhack/imhex-first-256-bytes-charmap-judah.webp" width="550" height="360" alt="ImHex of DM4-Judah at 0x20100" />
<figcaption>This is 𝓇𝒾𝓅ℯ 𝓌𝒾𝓉𝒽 𝓅ℴ𝓉ℯ𝓃𝓉𝒾𝒶𝓁.</figcaption>
</figure>
<p>This <em>looks</em> like it isn’t obfuscated. It looks like, if we’re <em>very</em> lucky, it might literally be a bunch of 8x8 bitmaps. Which, it turns out, they are. Here is how we can turn this back into an image:</p>
<h6 id="pick-an-8-byte-segment"><a href="#pick-an-8-byte-segment">0. pick an 8-byte segment</a></h6>
<p><em>We’re going to use the <strong>second</strong> character as our example since the first one is pretty boring and unillustrative</em>. as such we skip the first 8 bytes in favor of bytes 9-16</p>
<p><code>83393939393983FF</code></p>
<h6 id="split-into-1-byte-segments"><a href="#split-into-1-byte-segments">1. split into 1-byte segments</a></h6>
<p><code>83 39 39 39 39 39 83 FF</code></p>
<h6 id="put-each-byte-on-its-own-line"><a href="#put-each-byte-on-its-own-line">2. put each byte on its own line</a></h6>
<pre><code>83
39
39
39
39
39
83
FF</code></pre>
<h6 id="represent-these-lines-in-binary-as-in-as-8-bits-instead-of-hex-shorthand-as-in-as-two-hex-digits"><a href="#represent-these-lines-in-binary-as-in-as-8-bits-instead-of-hex-shorthand-as-in-as-two-hex-digits">3. represent these lines in binary (as in, as 8 bits) instead of hex shorthand (as in, as two hex digits)</a></h6>
<pre><code>10000011
00111001
00111001
00111001
00111001
00111001
10000011
11111111</code></pre>
<p>Each byte is a an instruction: “I represent 8 pixels. When displaying me, turn the 0s on and leave the 1s off”. Let’s try taking this representation one step further to make it easier to read: we’ll replce the <code>0</code>s with <code>▉</code>s and the <code>1</code>s with <code>╷</code>s</p>
<pre><code>╷▉▉▉▉▉╷╷
▉▉╷╷╷▉▉╷
▉▉╷╷╷▉▉╷
▉▉╷╷╷▉▉╷
▉▉╷╷╷▉▉╷
▉▉╷╷╷▉▉╷
╷▉▉▉▉▉╷╷
╷╷╷╷╷╷╷╷</code></pre>
<p>Tada!</p>
<p>It’s not a fluke, either. Here’s the first <em>four</em> characters after being decoded in this way:</p>
<pre><code>╷╷╷╷╷╷╷╷
╷╷╷╷╷╷╷╷
╷╷╷╷╷╷╷╷
╷╷╷╷╷╷╷╷
╷╷╷╷╷╷╷╷
╷╷╷╷╷╷╷╷
╷╷╷╷╷╷╷╷
╷╷╷╷╷╷╷╷</code></pre>
<pre><code>╷▉▉▉▉▉╷╷
▉▉╷╷╷▉▉╷
▉▉╷╷╷▉▉╷
▉▉╷╷╷▉▉╷
▉▉╷╷╷▉▉╷
▉▉╷╷╷▉▉╷
╷▉▉▉▉▉╷╷
╷╷╷╷╷╷╷╷</code></pre>
<pre><code>╷╷╷▉▉╷╷╷
╷╷▉▉▉╷╷╷
╷╷▉▉▉╷╷╷
╷╷╷▉▉╷╷╷
╷╷╷▉▉╷╷╷
╷╷╷▉▉╷╷╷
╷╷╷▉▉╷╷╷
╷╷╷╷╷╷╷╷</code></pre>
<pre><code>╷▉▉▉▉▉╷╷
▉▉╷╷╷▉▉╷
▉▉╷╷╷▉▉╷
╷╷╷▉▉▉╷╷
╷▉▉▉╷╷╷╷
▉▉╷╷╷╷╷╷
▉▉▉▉▉▉▉╷
╷╷╷╷╷╷╷╷</code></pre>
<p>Tada!</p>
<p>It looks like they’re even in the same order as is used in the character table. Like mentioned before, the vram or onscreen representation does not guarantee anything about how the data is represented internally. We are <em>quite fortunate</em> that the relationship between “position in the font” and “position in the character table” are so similar since it is less stuff to keep track of, but <a href="https://www.youtube.com/watch?v=aF1Yw_wu2cM">there was no guarantee it would be this way</a>. DM4 stores its font in the same place.</p>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/blobwizard.webp" class="admonition-icon" alt="" width="128" height="128" />Info</span>
<div class="admonition-content">
<p>Gameboy graphics are usually more complicated than this. Since we’re only dealing with monochrome we’re able to ignore stuff about bitplanes, attribute tables, etc. Which are best explained by somebody else and won’t be discussed unless in a later section we find it impossible to avoid getting into.</p>
</div>
</div>
<p>As mentioned, DM4-Judah uses a character table similar to or the same as the one from DM3-En. It also uses the same <em>font</em> as DM3-en. With a bit of math and experimentation we can figure out which bytes correspond to the subset of the font changed between DM4 and DM4-Judah.</p>
<p>So, I do that: I find the parts that constitute “Judah’s font”. I copy their values from DM4-Judah and paste them into the corresponding locations in DM4. This unlocks a cool trick. We’ll call this modified rom “DM4-fonttest”. We can diff DM4-fonttest and DM4 to create a <em>patch</em>: a file describing how to <em>produce DM4-fonttest</em> when given DM4 as an input. That patch can be found <a href="/misc/font-from-dm4-judah.ips">here</a></p>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/blobwizard.webp" class="admonition-icon" alt="" width="128" height="128" />Info</span>
<div class="admonition-content">
<p><em>Creating</em> the patch once you have the two versions of the file is not particularly interesting. Use a tool like lunarips to do this.</p>
</div>
</div>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/note.webp" class="admonition-icon" alt="" width="128" height="128" />Note</span>
<div class="admonition-content">
<p>I did this making the fonts embarassingly long ago, earlier this year. I think what I did was use imhex highlight patterns to annotate what ranges I cared about, then copied those ranges somehow. My project directory contains <code>dm4-judah-glyphset.pattern</code>, which is instructions for imhex on what ranges correspond to what characters. That file can be found <a href="/misc/dm4-judah-glyphset.pattern">here</a></p>
</div>
</div>
<p>So, now we are reasonably comfortable changing stuff and we’ve located and extracted the bulk of the text. Up next: translating it.</p>]]></description>
    <pubDate>Tue, 15 Oct 2024 00:00:00 UT</pubDate>
    <guid>https://nyuu.page/posts/2024-10-15-romhack/</guid>
    <dc:creator>nyuu</dc:creator>
</item>
<item>
    <title>Is this obvious scam a scam?</title>
    <link>https://nyuu.page/posts/2023-07-27-is-this-scam-a-scam/</link>
    <description><![CDATA[<p>A few quickies on fraud</p>
<h2 id="purpose-of-rscams"><a href="#purpose-of-rscams">Purpose of /r/scams</a></h2>
<p><a href="https://old.reddit.com/r/scams/">r/scams</a> is a strange place. A typical thread there goes sort of like this:</p>
<div class="forum-post">
<div class="forum-sidebar">
<img src="/images/avatars/snoo-1.webp" class="forum-avatar" width="256" height="256" alt="OP" />
<span class="forum-author">OP</span>
<span class="forum-title">Fraud Fledgeling</span>
<span class="forum-posts">Posts: 1</span>
</div>
<div class="forum-content">
<p>Hey, guys, I got sent this dm on instagram and I’m not sure what to make of it. A “guru” wants me to buy and send him cryptocurrency for him to “invest” on my behalf. So, is this obvious scam a scam?</p>
</div>
</div>
<div class="forum-post">
<div class="forum-sidebar">
<img src="/images/avatars/snoo-2.webp" class="forum-avatar" width="256" height="256" alt="Redditor #1" />
<span class="forum-author">Redditor #1</span>
<span class="forum-title">Scam Spotter</span>
<span class="forum-posts">Posts: 69420</span>
</div>
<div class="forum-content">
<p>Yes, that is a scam.</p>
</div>
</div>
<div class="forum-post">
<div class="forum-sidebar">
<img src="/images/avatars/snoo-3.webp" class="forum-avatar" width="256" height="256" alt="Redditor #2" />
<span class="forum-author">Redditor #2</span>
<span class="forum-title">Ponzi Prodigy</span>
<span class="forum-posts">Posts: 419</span>
</div>
<div class="forum-content">
<p>crypto!</p>
</div>
</div>
<div class="forum-reply">
<div class="forum-sidebar">
<img src="/images/avatars/robot.webp" class="forum-avatar" width="240" height="240" alt="Automod" />
<span class="forum-author">Automod</span>
<span class="forum-title">Dehydrated Water Salesbot</span>
<span class="forum-posts">Posts: Lots!</span>
</div>
<div class="forum-content">
<details>
<summary>
AutoModerator has been summoned to explain fake cryptocurrency site scams.
</summary>
Fake cryptocurrency websites and apps controlled by scammers are becoming more and more common. Sometimes the scam begins with a romance scammer who claims that they can help the victim invest in cryptocurrency. Victims are told to buy cryptocurrency of some kind using a legitimate cryptocurrency exchange, and then they are told to send their cryptocurrency to a website wallet address where it will be invested. Sometimes the scam begins with a notice that the victim won cryptocurrency on some website, in this case messages will often be sent through Discord. In either case, the scammer controls the website, so they make it look like there is money in the victim’s account on their website. Then the scammer (or the scammer pretending to be someone official who is associated with the website) tells the victim that they have to put more money into the website before they can get their money out of the website. Of course all of the money sent by the victim has gone directly into the scammer’s wallet, and any additional money sent by the victim to retrieve their money from the website will also go directly into the scammer’s wallet, and all of the information about money being held by the website was totally fake. This scam is also known as the pig butchering scam: <a href="https://www.reddit.com/r/Scams/comments/na8oax/asian_guygirl_from_online_dating_mentors_you_to/" class="uri">https://www.reddit.com/r/Scams/comments/na8oax/asian_guygirl_from_online_dating_mentors_you_to/</a>. If the scammer used Bitcoin, then you can report the scammer’s Bitcoin wallet address here: <a href="https://www.bitcoinabuse.com/reports" class="uri">https://www.bitcoinabuse.com/reports</a>. If the scammer used Ethereum, then you can report the scammer’s Ethereum wallet address here: <a href="https://info.etherscan.com/report-address/" class="uri">https://info.etherscan.com/report-address/</a>. You can see how much cryptocurrency has been sent to the scammer’s wallet address here: <a href="https://www.blockchain.com/explorer" class="uri">https://www.blockchain.com/explorer</a>. Thanks to redditor nimble2 for this script.
</details>
</div>
</div>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/note.webp" class="admonition-icon" alt="" width="128" height="128" />Note</span>
<div class="admonition-content">
<p>I spent sooo much time making the “fake forum posts” look right</p>
</div>
</div>
<p><a href="https://old.reddit.com/r/scams/">r/scams</a> is a community for discussing frauds &amp; avoiding being defrauded. This is noble, but I think its purpose has a weird tension in it:</p>
<ol type="1">
<li><p>If a poster thinks to ask about something on /r/scams/, the poster probably expects they are dealing with a scam. As they figure it’s a scam, they don’t need /r/scams/’ help.</p></li>
<li><p>If a person being defrauded doesn’t think they’re being scammed, then they aren’t going to ask about this on /r/scams/, so /r/scams/ can’t save them.</p></li>
</ol>
<p>I think this suggests that the range of situations where /r/scams/ is in a position to prevent a scam are pretty narrow. People definitely get value out of it regardless, of course.</p>
<h2 id="legitimate-use-of-noble-lie"><a href="#legitimate-use-of-noble-lie">Legitimate use of Noble Lie?</a></h2>
<p>Pig-butchers often try to get their mark to interact with fake cryptocurrency investment platforms. These sites are pretty barebones. They’ll have some price tickers, a deposit button, and a customer support widget, and not much else.</p>
<p>People on /r/scams/ will sometimes give advice to crypto investment scam victims, that makes me raise an eyebrow. The OP will post something like this:</p>
<div class="forum-post">
<div class="forum-sidebar">
<img src="/images/avatars/snoo-1.webp" class="forum-avatar" width="256" height="256" alt="OP" />
<span class="forum-author">OP</span>
<span class="forum-title">Scam Scion</span>
<span class="forum-posts">Posts: 1</span>
</div>
<div class="forum-content">
<p>My investment guru told me to download Coinbase and buy Bitcoin, and to then make an account on <a href="">https://www.0a8c11bc1TradePro.tk</a>, and to then send my Bitcoin from Coinbase to the address <code>0x10a8c11bc1TradePro</code>. Did I get scammed?</p>
</div>
</div>
<p>and they’ll get a response like this:</p>
<div class="forum-post">
<div class="forum-sidebar">
<img src="/images/avatars/snoo-2.webp" class="forum-avatar" width="256" height="256" alt="Redditor" />
<span class="forum-author">Redditor</span>
<span class="forum-title">Coin Disliker</span>
<span class="forum-posts">Posts: Several</span>
</div>
<div class="forum-content">
<p>Cryptocurrency is always a scam.</p>
</div>
</div>
<p>This is a strange response!</p>
<p>On one hand, there is a reasonable case for that nobody should buy cryptocurrency. OP certainly shouldn’t. OP will be better off if they categorically steer clear.</p>
<p>On the other hand, the point at which OP got <em>scammed</em> wasn’t when they downloaded Coinbase or even when they bought Bitcoin. They could have traded the Bitcoin for dollars and withdrawn the dollars, likely without issue. They got scammed only when they sent it to <code>0x10a8c11bc1TradePro</code>.</p>
<p>Sending their coin to <code>0x10a8c11bc1TradePro</code> is obviously a scam even in comparison to everything else in crypto. This distinction seems important to me. But telling OP about it might embolden them to deposit more and to then gamble it away or lose it trading shitcoins. Is it better if they don’t find out?</p>
<h2 id="omniscient-419-scammer"><a href="#omniscient-419-scammer">Omniscient 419 Scammer?</a></h2>
<p>Scam emails, the sort that gmail automatically &amp; silently junks for you, are written poorly. Here’s a representative excerpt from one:</p>
<blockquote>
<p>WITH DUE RESPECT OF THIS HONORABLE COURT UNITED STATE SUPREME COURT UNITED STATES OF AMERICA, WE WANT TO INFORM YOU THAT WE HAVE DISCOVERED A TRANSACTION BETWEEN YOU AND AFRICA UNITS, ACCORDING TO THE INVESTIGATION MADE IT HAS COME TO OUR NOTICE THAT YOU ARE THE REAL BENEFICIARY OF THE SAID FUNDS ONLY THAT YOU WERE DEALING WITH THE WRONG ONES.</p>
</blockquote>
<p>Terrible! Many have noticed this and asked why these are written so poorly.</p>
<p>The standard answer is “this is done intentionally, to filter out the skeptical, so the scammer doesn’t have to waste time responding to people who aren’t going to fall for it &amp; won’t send money.”</p>
<p>This sounds reasonable, and it’s the sort of thing that would be really satisfying if it were true, but is it? The authors might just be sort of bad at writing American English.</p>
<p>Youtuber “Atomic Shrimp” gets into <a href="https://www.youtube.com/playlist?list=PLk5KvJPikK02cQeWELmS-zh0MtNfwuh_e">extended conversations with email scammers</a> &amp; many of these go pretty “off-script”. The different scammers tend to have a distinct voice &amp; style &amp; so on. And this voice persists across different stages of him “getting them off-script”. Which I think suggests that this is often just how the person writing the scam email, actually writes.</p>
<p>This makes a bit more sense to me than that an email about how “the IRS demands Steam gift cards!” is actually playing 4-d chess.</p>
<hr />]]></description>
    <pubDate>Thu, 27 Jul 2023 00:00:00 UT</pubDate>
    <guid>https://nyuu.page/posts/2023-07-27-is-this-scam-a-scam/</guid>
    <dc:creator>nyuu</dc:creator>
</item>
<item>
    <title>Sideboarding with Pioneer UR Phoenix</title>
    <link>https://nyuu.page/posts/2023-06-02-sideboarding-ur-phoenix/</link>
    <description><![CDATA[<div class="card-notice">
<p>☞ This post contains <span class="emoji"><img src="/images/emoji/2728.svg" class="emoji-img" draggable="false" alt="✨" /><span class="emoji-text" aria-hidden="true">✨</span></span>on-hover card images<span class="emoji"><img src="/images/emoji/2728.svg" class="emoji-img" draggable="false" alt="✨" /><span class="emoji-text" aria-hidden="true">✨</span></span>, indicated by the hanafuda symbol <span class="hanafuda"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span>, like so: <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Thalia, Guardian of Thraben</span><img src="/images/cards/mtg/thalia-guardian-of-thraben.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Thalia, Guardian of Thraben {1}{W} - Legendary Creature — Human Soldier - First strike Noncreature spells cost {1} more to cast. - 2/1" /></span> ☜</p>
<div class="card-notice-details">
<p>Alt text contains card data for screen readers.</p>
</div>
</div>
<p>My dear girlfriend Alyssa—</p>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/blobwizard.webp" class="admonition-icon" alt="" width="128" height="128" />Info</span>
<div class="admonition-content">
<p>she can be found online in many places including her <a href="https://rationalconspiracy.com/">blog</a> and <a href="https://twitter.com/alyssamvance/">twitter</a></p>
</div>
</div>
<p>—is indulging me by trying out tournament magic. She wanted to play something reasonably competitive &amp; not have to spend a ton &amp; to not have to make cuts to save on budget &amp; for there to be a local scene. She picked pioneer.</p>
<p>I don’t play pioneer. I am okay at magic—</p>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/blobwizard.webp" class="admonition-icon" alt="" width="128" height="128" />Info</span>
<div class="admonition-content">
<p>I am an experienced amateur. I made mythic in each season I was active: <a href="/images/phoenix-sideboard/2019-03-16.webp">2019 March</a>, <a href="/images/phoenix-sideboard/2019-05-19.webp">2019 May</a>, <a href="/images/phoenix-sideboard/2019-06-28.webp">2019 June</a>, <a href="/images/phoenix-sideboard/2019-07-08.webp">2019 July</a>, <a href="/images/phoenix-sideboard/2019-10-20.webp">2019 October</a>, <a href="/images/phoenix-sideboard/2019-12-18.webp">2019 December</a>, <a href="/images/phoenix-sideboard/2023-01-31.webp">2023 January</a> and <a href="/images/phoenix-sideboard/2023-05-14.webp">2023 May</a> (pending). I also have an okay finish in a <a href="https://mtgtop8.com/event?e=27852&amp;d=420975&amp;f=LE&amp;switch=text">minor legacy tournament</a>.</p>
</div>
</div>
<p>—and so I think maybe I can be helpful despite not playing pioneer. I made this <a href="/pages/phoenix-sideboard/pioneer-meta-survey.html">overview</a> of the format to help her pick a deck. She’s built UR Phoenix and is taking it to an event soon. I now attempt to help her sideboard. Read on for wild, uninformed speculation about UR Phoenix and the pioneer format in general.</p>
<hr />
<h2 id="the-deck"><a href="#the-deck">The Deck</a></h2>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/note.webp" class="admonition-icon" alt="" width="128" height="128" />Note</span>
<div class="admonition-content">
<p>Note from the future: this post, like all posts from 2023, are posts I recovered from my old blog and reposted in 2025. When this post was current, it also included a link to a scryfall decklist thingy for easy exporting. In the intervening years I deleted that decklist, so, no more link.</p>
</div>
</div>
<p>Here’s the deck:</p>
<h3 id="main-60"><a href="#main-60">Main (60)</a></h3>
<h4 id="creature-9"><a href="#creature-9">Creature (9)</a></h4>
<p>4 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Thing in the Ice</span><img src="/images/cards/mtg/thing-in-the-ice.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Thing in the Ice  - Creature — Horror // Creature — Kraken Horror - " /></span> // <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Awoken Horror</span><img src="/images/cards/mtg/awoken-horror.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Awoken Horror  - Creature — Kraken Horror - When this creature transforms into Awoken Horror, return all non-Horror creatures to their owners&#39; hands. - 7/8" /></span></p>
<p>4 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Arclight Phoenix</span><img src="/images/cards/mtg/arclight-phoenix.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Arclight Phoenix {3}{R} - Creature — Phoenix - Flying, haste At the beginning of combat on your turn, if you&#39;ve cast three or more instant and sorcery spells this turn, return this card from your graveyard to the battlefield. - 3/2" /></span></p>
<p>1 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Brazen Borrower</span><img src="/images/cards/mtg/brazen-borrower.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Brazen Borrower {1}{U}{U} // {1}{U} - Creature — Faerie Rogue // Instant — Adventure -  - 3/1" /></span> // <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Petty Theft</span><img src="/images/cards/mtg/petty-theft.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Petty Theft {1}{U} - Instant — Adventure - Return target nonland permanent an opponent controls to its owner&#39;s hand." /></span></p>
<h4 id="instant-21"><a href="#instant-21">Instant (21)</a></h4>
<p>4 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Consider</span><img src="/images/cards/mtg/consider.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Consider {U} - Instant - Surveil 1. (Look at the top card of your library. You may put it into your graveyard.) Draw a card." /></span></p>
<p>4 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Fiery Impulse</span><img src="/images/cards/mtg/fiery-impulse.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Fiery Impulse {R} - Instant - Fiery Impulse deals 2 damage to target creature. Spell mastery — If there are two or more instant and/or sorcery cards in your graveyard, Fiery Impulse deals 3 damage instead." /></span></p>
<p>3 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Lightning Axe</span><img src="/images/cards/mtg/lightning-axe.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Lightning Axe {R} - Instant - As an additional cost to cast this spell, discard a card or pay {5}. Lightning Axe deals 5 damage to target creature." /></span></p>
<p>4 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Opt</span><img src="/images/cards/mtg/opt.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Opt {U} - Instant - Scry 1. (Look at the top card of your library. You may put that card on the bottom.) Draw a card." /></span></p>
<p>3 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Spell Pierce</span><img src="/images/cards/mtg/spell-pierce.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Spell Pierce {U} - Instant - Counter target noncreature spell unless its controller pays {2}." /></span></p>
<p>2 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Spikefield Hazard</span><img src="/images/cards/mtg/spikefield-hazard.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Spikefield Hazard  - Instant // Land - " /></span> // <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Spikefield Cave</span><img src="/images/cards/mtg/spikefield-cave.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Spikefield Cave  - Land - Spikefield Cave enters tapped. {T}: Add {R}." /></span></p>
<p>1 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Galvanic Iteration</span><img src="/images/cards/mtg/galvanic-iteration.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Galvanic Iteration {U}{R} - Instant - When you next cast an instant or sorcery spell this turn, copy that spell. You may choose new targets for the copy. Flashback {1}{U}{R} (You may cast this card from your graveyard for its flashback cost. Then exile it.)" /></span></p>
<h4 id="sorcery-11"><a href="#sorcery-11">Sorcery (11)</a></h4>
<p>3 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Chart a Course</span><img src="/images/cards/mtg/chart-a-course.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Chart a Course {1}{U} - Sorcery - Draw two cards. Then discard a card unless you attacked this turn." /></span></p>
<p>4 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Pieces of the Puzzle</span><img src="/images/cards/mtg/pieces-of-the-puzzle.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Pieces of the Puzzle {2}{U} - Sorcery - Reveal the top five cards of your library. Put up to two instant and/or sorcery cards from among them into your hand and the rest into your graveyard." /></span></p>
<p>4 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Treasure Cruise</span><img src="/images/cards/mtg/treasure-cruise.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Treasure Cruise {7}{U} - Sorcery - Delve (Each card you exile from your graveyard while casting this spell pays for {1}.) Draw three cards." /></span></p>
<h4 id="land-19"><a href="#land-19">Land (19)</a></h4>
<p>2 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Hall of Storm Giants</span><img src="/images/cards/mtg/hall-of-storm-giants.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Hall of Storm Giants  - Land - If you control two or more other lands, this land enters tapped. {T}: Add {U}. {5}{U}: Until end of turn, this land becomes a 7/7 blue Giant creature with ward {3}. It&#39;s still a land. (Whenever it becomes the target of a spell or ability an opponent controls, counter it unless that player pays {3}.)" /></span></p>
<p>2 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Island</span><img src="/images/cards/mtg/island.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Island  - Basic Land — Island - ({T}: Add {U}.)" /></span></p>
<p>1 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Otawara, Soaring City</span><img src="/images/cards/mtg/otawara-soaring-city.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Otawara, Soaring City  - Legendary Land - {T}: Add {U}. Channel — {3}{U}, Discard this card: Return target artifact, creature, enchantment, or planeswalker to its owner&#39;s hand. This ability costs {1} less to activate for each legendary creature you control." /></span></p>
<p>4 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Riverglide Pathway</span><img src="/images/cards/mtg/riverglide-pathway.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Riverglide Pathway  - Land // Land - " /></span> // <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Lavaglide Pathway</span><img src="/images/cards/mtg/lavaglide-pathway.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Lavaglide Pathway  - Land - {T}: Add {R}." /></span></p>
<p>4 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Spirebluff Canal</span><img src="/images/cards/mtg/spirebluff-canal.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Spirebluff Canal  - Land - This land enters tapped unless you control two or fewer other lands. {T}: Add {U} or {R}." /></span></p>
<p>4 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Steam Vents</span><img src="/images/cards/mtg/steam-vents.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Steam Vents  - Land — Island Mountain - ({T}: Add {U} or {R}.) As this land enters, you may pay 2 life. If you don&#39;t, it enters tapped." /></span></p>
<p>4 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Stormcarved Coast</span><img src="/images/cards/mtg/stormcarved-coast.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Stormcarved Coast  - Land - This land enters tapped unless you control two or more other lands. {T}: Add {U} or {R}." /></span></p>
<h3 id="sideboard-15"><a href="#sideboard-15">Sideboard (15)</a></h3>
<h4 id="creature-5"><a href="#creature-5">Creature (5)</a></h4>
<p>3 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Young Pyromancer</span><img src="/images/cards/mtg/young-pyromancer.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Young Pyromancer {1}{R} - Creature — Human Shaman - Whenever you cast an instant or sorcery spell, create a 1/1 red Elemental creature token. - 2/1" /></span></p>
<p>1 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Crackling Drake</span><img src="/images/cards/mtg/crackling-drake.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Crackling Drake {U}{U}{R}{R} - Creature — Drake - Flying Crackling Drake&#39;s power is equal to the total number of instant and sorcery cards you own in exile and in your graveyard. When this creature enters, draw a card. - */4" /></span></p>
<h4 id="instant-8"><a href="#instant-8">Instant (8)</a></h4>
<p>1 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Rending Volley</span><img src="/images/cards/mtg/rending-volley.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Rending Volley {R} - Instant - This spell can&#39;t be countered. Rending Volley deals 4 damage to target white or blue creature." /></span></p>
<p>2 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Abrade</span><img src="/images/cards/mtg/abrade.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Abrade {1}{R} - Instant - Choose one — • Abrade deals 3 damage to target creature. • Destroy target artifact." /></span></p>
<p>3 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Fry</span><img src="/images/cards/mtg/fry.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Fry {1}{R} - Instant - This spell can&#39;t be countered. Fry deals 5 damage to target creature or planeswalker that&#39;s white or blue." /></span></p>
<p>2 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Negate</span><img src="/images/cards/mtg/negate.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Negate {1}{U} - Instant - Counter target noncreature spell." /></span></p>
<p>1 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Mystical Dispute</span><img src="/images/cards/mtg/mystical-dispute.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Mystical Dispute {2}{U} - Instant - This spell costs {2} less to cast if it targets a blue spell. Counter target spell unless its controller pays {3}." /></span></p>
<h4 id="sorcery-2"><a href="#sorcery-2">Sorcery (2)</a></h4>
<p>2 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Brotherhood's End</span><img src="/images/cards/mtg/brotherhoods-end.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Brotherhood&#39;s End {1}{R}{R} - Sorcery - Choose one — • Brotherhood&#39;s End deals 3 damage to each creature and each planeswalker. • Destroy all artifacts with mana value 3 or less." /></span></p>
<h3 id="general-remarks"><a href="#general-remarks">General Remarks</a></h3>
<p>You are a Xerox<span class="emoji"><img src="/images/emoji/2122.svg" class="emoji-img" draggable="false" alt="™" /><span class="emoji-text" aria-hidden="true">™</span></span> deck: you want to cast cheap spells, especially self-replacing ones (“cantrips”) to set up wins through <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Arclight Phoenix</span><img src="/images/cards/mtg/arclight-phoenix.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Arclight Phoenix {3}{R} - Creature — Phoenix - Flying, haste At the beginning of combat on your turn, if you&#39;ve cast three or more instant and sorcery spells this turn, return this card from your graveyard to the battlefield. - 3/2" /></span> reanimations and <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Thing in the Ice</span><img src="/images/cards/mtg/thing-in-the-ice.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Thing in the Ice  - Creature — Horror // Creature — Kraken Horror - " /></span> // <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Awoken Horror</span><img src="/images/cards/mtg/awoken-horror.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Awoken Horror  - Creature — Kraken Horror - When this creature transforms into Awoken Horror, return all non-Horror creatures to their owners&#39; hands. - 7/8" /></span> flips for the beatdown.</p>
<p>You win by being able to interact profitably since you can do things you “already wanted to do” (e.g. cast <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Consider</span><img src="/images/cards/mtg/consider.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Consider {U} - Instant - Surveil 1. (Look at the top card of your library. You may put it into your graveyard.) Draw a card." /></span>) and have it move you closer to objectives like “phoenixes in graveyard” and “three precombat instants and/or sorceries” that make you win. Interacting with the opponent &amp; trading resources with them is usually good since you have a lot of card draw / card advantage.</p>
<p>You expect to spend the first few turns “setting up”: using the cantrips to get <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Arclight Phoenix</span><img src="/images/cards/mtg/arclight-phoenix.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Arclight Phoenix {3}{R} - Creature — Phoenix - Flying, haste At the beginning of combat on your turn, if you&#39;ve cast three or more instant and sorcery spells this turn, return this card from your graveyard to the battlefield. - 3/2" /></span>s in the graveyard &amp; durdling around until you have enough lands for it to be possible to cast three spells in a turn.</p>
<p>If you can, it is of course great to use the <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Galvanic Iteration</span><img src="/images/cards/mtg/galvanic-iteration.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Galvanic Iteration {U}{R} - Instant - When you next cast an instant or sorcery spell this turn, copy that spell. You may choose new targets for the copy. Flashback {1}{U}{R} (You may cast this card from your graveyard for its flashback cost. Then exile it.)" /></span> on something expensive like <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Treasure Cruise</span><img src="/images/cards/mtg/treasure-cruise.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Treasure Cruise {7}{U} - Sorcery - Delve (Each card you exile from your graveyard while casting this spell pays for {1}.) Draw three cards." /></span> rather than a mere <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Opt</span><img src="/images/cards/mtg/opt.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Opt {U} - Instant - Scry 1. (Look at the top card of your library. You may put that card on the bottom.) Draw a card." /></span>, but using it on a small spell is still fine.</p>
<h3 id="arclight-phoenix-ability-and-you"><a href="#arclight-phoenix-ability-and-you">Arclight Phoenix’ Ability And You</a></h3>
<p><span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Arclight Phoenix</span><img src="/images/cards/mtg/arclight-phoenix.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Arclight Phoenix {3}{R} - Creature — Phoenix - Flying, haste At the beginning of combat on your turn, if you&#39;ve cast three or more instant and sorcery spells this turn, return this card from your graveyard to the battlefield. - 3/2" /></span> reads:</p>
<blockquote>
<p>At the beginning of combat on your turn, if you’ve cast three or more instant and sorcery spells this turn, return Arclight Phoenix from your graveyard to the battlefield.</p>
</blockquote>
<p>You want to look for opportunities to cast three instants or sorceries in your turn &amp; before combat. Your opponent knows you are trying to do this and may try to stop you.</p>
<h3 id="our-meta"><a href="#our-meta">Our Meta</a></h3>
<p>Our local meta is aggro heavy, and mono-blue spirits heavy in particular. Per the <a href="/pages/phoenix-sideboard/pioneer-meta-survey.html">matchup matrix</a> the UR Phoenix player is actually favored if they understand the matchup well enough.</p>
<p>This makes sense to me:</p>
<ul>
<li><p>blue is bad at exiling graveyards, so the phoenixes and delve targets are <em>probably</em> not going anywhere.</p></li>
<li><p>you can accomplish your goals by casting nothing but <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Opt</span><img src="/images/cards/mtg/opt.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Opt {U} - Instant - Scry 1. (Look at the top card of your library. You may put that card on the bottom.) Draw a card." /></span> and <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Consider</span><img src="/images/cards/mtg/consider.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Consider {U} - Instant - Surveil 1. (Look at the top card of your library. You may put it into your graveyard.) Draw a card." /></span>, and it’s really bad to counter an <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Opt</span><img src="/images/cards/mtg/opt.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Opt {U} - Instant - Scry 1. (Look at the top card of your library. You may put that card on the bottom.) Draw a card." /></span> or <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Consider</span><img src="/images/cards/mtg/consider.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Consider {U} - Instant - Surveil 1. (Look at the top card of your library. You may put it into your graveyard.) Draw a card." /></span> most of the time</p></li>
<li><p>Arclight Phoenix’ “return to play” ability doesn’t count as casting it, so it’s not like they can counter you.</p></li>
<li><p>Arclight Phoenix has flying, can lethally trade with most spirits most of the time, and can be gotten back. One of Spirits’ play patterns is to play one spirit, put <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Curious Obsession</span><img src="/images/cards/mtg/curious-obsession.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Curious Obsession {U} - Enchantment — Aura - Enchant creature Enchanted creature gets +1/+1 and has &quot;Whenever this creature deals combat damage to a player, you may draw a card.&quot; At the beginning of your end step, if you didn&#39;t attack with a creature this turn, sacrifice this Aura." /></span> on it, then attack like ten times with it, using the extra cards to protect the spirit and counter your stuff. This is only good if they’re able to do combat damage to you.</p></li>
</ul>
<p>However: spirits has a <em>lot</em> of mechanics and many of them make it possible for an experienced player to trick the opponent. It’s important to know what the deck can do, so you can plan ahead around “if I do x, they might do y or z. Depending on which, I will do a or b…”. You not knowing they can give a spirit hexproof at instant speed, for example, would give them an advantage.</p>
<p>We’re going to tweak your sideboard to be <em>very</em> anti-spirits. Most Phoenix sideboards make more concessions to fighting ramp and control, but I’m not seeing these at our store.</p>
<h3 id="rules-rulings-conventions"><a href="#rules-rulings-conventions">Rules &amp; Rulings &amp; Conventions</a></h3>
<ul>
<li><p>The copy made by <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Galvanic Iteration</span><img src="/images/cards/mtg/galvanic-iteration.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Galvanic Iteration {U}{R} - Instant - When you next cast an instant or sorcery spell this turn, copy that spell. You may choose new targets for the copy. Flashback {1}{U}{R} (You may cast this card from your graveyard for its flashback cost. Then exile it.)" /></span> does not count as “casting” a spell</p></li>
<li><p>The discarding done by <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Lightning Axe</span><img src="/images/cards/mtg/lightning-axe.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Lightning Axe {R} - Instant - As an additional cost to cast this spell, discard a card or pay {5}. Lightning Axe deals 5 damage to target creature." /></span> is a “cost”: it happens as you start casting the spell. So for better or worse the opponent can’t use counterspells to stop you from using <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Lightning Axe</span><img src="/images/cards/mtg/lightning-axe.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Lightning Axe {R} - Instant - As an additional cost to cast this spell, discard a card or pay {5}. Lightning Axe deals 5 damage to target creature." /></span>’s secondary cost as a discard outlet.</p></li>
<li><p>The first thing that happens in the upkeep step is all the effects that say “at the beginning of your upkeep, do x” all go on the stack in FILO order. If you control simultaneous effects, you choose the order.</p></li>
<li><p>The opponent is probably not going to help you by reminding you to take counters off of <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Thing in the Ice</span><img src="/images/cards/mtg/thing-in-the-ice.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Thing in the Ice  - Creature — Horror // Creature — Kraken Horror - " /></span> // <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Awoken Horror</span><img src="/images/cards/mtg/awoken-horror.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Awoken Horror  - Creature — Kraken Horror - When this creature transforms into Awoken Horror, return all non-Horror creatures to their owners&#39; hands. - 7/8" /></span> or reminding you to bring back the <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Arclight Phoenix</span><img src="/images/cards/mtg/arclight-phoenix.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Arclight Phoenix {3}{R} - Creature — Phoenix - Flying, haste At the beginning of combat on your turn, if you&#39;ve cast three or more instant and sorcery spells this turn, return this card from your graveyard to the battlefield. - 3/2" /></span>. Everyone misses triggers sometimes. You get a lot of win% by making sure you remember the most important ones always. This will take practice. Use visual aids.</p>
<ul>
<li>I’m going to make you a reminder card for tracking “precombat instants/sorceries cast this turn” so you keep in mind to think about whether to work towards reaching it that turn &amp; how far you currently are. It may take getting used to; that is okay.</li>
</ul></li>
<li><p>The stack is FILO. If you try to use a lighting axe to kill something and the opponent responds by casting <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Rattlechains</span><img src="/images/cards/mtg/rattlechains.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Rattlechains {1}{U} - Creature — Spirit - Flash Flying When this creature enters, target Spirit gains hexproof until end of turn. You may cast Spirit spells as though they had flash. - 2/1" /></span>, then the Rattlechains will resolve first. Then its’ ETB hexproof-granting ability will go on the stack also ahead of the lighting axe, and by the time the axe resolves the target will have hexproof and so not get axed.</p></li>
<li><p>“Can’t be countered” means countering it doesn’t do anything. It also means that countering-related effects such as “ward” (which usually counter stuff unless you pay the ward cost) don’t do anything.</p></li>
<li><p>“Can’t be countered” does not go through hexproof.</p></li>
</ul>
<h3 id="general-tips"><a href="#general-tips">General Tips</a></h3>
<p>Try to look at spending your mana in terms of “how do I make the best use of the mana I get <em>this turn cycle</em>. Sometimes this means doing a lot of things in your turn’s precombat main phase to try to get back the phoenixes. Sometimes it means doing a lot of things in the opponent’s end step so you get to act as late as possible and/or remove counters from a <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Thing in the Ice</span><img src="/images/cards/mtg/thing-in-the-ice.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Thing in the Ice  - Creature — Horror // Creature — Kraken Horror - " /></span> // <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Awoken Horror</span><img src="/images/cards/mtg/awoken-horror.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Awoken Horror  - Creature — Kraken Horror - When this creature transforms into Awoken Horror, return all non-Horror creatures to their owners&#39; hands. - 7/8" /></span>. You want to <strong>preserve optionality</strong></p>
<p>Notice what your opponent is trying to do. Are they spending resources on trying to find lands to make their land drops vs whether they are advancing their gameplan, etc. If they are struggling to just find their lands, be aggressive; they probably can’t counter your spell.</p>
<p>Failing that, do things that make the opponent play worse. Force them to make a lot of choices, so they have more opportunities to make the wrong ones. Winning is made out of scads of tiny edges and correct decisions made out of habit &amp; reflex. People make a lot of mistakes. If you can make it <em>look</em> like they’re facing a critical choice, they will probably act like it and they might misplay. This works just as well if your hand is nothing but land: they may <em>suspect</em> a bluff, but they usually won’t <em>know</em> it is a bluff.</p>
<p>Think in terms of how many turns you are away from killing the opponent (your “clock”) and how different lines of play change or don’t change your clock. If using a burn spell on the opponent isn’t going to make them die any faster (e.g. it means they are at 1 rather than at 3) this usually means “don’t use it on them; just wait”.</p>
<h3 id="sideboarding"><a href="#sideboarding">Sideboarding</a></h3>
<p>If killing their creatures doesn’t put you ahead then you probably don’t need things that kill their creatures. Killing a <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Bloodtithe Harvester</span><img src="/images/cards/mtg/bloodtithe-harvester.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Bloodtithe Harvester {B}{R} - Creature — Vampire - When this creature enters, create a Blood token. (It&#39;s an artifact with &quot;{1}, {T}, Discard a card, Sacrifice this token: Draw a card.&quot;) {T}, Sacrifice this creature: Target creature gets -X/-X until end of turn, where X is twice the number of Blood tokens you control. Activate only as a sorcery. - 3/2" /></span> doesn’t really set them back or you forward most of the time, so consider ignoring it.</p>
<p>Kill their <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Thalia, Guardian of Thraben</span><img src="/images/cards/mtg/thalia-guardian-of-thraben.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Thalia, Guardian of Thraben {1}{W} - Legendary Creature — Human Soldier - First strike Noncreature spells cost {1} more to cast. - 2/1" /></span> on sight.</p>
<p>They’re going to try to exile the <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Arclight Phoenix</span><img src="/images/cards/mtg/arclight-phoenix.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Arclight Phoenix {3}{R} - Creature — Phoenix - Flying, haste At the beginning of combat on your turn, if you&#39;ve cast three or more instant and sorcery spells this turn, return this card from your graveyard to the battlefield. - 3/2" /></span> in the post-sideboard games; consider not putting them in the graveyard unless you plan on reviving them very soon. Remember the <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Brazen Borrower</span><img src="/images/cards/mtg/brazen-borrower.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Brazen Borrower {1}{U}{U} // {1}{U} - Creature — Faerie Rogue // Instant — Adventure -  - 3/1" /></span> // <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Petty Theft</span><img src="/images/cards/mtg/petty-theft.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Petty Theft {1}{U} - Instant — Adventure - Return target nonland permanent an opponent controls to its owner&#39;s hand." /></span> can bounce most permanents, including Leylines. Sometimes the opponent actually cannot recast it due to not running black mana. Sometimes they <em>could</em> recast it but one turn of graveyard access is enough for you to win. And if you pressure them enough, they might not be able to justify casting it.</p>
<h4 id="specific-matchups"><a href="#specific-matchups">Specific matchups</a></h4>
<h5 id="green-devotion"><a href="#green-devotion">Green Devotion</a></h5>
<p>This is the second most popular deck in the format. I don’t think I’ve seen it played at our store. Our sideboard is weak against them since we’re focusing so much on anti-aggro. If you do face them: their thing is to ramp a lot and then cast a huge thing that wins the game. For example: <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Storm the Festival</span><img src="/images/cards/mtg/storm-the-festival.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Storm the Festival {3}{G}{G}{G} - Sorcery - Look at the top five cards of your library. You may put up to two permanent cards with mana value 5 or less from among them onto the battlefield. Put the rest on the bottom of your library in a random order. Flashback {7}{G}{G}{G} (You may cast this card from your graveyard for its flashback cost. Then exile it.)" /></span>.</p>
<p>The majority of their “bombs” are noncreature spells. <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Negate</span><img src="/images/cards/mtg/negate.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Negate {1}{U} - Instant - Counter target noncreature spell." /></span> these. Check with them about how much mana they have or can make before you <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Spell Pierce</span><img src="/images/cards/mtg/spell-pierce.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Spell Pierce {U} - Instant - Counter target noncreature spell unless its controller pays {2}." /></span>.</p>
<p>Out: 2 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Pieces of the Puzzle</span><img src="/images/cards/mtg/pieces-of-the-puzzle.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Pieces of the Puzzle {2}{U} - Sorcery - Reveal the top five cards of your library. Put up to two instant and/or sorcery cards from among them into your hand and the rest into your graveyard." /></span></p>
<p>In: 2 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Negate</span><img src="/images/cards/mtg/negate.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Negate {1}{U} - Instant - Counter target noncreature spell." /></span></p>
<h5 id="rakdos-midrange"><a href="#rakdos-midrange">Rakdos Midrange</a></h5>
<p>This is the most popular deck in the format. It’s pretty expensive so it’s going to be underrepresented but I think we have one player on it.</p>
<p>Their premier threat is <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Sheoldred, the Apocalypse</span><img src="/images/cards/mtg/sheoldred-the-apocalypse.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Sheoldred, the Apocalypse {2}{B}{B} - Legendary Creature — Phyrexian Praetor - Deathtouch Whenever you draw a card, you gain 2 life. Whenever an opponent draws a card, they lose 2 life. - 4/5" /></span>. Save <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Lightning Axe</span><img src="/images/cards/mtg/lightning-axe.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Lightning Axe {R} - Instant - As an additional cost to cast this spell, discard a card or pay {5}. Lightning Axe deals 5 damage to target creature." /></span> for this unless you expect to win before their fifth turn since that’s when they’ll start drawing cards → gaining life → becoming ~unkillable via just having the Sheoldred.</p>
<p>They have a lot of removal and can generally drag us into a long grindy game. We take out things that aren’t impactful enough and bring in things that let us clog up or wipe the board.</p>
<p>OUT: 1 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Galvanic Iteration</span><img src="/images/cards/mtg/galvanic-iteration.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Galvanic Iteration {U}{R} - Instant - When you next cast an instant or sorcery spell this turn, copy that spell. You may choose new targets for the copy. Flashback {1}{U}{R} (You may cast this card from your graveyard for its flashback cost. Then exile it.)" /></span>, 4 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Pieces of the Puzzle</span><img src="/images/cards/mtg/pieces-of-the-puzzle.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Pieces of the Puzzle {2}{U} - Sorcery - Reveal the top five cards of your library. Put up to two instant and/or sorcery cards from among them into your hand and the rest into your graveyard." /></span>, 1 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Opt</span><img src="/images/cards/mtg/opt.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Opt {U} - Instant - Scry 1. (Look at the top card of your library. You may put that card on the bottom.) Draw a card." /></span>, 4 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Treasure Cruise</span><img src="/images/cards/mtg/treasure-cruise.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Treasure Cruise {7}{U} - Sorcery - Delve (Each card you exile from your graveyard while casting this spell pays for {1}.) Draw three cards." /></span></p>
<p>IN: 3 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Young Pyromancer</span><img src="/images/cards/mtg/young-pyromancer.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Young Pyromancer {1}{R} - Creature — Human Shaman - Whenever you cast an instant or sorcery spell, create a 1/1 red Elemental creature token. - 2/1" /></span>, 2 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Negate</span><img src="/images/cards/mtg/negate.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Negate {1}{U} - Instant - Counter target noncreature spell." /></span>, 2 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Abrade</span><img src="/images/cards/mtg/abrade.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Abrade {1}{R} - Instant - Choose one — • Abrade deals 3 damage to target creature. • Destroy target artifact." /></span>, 1 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Crackling Drake</span><img src="/images/cards/mtg/crackling-drake.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Crackling Drake {U}{U}{R}{R} - Creature — Drake - Flying Crackling Drake&#39;s power is equal to the total number of instant and sorcery cards you own in exile and in your graveyard. When this creature enters, draw a card. - */4" /></span>, 2 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Brotherhood's End</span><img src="/images/cards/mtg/brotherhoods-end.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Brotherhood&#39;s End {1}{R}{R} - Sorcery - Choose one — • Brotherhood&#39;s End deals 3 damage to each creature and each planeswalker. • Destroy all artifacts with mana value 3 or less." /></span></p>
<p><em>This might be “over-boarding”; feel free to do less if you want.</em></p>
<h5 id="white-humans-weenies"><a href="#white-humans-weenies">White Humans / Weenies</a></h5>
<p>This is my deck! Bring in removal, especially boardwipes. Other than <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Brave the Elements</span><img src="/images/cards/mtg/brave-the-elements.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Brave the Elements {W} - Instant - Choose a color. White creatures you control gain protection from the chosen color until end of turn." /></span> (and some activated abilities on creatures) this deck plays at sorcery speed. Expect them to dump their hand into play quickly and to have minimal followup if you boardwipe. This matchup is about surviving the first few turns</p>
<p>Take out spell pierces and trim some copies of more expensive spells.</p>
<p>IN: 2 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Brotherhood's End</span><img src="/images/cards/mtg/brotherhoods-end.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Brotherhood&#39;s End {1}{R}{R} - Sorcery - Choose one — • Brotherhood&#39;s End deals 3 damage to each creature and each planeswalker. • Destroy all artifacts with mana value 3 or less." /></span>, 3 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Fry</span><img src="/images/cards/mtg/fry.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Fry {1}{R} - Instant - This spell can&#39;t be countered. Fry deals 5 damage to target creature or planeswalker that&#39;s white or blue." /></span>, 1 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Rending Volley</span><img src="/images/cards/mtg/rending-volley.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Rending Volley {R} - Instant - This spell can&#39;t be countered. Rending Volley deals 4 damage to target white or blue creature." /></span>, 2 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Abrade</span><img src="/images/cards/mtg/abrade.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Abrade {1}{R} - Instant - Choose one — • Abrade deals 3 damage to target creature. • Destroy target artifact." /></span></p>
<p>OUT: 3 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Spell Pierce</span><img src="/images/cards/mtg/spell-pierce.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Spell Pierce {U} - Instant - Counter target noncreature spell unless its controller pays {2}." /></span>, 2 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Treasure Cruise</span><img src="/images/cards/mtg/treasure-cruise.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Treasure Cruise {7}{U} - Sorcery - Delve (Each card you exile from your graveyard while casting this spell pays for {1}.) Draw three cards." /></span>, 2 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Pieces of the Puzzle</span><img src="/images/cards/mtg/pieces-of-the-puzzle.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Pieces of the Puzzle {2}{U} - Sorcery - Reveal the top five cards of your library. Put up to two instant and/or sorcery cards from among them into your hand and the rest into your graveyard." /></span>, 1 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Chart a Course</span><img src="/images/cards/mtg/chart-a-course.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Chart a Course {1}{U} - Sorcery - Draw two cards. Then discard a card unless you attacked this turn." /></span></p>
<h5 id="u-spirits"><a href="#u-spirits">U Spirits</a></h5>
<p>Know what their cards do beforehand. Here is an archetypal decklist; <a href="https://www.mtggoldfish.com/archetype/pioneer-mono-blue-spirits">take a look</a></p>
<p>They’re going to try to play one spirit, put <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Curious Obsession</span><img src="/images/cards/mtg/curious-obsession.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Curious Obsession {U} - Enchantment — Aura - Enchant creature Enchanted creature gets +1/+1 and has &quot;Whenever this creature deals combat damage to a player, you may draw a card.&quot; At the beginning of your end step, if you didn&#39;t attack with a creature this turn, sacrifice this Aura." /></span> on it, then attack like ten times with it, using the extra cards to protect the spirit and counter your stuff. This is only good if they’re able to do combat damage to you. Their creatures are pretty bad if you aren’t surprised by them.</p>
<p>The stack is FILO. If you try to use a lighting axe to kill something and the opponent responds by casting <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Rattlechains</span><img src="/images/cards/mtg/rattlechains.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Rattlechains {1}{U} - Creature — Spirit - Flash Flying When this creature enters, target Spirit gains hexproof until end of turn. You may cast Spirit spells as though they had flash. - 2/1" /></span>, then the Rattlechains will resolve first. Then its’ ETB hexproof-granting ability will go on the stack also ahead of the lighting axe, and by the time the axe resolves the target will have hexproof and so not get axed.</p>
<p>They’re allowed to “level up” the <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Ascendant Spirit</span><img src="/images/cards/mtg/ascendant-spirit.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Ascendant Spirit {U} - Snow Creature — Spirit - {S}{S}: This creature becomes a Spirit Warrior with base power and toughness 2/3. {S}{S}{S}: If this creature is a Warrior, put a flying counter on it and it becomes a Spirit Warrior Angel with base power and toughness 4/4. {S}{S}{S}{S}: If this creature is an Angel, put two +1/+1 counters on it and it gains &quot;Whenever this creature deals combat damage to a player, draw a card.&quot; - 1/1" /></span> at instant speed. Doing so uses the stack.</p>
<p>Your gameplan is the same as always:</p>
<ol type="1">
<li><p>survive the early turns as you get set up</p></li>
<li><p>flip a thing in the ice or reanimate some phoenixes for the win</p></li>
</ol>
<p>Since their gameplan leads to them drowning in cards, you’ll want to kill their stuff. Do this EITHER when they are tapped out or right after they declare attacks.</p>
<p>Remember that <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Mystical Dispute</span><img src="/images/cards/mtg/mystical-dispute.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Mystical Dispute {2}{U} - Instant - This spell costs {2} less to cast if it targets a blue spell. Counter target spell unless its controller pays {3}." /></span> counters everything in their deck for one mana. If you want to prepare even further, we could get you more of them.</p>
<p>I think <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Thing in the Ice</span><img src="/images/cards/mtg/thing-in-the-ice.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Thing in the Ice  - Creature — Horror // Creature — Kraken Horror - " /></span> // <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Awoken Horror</span><img src="/images/cards/mtg/awoken-horror.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Awoken Horror  - Creature — Kraken Horror - When this creature transforms into Awoken Horror, return all non-Horror creatures to their owners&#39; hands. - 7/8" /></span> is worse here since it cannot block flyers.</p>
<p>IN: 2 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Brotherhood's End</span><img src="/images/cards/mtg/brotherhoods-end.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Brotherhood&#39;s End {1}{R}{R} - Sorcery - Choose one — • Brotherhood&#39;s End deals 3 damage to each creature and each planeswalker. • Destroy all artifacts with mana value 3 or less." /></span>, 3 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Fry</span><img src="/images/cards/mtg/fry.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Fry {1}{R} - Instant - This spell can&#39;t be countered. Fry deals 5 damage to target creature or planeswalker that&#39;s white or blue." /></span>, 1 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Rending Volley</span><img src="/images/cards/mtg/rending-volley.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Rending Volley {R} - Instant - This spell can&#39;t be countered. Rending Volley deals 4 damage to target white or blue creature." /></span>, 2 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Abrade</span><img src="/images/cards/mtg/abrade.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Abrade {1}{R} - Instant - Choose one — • Abrade deals 3 damage to target creature. • Destroy target artifact." /></span>, 1 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Mystical Dispute</span><img src="/images/cards/mtg/mystical-dispute.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Mystical Dispute {2}{U} - Instant - This spell costs {2} less to cast if it targets a blue spell. Counter target spell unless its controller pays {3}." /></span>, 1 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Crackling Drake</span><img src="/images/cards/mtg/crackling-drake.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Crackling Drake {U}{U}{R}{R} - Creature — Drake - Flying Crackling Drake&#39;s power is equal to the total number of instant and sorcery cards you own in exile and in your graveyard. When this creature enters, draw a card. - */4" /></span></p>
<p>OUT: 1 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Galvanic Iteration</span><img src="/images/cards/mtg/galvanic-iteration.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Galvanic Iteration {U}{R} - Instant - When you next cast an instant or sorcery spell this turn, copy that spell. You may choose new targets for the copy. Flashback {1}{U}{R} (You may cast this card from your graveyard for its flashback cost. Then exile it.)" /></span>, 4 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Thing in the Ice</span><img src="/images/cards/mtg/thing-in-the-ice.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Thing in the Ice  - Creature — Horror // Creature — Kraken Horror - " /></span> // <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Awoken Horror</span><img src="/images/cards/mtg/awoken-horror.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Awoken Horror  - Creature — Kraken Horror - When this creature transforms into Awoken Horror, return all non-Horror creatures to their owners&#39; hands. - 7/8" /></span>, 2 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Treasure Cruise</span><img src="/images/cards/mtg/treasure-cruise.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Treasure Cruise {7}{U} - Sorcery - Delve (Each card you exile from your graveyard while casting this spell pays for {1}.) Draw three cards." /></span>, 2 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Pieces of the Puzzle</span><img src="/images/cards/mtg/pieces-of-the-puzzle.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Pieces of the Puzzle {2}{U} - Sorcery - Reveal the top five cards of your library. Put up to two instant and/or sorcery cards from among them into your hand and the rest into your graveyard." /></span>, 1 <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Chart a Course</span><img src="/images/cards/mtg/chart-a-course.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Chart a Course {1}{U} - Sorcery - Draw two cards. Then discard a card unless you attacked this turn." /></span></p>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/note.webp" class="admonition-icon" alt="" width="128" height="128" />Note</span>
<div class="admonition-content">
<p>Want to keep <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Thing in the Ice</span><img src="/images/cards/mtg/thing-in-the-ice.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Thing in the Ice  - Creature — Horror // Creature — Kraken Horror - " /></span> // <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Awoken Horror</span><img src="/images/cards/mtg/awoken-horror.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Awoken Horror  - Creature — Kraken Horror - When this creature transforms into Awoken Horror, return all non-Horror creatures to their owners&#39; hands. - 7/8" /></span> in? Do what you think is best, of course. I’d look into running more <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Crackling Drake</span><img src="/images/cards/mtg/crackling-drake.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Crackling Drake {U}{U}{R}{R} - Creature — Drake - Flying Crackling Drake&#39;s power is equal to the total number of instant and sorcery cards you own in exile and in your graveyard. When this creature enters, draw a card. - */4" /></span> after all and bringing them in for this, I think. It even lives through <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Brotherhood's End</span><img src="/images/cards/mtg/brotherhoods-end.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Brotherhood&#39;s End {1}{R}{R} - Sorcery - Choose one — • Brotherhood&#39;s End deals 3 damage to each creature and each planeswalker. • Destroy all artifacts with mana value 3 or less." /></span>!</p>
</div>
</div>
<h5 id="generic-control"><a href="#generic-control">Generic Control</a></h5>
<p>Take out burn spells such as <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Spikefield Hazard</span><img src="/images/cards/mtg/spikefield-hazard.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Spikefield Hazard  - Instant // Land - " /></span> // <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Spikefield Cave</span><img src="/images/cards/mtg/spikefield-cave.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Spikefield Cave  - Land - Spikefield Cave enters tapped. {T}: Add {R}." /></span> &amp; <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Fiery Impulse</span><img src="/images/cards/mtg/fiery-impulse.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Fiery Impulse {R} - Instant - Fiery Impulse deals 2 damage to target creature. Spell mastery — If there are two or more instant and/or sorcery cards in your graveyard, Fiery Impulse deals 3 damage instead." /></span></p>
<p>Bring in counterspells and things that generate value e.g. <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Crackling Drake</span><img src="/images/cards/mtg/crackling-drake.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Crackling Drake {U}{U}{R}{R} - Creature — Drake - Flying Crackling Drake&#39;s power is equal to the total number of instant and sorcery cards you own in exile and in your graveyard. When this creature enters, draw a card. - */4" /></span> &amp; <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Young Pyromancer</span><img src="/images/cards/mtg/young-pyromancer.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Young Pyromancer {1}{R} - Creature — Human Shaman - Whenever you cast an instant or sorcery spell, create a 1/1 red Elemental creature token. - 2/1" /></span></p>
<h5 id="generic-aggro"><a href="#generic-aggro">Generic Aggro</a></h5>
<p>Take out expensive spells that you won’t have time to cast before dying. Feel free to take out one of each of a few things.</p>
<p>Bring in all the removal: burn spells, boardwipes. Remember that if your third noncreature spell is <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Brotherhood's End</span><img src="/images/cards/mtg/brotherhoods-end.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Brotherhood&#39;s End {1}{R}{R} - Sorcery - Choose one — • Brotherhood&#39;s End deals 3 damage to each creature and each planeswalker. • Destroy all artifacts with mana value 3 or less." /></span>, you could wipe their board and then get all your Phoenixes back in that same turn</p>
<h5 id="generic-combo"><a href="#generic-combo">Generic Combo</a></h5>
<p>Burn spells out</p>
<p>Counterspells in</p>
<h5 id="convoke-loxodon-hierarch-aggro"><a href="#convoke-loxodon-hierarch-aggro">Convoke / Loxodon Hierarch Aggro</a></h5>
<p>Burn and boardwipes in</p>
<p>Expensive spells out</p>
<hr />
<h3 id="conclusion"><a href="#conclusion">Conclusion</a></h3>
<p>Good luck!</p>
<hr />]]></description>
    <pubDate>Fri, 02 Jun 2023 00:00:00 UT</pubDate>
    <guid>https://nyuu.page/posts/2023-06-02-sideboarding-ur-phoenix/</guid>
    <dc:creator>nyuu</dc:creator>
</item>
<item>
    <title>Lengthen your web browser!</title>
    <link>https://nyuu.page/posts/2023-03-24-on-lengthening/</link>
    <description><![CDATA[<h2 id="tldr"><a href="#tldr">tl;dr</a></h2>
<p>Vertical space is better than horizontal space and you should guard it jealously.</p>
<p>Why it is better:</p>
<ul>
<li><p>Most experiences people have on computers don’t need much horizontal space</p></li>
<li><p>Most experiences people have on computers are <em>infinitely tall</em>.</p></li>
</ul>
<p>What you can do about it:</p>
<ul>
<li>Get <a href="https://addons.mozilla.org/en-US/firefox/addon/tree-style-tab/">treestyletab</a> <strong>and</strong> hide the horizontal tab bar.</li>
</ul>
<h3 id="on-configuration"><a href="#on-configuration">on configuration</a></h3>
<p>If your job is “using a computer”, you owe it to yourself to spend some time shaping your workspace into your ideal shape. If you routinely get annoyed at something in your workflow that you plausibly could configure your way into eliminating, you really should do that. Make computers do “tasks fit for computers”; don’t do them yourself on the computer’s behalf.</p>
<h3 id="on-browser-tabs"><a href="#on-browser-tabs">on browser tabs</a></h3>
<p>The browser tab was invented in 1998 for <a href="https://en.wikipedia.org/wiki/NetCaptor">SimulBrowse</a>.</p>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/note.webp" class="admonition-icon" alt="" width="128" height="128" />Note</span>
<div class="admonition-content">
<p>Installer found courtesy of <a href="https://browsers.evolt.org/">Evolt</a> (later renamed NetCaptor)</p>
</div>
</div>
<p>Tab behavior and presentation is nearly identical to now. SimulBrowse looked like this:</p>
<p><a href="/images/vertical-space/simulbrowse-3.webp" class="inset"><img src="/images/vertical-space/simulbrowse-3.webp" title="several tabs on http://gnu.org/ open in SimulBrowse 3.0.1" width="1920" height="1010" alt="several tabs on http://gnu.org/ open in SimulBrowse 3.0.1" /></a></p>
<p>The only significant difference between tab behavior then and now is: in the original version, the tab screen overflow behavior is “the tabs spill off of the side of the screen”. They don’t compress horizontally as you open more of them. You can look at different parts of the tab bar by clicking the <kbd>◂</kbd> and <kbd>▸</kbd> arrows found to the right of the tab bar:</p>
<p><a href="/images/vertical-space/simulbrowse-3-zoom.webp" class="gbc"><img src="/images/vertical-space/simulbrowse-3-zoom.webp" title="several tabs on http://gnu.org/ the tab navigation arrows in SimulBrowse 3.0.1" width="261" height="30" alt="several tabs on http://gnu.org/ the tab navigation arrows in SimulBrowse 3.0.1" /></a></p>
<p>No later than 2004—</p>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/note.webp" class="admonition-icon" alt="" width="128" height="128" />Note</span>
<div class="admonition-content">
<p>Which is way before most people started using tabs. the typical person probably started sometime around Firefox 2-3 (late 2006-early 2008) if they were ahead of the curve, or with the launch of Chrome (mid 2008) if they weren’t Into Browsers enough to have tried early Firefox. In other words, in short, for the overwhelming majority of people, tabs have never changed at all.</p>
</div>
</div>
<p>—the “tabs compress as you open more of them” behavior was invented. Firefox 1.0 (2004) has this; some earlier browser might also. “No later than 2004” is the last time the tab user experience has meaningfully changed. Two features of browsing that are poorly served by contemporary tabs:</p>
<ol type="1">
<li><p>Browsing is <em>hierarchical</em>; you start in one place and you carve a path through hyperlinks, possibly opening a few additional tabs from each page you visit. “Where you accessed something <em>from</em>” is a natural, useful signpost in keeping track of what you’re up to. The tab bar is flat, so it can’t capture this information.</p></li>
<li><p>Browsing is about <em>abundance</em>; you’ll probably open dozens of tabs in the course of doing anything deeper than cursory research. Doing so squishes the tabs or drives them offscreen or both; it’s difficult to have a decent quick reference of “what do I have open”.
Some examples:</p>
<ul>
<li><p><a href="/images/vertical-space/horiz-30ish.webp"><img src="/images/vertical-space/horiz-30ish.webp" title="thirtyish google chrome tabs" width="1914" height="66" alt="thirtyish google chrome tabs" /></a></p>
<p>Thirty tabs open in chrome: perhaps in the moment you can mostly keep track of what each thing is based on the favicon and first two letters and relative location on the bar?*</p></li>
<li><p><a href="/images/vertical-space/horiz-lots.webp"><img src="/images/vertical-space/horiz-lots.webp" title="fortyish google chrome tabs" width="1920" height="63" alt="fortyish google chrome tabs" /></a></p>
<p>Forty tabs: you get favicons and relative locations. nothing else</p></li>
</ul></li>
</ol>
<p>Lemma: the horizontal browser tab bar is a historical accident and doesn’t scale well with heavy use.</p>
<h3 id="on-horizontal-and-vertical-space"><a href="#on-horizontal-and-vertical-space">on horizontal and vertical space</a></h3>
<p>Vertical space is nearly arbitrarily valuable. Most of what people do on computers is browse endless feeds. How much feed you can skim at once is mostly bounded by how tall the viewport can be, which is bounded by the screen resolution minus any operating system and browser cruft.</p>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/note.webp" class="admonition-icon" alt="" width="128" height="128" />Note</span>
<div class="admonition-content">
<p>To take it a step further: how much you can skim at once is actually bounded by your eyeballs. Adding more pixels etc doesn’t help if you’re saturating your eye already.</p>
</div>
</div>
<p>The activities that <em>aren’t</em> browsing endless feeds are still mostly vertically constrained. Programmers generally limit themselves to 80ish characters per line, so any one view in their text editor or IDE doesn’t benefit from being any wider. File/project explorers and in-window terminals/debugger consoles can generally be moved to the sides if they aren’t already there by default.</p>
<p>Regardless of what you’re up to, giving yourself more vertical space to do it in will probably make the experience better.</p>
<p>Lemma: getting rid of the horizontal tab bar and repurposing its space might be nice.</p>
<p>Horizontal space is considerably less valuable. I see three reasons for this:</p>
<ul>
<li>Human horizontal vision is wider than the vertical vision.</li>
</ul>
<p>You can fit more things in it, so a unit amount of it is less precious.</p>
<ul>
<li>Many activities are chat apps. Chat apps are thirsty for vertical space and are borderline indifferent to horizontal space.</li>
</ul>
<p>Each message in a typical chat app is allocated at least one vertical “line” regardless of its length. The horizontal space of that line is filled with the message. If it’s a short message, the rest of the horizontal space is left unused. If the message is too long to fit on one line, it gets word-wrapped across however many lines it requires.</p>
<p>Most chat conversations word-wrap very well. Most of the messages are way shorter than one “typical screen-length line”, so there’s lots of unused space after the lines. Consider the following anonymized discord conversations, presented in portrait and landscape view.</p>
<p>One of these screenshots was taken on my landscape-oriented 1920x1200 monitor:</p>
<p><a href="/images/vertical-space/discord-horizontal.webp" class="inset"><img src="/images/vertical-space/discord-horizontal.webp" title="discord viewed in a horizontal window" width="1920" height="1152" alt="discord viewed in a horizontal window" /></a></p>
<p>The other on my (identical but rotated 90°) portrait-oriented 1200x1920 monitor:</p>
<p><a href="/images/vertical-space/discord-vertical.webp" class="inset"><img src="/images/vertical-space/discord-vertical.webp" title="discord viewed in a vertical window" width="1200" height="1920" alt="discord viewed in a vertical window" /></a></p>
<p>The latter is able to show about twice as many lines (use the black box present in both images as a landmark if you’d like to check) despite having the same pixel count. This is because it doesn’t have to spend tons of screen space on “the non-content between the end of the message and the right edge of the screen”.</p>
<ul>
<li>Activities that aren’t chat apps often limit themselves to relatively narrow widths and that’s probably for the best.</li>
</ul>
<p>If you have an ultrawide monitor you probably never open up a plaintext document in fullscreen with no wordwrap and then read the document using the entire monitor. That monitor is useful for multitasking and movies, but you would probably not display or read a book on that monitor as one giant window. It isn’t suited for “read from left to right, then at the end go all the way back to the left and down by one, then repeat”. The distance between the start and the end of the lines is too large for this to be a good experience so people don’t do it.</p>
<p>Websites figure you don’t want to do that and won’t let you. Below is an (anonymized) screenshot, this time of what I see when I visit twitter. This is as viewed on a typical 1920x1080 monitor:</p>
<p><a href="/images/vertical-space/twitter-horizontal-padding.webp" class="inset"><img src="/images/vertical-space/twitter-horizontal-padding.webp" title="twitter viewed in my web browser with the padding indicated in red and the content indicated in blue" width="1920" height="1080" alt="twitter viewed in my web browser with the padding indicated in red and the content indicated in blue" /></a></p>
<p><em>a third of the viewport is dedicated to horizontal padding!</em></p>
<p>Twitter doesn’t <em>want</em> you to view it in ultrawide. It responds to being fed more space by wasting more of it. It is pretty typical in this regard.</p>
<p>Reddit is an endless feed. Adding more horizontal resolution to the viewport doesn’t allow it to show you more posts since it can only show one post per row. Nor does it allow you to view more comments at once since reddit also softwraps the commments to ~100 characters per line. Reddit is, in effect, a SPA designed for very tiny screens. Most websites, static or not, follow similar design principles.</p>
<p>Lemma: a lot of people have horizontal regions of screen space that usually aren’t being used for anything in particular.</p>
<h3 id="thus-treestyletab"><a href="#thus-treestyletab">thus: treestyletab</a></h3>
<p>Check out my UI; it makes such elegant use of space by putting a tab <em>tree</em> in a sidebar and not having a tab bar at all:</p>
<p><a href="/images/vertical-space/my-ui.webp" class="inset"><img src="/images/vertical-space/my-ui.webp" title="firefox open to one of my reddit comments with the stock tab bar hidden and the treestyletab addon enabled" width="1920" height="1080" alt="firefox open to one of my reddit comments with the stock tab bar hidden and the treestyletab addon enabled" /></a></p>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/note.webp" class="admonition-icon" alt="" width="128" height="128" />Note</span>
<div class="admonition-content">
<p>Eschewing an address bar is a <em>bit</em> too radical for my tastes so “just browse in fullscreen mode” isn’t quite right. If I really want to hide the tree, <kbd>F1</kbd> toggles showing/hiding it.</p>
</div>
</div>
<p>Giving a <em>robust</em> tutorial for replicating this arrangement would involve writing <em>way</em> more, but the bullet point version is short. To get this UI, use <a href="https://www.mozilla.org/en-US/firefox/new/">Firefox</a>, with:</p>
<ul>
<li><p>the <a href="https://addons.mozilla.org/en-US/firefox/addon/tree-style-tab/">treestyletab</a> extension (provides the tree)</p></li>
<li><p>the <code>toolkit.legacyUserProfileCustomizations.stylesheets</code> flag enabled in <code>about:config</code> (makes it possible to hide the tab bar)</p>
<p>::: note
You’ll need to restart Firefox for this change to take effect. You’ll also need to restart for any changes in userChrome to take effect.
:::</p></li>
<li><p>the following rules in <code>{FirefoxProfileFolder}/chrome/userChrome.css</code> to actually hide the horizontal bar:</p>
<p>::: note
If you’re following along and can’t <em>find</em> the folder: go to <code>about:support</code> and check the entry for “Profile directory” for its location.
:::</p></li>
</ul>
<div class="sourceCode" id="cb1"><pre class="sourceCode css"><code class="sourceCode css"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="pp">#main-window</span><span class="ex">[</span><span class="ss">tabsintitlebar</span><span class="op">=</span><span class="st">&quot;true&quot;</span><span class="ex">]</span><span class="in">:not(</span><span class="ex">[</span><span class="ss">extradragspace</span><span class="op">=</span><span class="st">&quot;true&quot;</span><span class="ex">]</span><span class="in">)</span> <span class="pp">#TabsToolbar</span> <span class="op">&gt;</span> <span class="fu">.toolbar-items</span> {</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">opacity</span><span class="ch">:</span> <span class="dv">0</span><span class="op">;</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">pointer-events</span><span class="ch">:</span> <span class="dv">none</span><span class="op">;</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>}</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a><span class="pp">#main-window</span><span class="in">:not(</span><span class="ex">[</span><span class="ss">tabsintitlebar</span><span class="op">=</span><span class="st">&quot;true&quot;</span><span class="ex">]</span><span class="in">)</span> <span class="pp">#TabsToolbar</span> {</span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">visibility</span><span class="ch">:</span> <span class="dv">collapse</span> <span class="at">!important</span><span class="op">;</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>}</span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="pp">#sidebar-box</span><span class="ex">[</span><span class="ss">sidebarcommand</span><span class="op">=</span><span class="st">&quot;treestyletab_piro_sakura_ne_jp-sidebar-action&quot;</span><span class="ex">]</span> <span class="pp">#sidebar-header</span> {</span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>  <span class="kw">display</span><span class="ch">:</span> <span class="dv">none</span><span class="op">;</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<p>Most people use Chrome, which so far as I can tell doesn’t allow modifying the UI to hide the original tab bar. People have made <a href="https://chrome.google.com/webstore/detail/tree-style-tab/oicakdoenlelpjnkoljnaakdofplkgnd?hl=en">Chrome extensions</a> that supplement the bar with a shortcut-invokable tree <a href="/images/vertical-space/chrome-tst.webp">popup</a>, which isn’t what I’m used to, but has its own kind of charm. Regardless: consider demanding a better tab experience from your favorite browser. We can do better than The Bar.</p>
<hr />]]></description>
    <pubDate>Fri, 24 Mar 2023 00:00:00 UT</pubDate>
    <guid>https://nyuu.page/posts/2023-03-24-on-lengthening/</guid>
    <dc:creator>nyuu</dc:creator>
</item>
<item>
    <title>Magic has a linkrot problem</title>
    <link>https://nyuu.page/posts/2023-02-14-mtg-linkrot/</link>
    <description><![CDATA[<div class="dropcap dropcap-m">
<p>Magic and Magic-related websites have a problem: a lot of their links don’t work! In some cases, this is understandable. For example, “<a href="https://mtg.fandom.com/wiki/The_Dojo">the dojo</a>” has been defunct for twenty years, so it is perhaps unreasonable to be mad at them for the original link to “<a href="https://articles.starcitygames.com/articles/whos-the-beatdown/">who’s the beatdown</a>” breaking.</p>
</div>
<p>Other cases are harder to understand.</p>
<ul>
<li>In Magic Arena, in the shop, until <em>very recently</em>, the in-app link to the page on Wizards of the Coast’s site about pack droprates, was broken, and had been wrong for months. The link provided in Arena was <a href="https://magic.wizards.com/en/promotions/drop-rates">this one</a>; the information on the website was actualy <a href="https://magic.wizards.com/en/mtgarena/drop-rates">over here</a>.</li>
</ul>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/note.webp" class="admonition-icon" alt="" width="128" height="128" />Note</span>
<div class="admonition-content">
<p>These days, the in-app link works and points <a href="https://magic.wizards.com/en/mtgarena/drop-rates?utm_medium=product&amp;utm_source=arena">here</a></p>
</div>
</div>
<ul>
<li>On the Wizards of the Coast’s website, links to <em>other parts of the Wizards’s of the Cost website</em> sometimes don’t work. This <a href="https://magic.wizards.com/en/news/making-magic/four-hundred-and-counting-2009-09-25">list of articles</a> has an entry named</li>
</ul>
<blockquote>
<p>Week #397 (August 4, 2009) – “Designing for Johnny”</p>
</blockquote>
<p>The link points to <a href="https://magic.wizards.com/en/articles/archive/designing-johnny-2009-08-03">here</a>, which 404s. Searching for a working link via google didn’t go turn up anything. Searching via DuckDuckGo worked and turned up <a href="https://magic.wizards.com/en/news/making-magic/designing-johnny-2009-07-31">this</a>. So, at some point wotc changed their article url pattern from <code>/articles/archive/foo</code> to <code>/news/making-magic/foo</code>, but also changed the article publish date?</p>
<p>That article is pretty old, but, it’s not like its dead content or anything. Mark Rosewater’s posts link extensively to his older posts, which is why I ended up finding the above oddity. The big vendors do these site reorganizations that change the location (or remove entirely) older articles and then don’t update the links to those articles to match the new location. It’s pretty hit or miss whether the on-hover card images in a given article will work five years down the line.</p>
<p>It’d be nice if the community would stop migrating all its strategy discussions and resources into the unindexable Discord walled garden, too. I figure doing so is at least partially a response to “stuff on Magic websites is too impermanent”, but, Discord-hosted content can be fragile too and there’s less recourse if something goes wrong.</p>
<p>I’m not really sure what the solution here is. Maybe there could be a browser extension, where you give it a whitelist of websites, and on those sites if you try to access 404ed content, the extension Googles or DDGs for terms that <em>ought</em> to find a working link to the content, and serves up the search results, or seamlessly takes you to the first result.</p>]]></description>
    <pubDate>Tue, 14 Feb 2023 00:00:00 UT</pubDate>
    <guid>https://nyuu.page/posts/2023-02-14-mtg-linkrot/</guid>
    <dc:creator>nyuu</dc:creator>
</item>
<item>
    <title>Early ‘Pokemon Trading Card Game’ Design Review</title>
    <link>https://nyuu.page/posts/2023-02-13-early-pokemon/</link>
    <description><![CDATA[<div class="card-notice">
<p>☞ This post contains <span class="emoji"><img src="/images/emoji/2728.svg" class="emoji-img" draggable="false" alt="✨" /><span class="emoji-text" aria-hidden="true">✨</span></span>on-hover card images<span class="emoji"><img src="/images/emoji/2728.svg" class="emoji-img" draggable="false" alt="✨" /><span class="emoji-text" aria-hidden="true">✨</span></span>, indicated by the hanafuda symbol <span class="hanafuda"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span>, like so: <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Thalia, Guardian of Thraben</span><img src="/images/cards/mtg/thalia-guardian-of-thraben.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Thalia, Guardian of Thraben {1}{W} - Legendary Creature — Human Soldier - First strike Noncreature spells cost {1} more to cast. - 2/1" /></span> ☜</p>
<div class="card-notice-details">
<p>Alt text contains card data for screen readers.</p>
</div>
</div>
<div class="dropcap dropcap-o">
<p>One of the things I’m keeping score on when reviewing a game is, how many of its mechanics <em>matter</em> to someone playing to win? Let’s turn back the clock, to when the Pokemon Trading Card Game was first released in the US. How did it fare making its mechanics relevant to competitive players? I think it did badly; here’s why.</p>
</div>
<p>This post’s examples are (with one) about the first Pokemon set - the <a href="https://pkmncards.com/set/base-set/">Base Set</a> - exclusively. The base set was, for little while, the <em>only</em> set. A short while later, two more sets came out: <a href="https://bulbapedia.bulbagarden.net/wiki/Jungle_(TCG)">Jungle</a> and <a href="https://bulbapedia.bulbagarden.net/wiki/Fossil_(TCG)">Fossil</a>. These three were the cardpool for the first notable competitive format, <em>descriptively</em> named “BJF”, short for “Base/Jungle/Fossil”. It’s a bit weird to try to size up the base set on its own since it wasn’t played without Jungle or Fossil for <em>that</em> long. But the BJF sets are all fairly similar in terms of balance: trainers are strong; non-evolving pokemon are stong; other things are weak. The general design trends still hold, even if trivia like “what percentage of the cardpool is trainers” changes a bit when you bring Jungle and Fossil into the picture.</p>
<p>I am going to explain mechanics by alluding and comparing to what <em>Magic</em> does.</p>
<h3 id="game-design"><a href="#game-design">game design</a></h3>
<p>At the beginning, Pokemon had <a href="https://pkmncards.com/set/base-set/">one set</a>; the Base Set. We can look at its composition to make reasonable guesses about what the designers were thinking. If they emphasized a mechanic (featured on lots of cards, or rarer ones, or shinier and/or cooler ones, or it gets allocated a lot of the rules-space) then there’s a good chance they thought it was important.</p>
<p>It <em>looks</em> like the core mechanical selling point was supposed to be about a rising power level over the course of the game via the <em>evolution</em> mechanic. The way evolution works is, you can use later, stronger evolutionary stages of a given Pokemon, but fonly if you already have the unevolved form in play, and only if it has survived at its current stage for at least one turn already. Some Pokemon evolve no times, some once, and some twice. The cards have rarities; the packs they came in would come with more commons and fewer rares. Second-stage evolutions were pretty much exclusively found at the highest rarity and made up much of the rare pool. There were a few fancy, shiny foil-art cards; all of them Pokemon, most of them second-stage evolutions. The marketing I remember seeing as a kid was about getting to use evolution to play a <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Charizard</span><img src="/images/cards/pokemon/base1-4.webp" class="card-image" loading="eager" decoding="async" width="600" height="825" alt="Charizard - 120 HP - Fire - Energy Burn: As often as you like during your turn (before your attack), you may turn all Energy attached to Charizard into Fire Energy for the rest of the turn. This power can&#39;t be used if Charizard is Asleep, Confused, or Paralyzed. - Fire Spin [FireFireFireFire] 100: Discard 2 Energy cards attached to Charizard in order to use this attack. - Weakness: Water ×2" /></span>. Evolution is flavorful; it’s cool; it’s strategically <em>awful</em>.</p>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/note.webp" class="admonition-icon" alt="" width="128" height="128" />Note</span>
<div class="admonition-content">
<p>Evolution was bad at the time. It might be good now.</p>
</div>
</div>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/blobwizard.webp" class="admonition-icon" alt="" width="128" height="128" />Info</span>
<div class="admonition-content">
<p>Aside: the first set has 102 cards. The card-type breakdown is 69 Pokemon, 26, trainers, 7 energy. The trainers focus on lots of different mechanics. A mere two of them (<span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Devolution Spray</span><img src="/images/cards/pokemon/base1-72.webp" class="card-image" loading="eager" decoding="async" width="600" height="825" alt="Devolution Spray" /></span>, <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Pokémon Breeder</span><img src="/images/cards/pokemon/base1-76.webp" class="card-image" loading="eager" decoding="async" width="600" height="825" alt="Pokémon Breeder" /></span>) are “about” evolution and an additional handful could benefit evolution-based strategies but weren’t about them. It’d be fair to say trainers are not intended to be “about” evolution. Pokemon, however, are <strong>about evolution</strong>. 53/69<sup>(77%!)</sup> of them evolve or are evolved. Of the quarter that don’t have evolutions, a bunch gain them in Jungle and/or Fossil. This game is “about evolution”.</p>
</div>
</div>
<p>Evolution could be great if the evolved forms were sufficiently stronger (more health, more damage per energy, more raw damage) than the non-evolving Pokemon. They aren’t; evolving isn’t profitable. Your attacks get stronger, which is flashy and cool! But your attacks also get more expensive, which is a huge problem and makes it impossible to <em>actually do damage</em>.</p>
<p>An important idea in trading card games: over the course of the game, the amount of “swinginess” that happens in each turn should increase. The first turn should have puny little effects that represent tiny swings in “who is winning”. Later turns should have increasingly large effects &amp; so large swings in “who is winning and by how much”. Analogous maybe to the “material advantage” bars shown by chess apps? Most collectible card games have a mechanic meant to achieve this.</p>
<ul>
<li><p>Magic has “you need mana to cast spells. You get mana from lands. You can play one land per turn. Thus, you can do more expensive (and therefore stronger) things the longer the game goes on”.</p></li>
<li><p>Hearthstone has “you need mana to cast spells. You have a mana pool. It starts at one mana. Each turn, its capacity increases by one, and then it refills completely. So on turn one you can cast a one mana card. And you must wait until turn ten to can cast a ten mana card”.</p></li>
<li><p>Yu-Gi-Oh has the mechanic of “you need creatures to win. You can play one creature per turn. Larger creatures require you to sacrifice in-play creatures. So, large creatures cost cards and time.”</p></li>
<li><p>Pokemon has <em>energy</em> cards. You can play one energy per turn. Energy are attached to a specific Pokemon. To use an attack, you must have some minimum amount of energy. Stronger attacks generally have higher energy requirements.</p></li>
</ul>
<p>Destroying an energy in Pokemon is loosely analogous to destroying a land in Magic.</p>
<p>Roughly a quarter of every competitively viable early Pokemon deck consists of uncounterable zero-cost <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Stone Rain</span><img src="/images/cards/mtg/stone-rain.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Stone Rain {2}{R} - Sorcery - Destroy target land." /></span>s! Every sixty-card deck contains four of each of the following: <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Energy Removal</span><img src="/images/cards/pokemon/base1-92.webp" class="card-image" loading="eager" decoding="async" width="600" height="825" alt="Energy Removal" /></span> (destroy an energy), <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Super Energy Removal</span><img src="/images/cards/pokemon/base1-79.webp" class="card-image" loading="eager" decoding="async" width="600" height="825" alt="Super Energy Removal" /></span> (destroy <em>two</em> energy), <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Item Finder</span><img src="/images/cards/pokemon/base1-74.webp" class="card-image" loading="eager" decoding="async" width="600" height="825" alt="Item Finder" /></span> (graveyard recursion for your energy removals), and <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Computer Search</span><img src="/images/cards/pokemon/base1-71.webp" class="card-image" loading="eager" decoding="async" width="600" height="825" alt="Computer Search" /></span> (unconditional <a href="https://mtg.fandom.com/wiki/Tutor">tutor</a>/search library for whatever card you want; can find an energy removal).</p>
<p>We know that every viable deck runs the maximum allowed amount of the above cards, since blowing up your opponent’s resources is pretty much the strongest thing you can be doing. In fact: every viable deck has something like <em>thirty</em> cards (half of the deck!) in common with all other viable decks, since there are so many overwhelmingly generically powerful effects in the format.</p>
<p>Attacks must be cheap to be viable, since your opponent is going to be constantly destroying your energies. Attacks of evolved Pokemon are <em>expensive</em>; they’ll often cost three or four energy pips. Evolutions overall are too hard to get into play and too easy to end up unable to act due to lack of energy. The more reliable strategy is to pick from a shortlist of powerful non-evolving options: <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Hitmonchan</span><img src="/images/cards/pokemon/base1-7.webp" class="card-image" loading="eager" decoding="async" width="600" height="825" alt="Hitmonchan - 70 HP - Fighting - Jab [Fighting] 20:  - Special Punch [FightingFightingColorless] 40:  - Weakness: Psychic ×2" /></span> of <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Electabuzz</span><img src="/images/cards/pokemon/base1-20.webp" class="card-image" loading="eager" decoding="async" width="600" height="825" alt="Electabuzz - 70 HP - Lightning - Thundershock [Lightning] 10: Flip a coin. If heads, the Defending Pokémon is now Paralyzed. - Thunderpunch [LightningColorless] 30+: Flip a coin. If heads, this attack does 30 damage plus 10 more damage; if tails, this attack does 30 damage plus Electabuzz does 10 damage to itself. - Weakness: Fighting ×2" /></span> <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Mewtwo</span><img src="/images/cards/pokemon/base1-10.webp" class="card-image" loading="eager" decoding="async" width="600" height="825" alt="Mewtwo - 60 HP - Psychic - Psychic [PsychicColorless] 10+: Does 10 damage plus 10 more damage for each Energy card attached to the Defending Pokémon. - Barrier [PsychicPsychic]: Discard 1 Psychic Energy card attached to Mewtwo in order to prevent all effects of attacks, including damage, done to Mewtwo during your opponent&#39;s next turn. - Weakness: Psychic ×2" /></span> <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Chansey</span><img src="/images/cards/pokemon/base1-3.webp" class="card-image" loading="eager" decoding="async" width="600" height="825" alt="Chansey - 120 HP - Colorless - Scrunch [ColorlessColorless]: Flip a coin. If heads, prevent all damage done to Chansey during your opponent&#39;s next turn. (Any other effects of attacks still happen.) - Double-edge [ColorlessColorlessColorlessColorless] 80: Chansey does 80 damage to itself. - Weakness: Fighting ×2" /></span>. The next two sets, Jungle and Fossil, were designed similarly: they added many Pokemon, but the ones with competitive relevance continued to be efficient non-evolving Pokemon (<span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Moltres</span><img src="/images/cards/pokemon/base3-27.webp" class="card-image" loading="eager" decoding="async" width="600" height="825" alt="Moltres - 70 HP - Fire - Wildfire [Fire]: You may discard any number of Fire Energy cards attached to Moltres when you use this attack. If you do, discard that many cards from the top of your opponent&#39;s deck. - Dive Bomb [FireFireFireFire] 80: Flip a coin. If tails, this attack does nothing." /></span> <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Magmar</span><img src="/images/cards/pokemon/base3-39.webp" class="card-image" loading="eager" decoding="async" width="600" height="825" alt="Magmar - 70 HP - Fire - Smokescreen [Fire] 10: If the Defending Pokémon tries to attack during your opponent&#39;s next turn, your opponent flips a coin. If tails, that attack does nothing. - Smog [FireFire] 20: Flip a coin. If heads, the Defending Pokémon is now Poisoned. - Weakness: Water ×2" /></span>-<span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Scyther</span><img src="/images/cards/pokemon/base2-10.webp" class="card-image" loading="eager" decoding="async" width="600" height="825" alt="Scyther - 70 HP - Grass - Swords Dance [Grass]: During your next turn, Scyther&#39;s Slash attack&#39;s base damage is 60 instead of 30. - Slash [ColorlessColorlessColorless] 30:  - Weakness: Fire ×2" /></span> <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Mewtwo</span><img src="/images/cards/pokemon/base1-10.webp" class="card-image" loading="eager" decoding="async" width="600" height="825" alt="Mewtwo - 60 HP - Psychic - Psychic [PsychicColorless] 10+: Does 10 damage plus 10 more damage for each Energy card attached to the Defending Pokémon. - Barrier [PsychicPsychic]: Discard 1 Psychic Energy card attached to Mewtwo in order to prevent all effects of attacks, including damage, done to Mewtwo during your opponent&#39;s next turn. - Weakness: Psychic ×2" /></span>); The Jungle and Fossil additions didn’t change the “evolved is a really big downside” dynamic.</p>
<p>Pokemon had large competitive tournaments almost immediately after it was brought to the US. This is unusual for a new trading card game; it’s common for competitive support to emerge only later. In the case of Pokemon, this early competitive support means lots of people got to go to tournaments and experience playing against “a deck consisting of efficient non-evolving pokemon and energy destruction”!</p>
<p>Sometimes, a contemporary writer will try to cover “the early Pokemon trading card game’s metagame” and will list a few strategies. They’ll generally be left scrabbling to find strategies that <em>aren’t</em> “just use the efficient non-evolving ones”; they’ll likely mention the <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Blastoise</span><img src="/images/cards/pokemon/base1-2.webp" class="card-image" loading="eager" decoding="async" width="600" height="825" alt="Blastoise - 100 HP - Water - Rain Dance: As often as you like during your turn (before your attack), you may attach 1 Water Energy card to 1 of your Water Pokémon. (This doesn&#39;t use up your 1 Energy card attachment for the turn.) This power can&#39;t be used if Blastoise is Asleep, Confused, or Paralyzed. - Hydro Pump [WaterWaterWater] 40+: Does 40 damage plus 10 more damage for each Water Energy attached to Blastoise but not used to pay for this attack&#39;s Energy cost. Extra Water Energy after the 2nd doesn&#39;t count. - Weakness: Lightning ×2" /></span>/Rain Dance strategy, <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Wigglytuff</span><img src="/images/cards/pokemon/base2-16.webp" class="card-image" loading="eager" decoding="async" width="600" height="825" alt="Wigglytuff - 80 HP - Colorless - Lullaby [Colorless]: The Defending Pokémon is now Asleep. - Do the Wave [ColorlessColorlessColorless] 10+: Does 10 damage plus 10 more damage for each of your Benched Pokémon. - Weakness: Fighting ×2" /></span>/“Do the Wave”, and if they’re especially good researchers then they may talk about Moltres + Chansey Stall/Mill. The latter two archetypes are pretty good, too. Rain Dance is rather bad, though. <em>Back in the late 90s</em>, people hadn’t figured this out, so contemporaneous sources would talk about it being good. It turns out, “being able to play as many energy as you can access, <em>if</em> you can evolve”, is a fragile strategy! You might not find your combo pieces. You might get forced to start the game with just a <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Squirtle</span><img src="/images/cards/pokemon/base1-63.webp" class="card-image" loading="eager" decoding="async" width="600" height="825" alt="Squirtle - 40 HP - Water - Bubble [Water] 10: Flip a coin. If heads, the Defending Pokémon is now Paralyzed. - Withdraw [WaterColorless]: Flip a coin. If heads, prevent all damage done to Squirtle during your opponent&#39;s next turn. (Any other effects of attacks still happen.) - Weakness: Lightning ×2" /></span>; you plausibly get one-turn killed by a <em>lot</em> of unevolved-pokemon-deck’s opening hands in this situation.</p>
<p>For the curious, there are <a href="https://jklaczPokemon.com/">strategic resources</a> out there specifically about the earliest Pokemon formats. There is a very cool <a href="https://discord.gg/hqRmAb6h">Discord server</a>, also focused on retro Pokemon formats, particularly base-jungle-fossil. If you aren’t put off by the strong non-evolving Pokemon and the rampant land destruction, you actually can play this (twenty years out of date!) format, in paper, via webcam, on that server. It’s part of a recent broader trend of forming communities for webcam-based play for older or less accessible trading card game formats. There’s one for <a href="https://discord.gg/np5CFwh">legacy Magic</a>, too.</p>
<h2 id="conclusion"><a href="#conclusion">conclusion</a></h2>
<p>Parting thought: check out my BJF decks! The discord server I mentioned in the previous paragraphs holds monthly tournaments; the registration process involves submitting a decklist via taking a picture of your deck all splayed out. These pictures were taken for that purpose.</p>
<p>In cases where I didn’t have a desired card in time for the deck registration photo but expected I’d have it in time for my actual matches, I sometimes used proxies. So there are a few obvious “fakes” in these. I still think they’re cool, though:</p>
<figure>
<img src="/images/pkmn-history/pkmndeck1.webp" width="1280" height="960" alt="haymaker" />
<figcaption aria-hidden="true">haymaker</figcaption>
</figure>
<figure>
<img src="/images/pkmn-history/pkmndeck2.webp" width="1280" height="960" alt="rain dance" />
<figcaption aria-hidden="true">rain dance</figcaption>
</figure>
<figure>
<img src="/images/pkmn-history/pkmndeck3.webp" width="4048" height="3036" alt="stall" />
<figcaption aria-hidden="true">stall</figcaption>
</figure>]]></description>
    <pubDate>Mon, 13 Feb 2023 00:00:00 UT</pubDate>
    <guid>https://nyuu.page/posts/2023-02-13-early-pokemon/</guid>
    <dc:creator>nyuu</dc:creator>
</item>
<item>
    <title>Early Yu-Gi-Oh! Was Weird</title>
    <link>https://nyuu.page/posts/2023-02-12-early-yugioh/</link>
    <description><![CDATA[<div class="card-notice">
<p>☞ This post contains <span class="emoji"><img src="/images/emoji/2728.svg" class="emoji-img" draggable="false" alt="✨" /><span class="emoji-text" aria-hidden="true">✨</span></span>on-hover card images<span class="emoji"><img src="/images/emoji/2728.svg" class="emoji-img" draggable="false" alt="✨" /><span class="emoji-text" aria-hidden="true">✨</span></span>, indicated by the hanafuda symbol <span class="hanafuda"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span>, like so: <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Thalia, Guardian of Thraben</span><img src="/images/cards/mtg/thalia-guardian-of-thraben.jpg" class="card-image" loading="eager" decoding="async" width="488" height="680" alt="Thalia, Guardian of Thraben {1}{W} - Legendary Creature — Human Soldier - First strike Noncreature spells cost {1} more to cast. - 2/1" /></span> ☜</p>
<div class="card-notice-details">
<p>Alt text contains card data for screen readers.</p>
</div>
</div>
<div class="dropcap dropcap-i">
<p>I am a huge fan of card games, in general. The one that has held the lion’s share of my time and mindshare is <em><a href="https://en.wikipedia.org/wiki/Magic:_The_Gathering">Magic</a></em>, <a href="https://magic.wizards.com/en/formats/legacy">legacy</a>-format Magic in particular. I will eventually put down my thoughts on how to win at Magic, but this is not that post.</p>
</div>
<p>I was born a <em>bit</em> too late to play Magic on-release. I was one year old at the time, so, I probably wouldn’t have had the dexterity needed to shuffle effectively. I was born at just the right time to catch the beginning of some other card games, though: Pokemon and Yu-Gi-Oh. This post is about localization trivia about the latter.</p>
<p>This post is about the “<a href="https://www.formatlibrary.com/formats/yugi-kaiba">Yugi-Kaiba Format</a>”. Many of the rough edges discussed aren’t true anymore, and some of them stopped being true very quickly.</p>
<p>I am going to explain mechanics by alluding and comparing to what <em>Magic</em> does.</p>
<h3 id="the-manga"><a href="#the-manga">the manga</a></h3>
<p>Yu-Gi-Oh is a card game, based on an arc from <a href="https://en.wikipedia.org/wiki/Yu-Gi-Oh!">a manga</a> also titled Yu-Gi-Oh. The plot of every early Yu-Gi-Oh chapter is as follows:</p>
<ol type="1">
<li><p>Introduce someone comically evil. Evil person threatens Yugi (the protagonist) and/or his friends</p></li>
<li><p>Introduce a game. Yugi and the evil person play that game with life or death stakes</p></li>
<li><p>Yugi wins; his opponent is driven insane or <a href="/images/ygo-history/literally-dies.webp">dies</a></p></li>
</ol>
<p>In Yu-Gi-Oh (the manga), one of the games in one of the arcs is called “Duel Monsters”.</p>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/blobwizard.webp" class="admonition-icon" alt="" width="128" height="128" />Info</span>
<div class="admonition-content">
<p>Duel Monsters is, in some early material, referred to by the less catchy name “Magic and Wizards”.</p>
</div>
</div>
<p>It didn’t have fleshed-out rules since it did not exist outside of the story, and the story isn’t <em>really</em> about Duel Monsters’ mechanical details. Yu-Gi-Oh (the card game) is based on Duel Monsters. The card game was produced by … <span class="emoji"><img src="/images/emoji/1f941.svg" class="emoji-img" draggable="false" alt="🥁" /><span class="emoji-text" aria-hidden="true">🥁</span></span>… <em>Konami</em>, a famous Japanese game publishing company.</p>
<h3 id="konami"><a href="#konami">konami</a></h3>
<p>Konami has some to-my-knowledge uniquely terrible labor practices<sup><a href="https://kotaku.com/report-konami-is-treating-its-staff-like-prisoners-1721700073">1</a> <a href="https://www.pcmag.com/news/konami-is-making-life-difficult-for-former-employees">2</a> <a href="https://twitter.com/ultimashadowx/status/1173622658354831361?lang=en">3</a></sup>! One of these practices is this one-two punch:</p>
<ul>
<li><p>not crediting artists for their work on card illustrations</p></li>
<li><p>requiring all artists to sign NDAs! artists are not allowed to take credit for their work in any way</p></li>
</ul>
<p>The “vibe” is, “by fiat, this game is a black-box created by Konami<span class="emoji"><img src="/images/emoji/2122.svg" class="emoji-img" draggable="false" alt="™" /><span class="emoji-text" aria-hidden="true">™</span></span>. it does not contain artistic flourishes or influences by individuals.” This sort of a labor culture is not conducive to getting much primary source material about what working on the game was like, and why a design decision was made, which is a shame. There’s a wealth of information out there about how <em>Magic</em> is made now &amp; how it was made <a href="https://www.Magiclibrarities.net/955-rarities-alpha-beta-gamma-playtest-cards-english-cards-index.html">in the past</a>. I’m told some similar resources exist for Pokemon, though I don’t know this for sure.</p>
<h3 id="jargon"><a href="#jargon">jargon</a></h3>
<p>Like many games, Yu-Gi-Oh has a bunch of jargon for its game concepts - kinds of cards, parts of cards, parts of turns, etc.</p>
<p>Yu-Gi-Oh lifted a lot of its gameplay elements from Magic one-to-one and just gave them a new, slightly different name. Examples:</p>
<ul>
<li><p>Power ⇒ Attack</p></li>
<li><p>Combat ⇒ The Battle Step</p></li>
<li><p>Upkeep ⇒ Standby</p></li>
<li><p>Sacrifice ⇒ Tribute</p></li>
</ul>
<p>They mostly did a thorough job of not 1:1 using Magic jargon. Except for how they named one of their card types: “Magic card”. <em>Weird oversight!</em> This was later retconned or renamed or amended to “Spell card”. It’d be cool to know what the deal is with this, but, due to how Konami’s implicit position is that the game does not have artists or a development process, probably we will never know.</p>
<h3 id="relevant-game-mechanics"><a href="#relevant-game-mechanics">relevant game mechanics</a></h3>
<p>I am going to explain mechanics by alluding and comparing to what <em>Magic</em> does.</p>
<p>Quoting myself in <a href="/posts/2023-02-13-early-pokemon/">“Pokemon Trading Card Game” design review</a>:</p>
<blockquote>
<p>An important idea in trading card games: over the course of the game, the amount of “swinginess” that happens in each turn should increase. The first turn should have puny little effects that represent tiny swings in “who is winning”. Later turns should have increasingly large effects &amp; so large swings in “who is winning and by how much”. Analogous maybe to the “material advantage” bars shown by chess apps? Most collectible card games have a mechanic meant to achieve this.</p>
</blockquote>
<blockquote>
<p>Yu-Gi-Oh has the mechanic of “you need creatures to win. You can play one creature per turn. Larger creatures require you to sacrifice in-play creatures. So, large creatures cost cards and time.”</p>
</blockquote>
<p>Yu-Gi-Oh doesn’t have mana. Most cards can be cast for free; the main resource, so far as I can tell, is card advantage. The pace / swinginess of the game is mediated by “normal summoning” and “stars”.</p>
<ul>
<li><p>Normal summoning: you can play no more than one creature per turn. Loosely analogous to how in Magic you can play only one land per turn. Much like Magic’s land drops, there are ways to get around this “one per turn” limitation &amp; play more creatures.</p></li>
<li><p>Stars: some creatures have a sort of psuedo mana-cost. Each creature has an immutable stat, its amount of “stars”. Things with a lot of stars are, (and these are the only game objects this is true of), not free. They cost “sacrificing some number of creatures”! Here is a list explaining what star counts correspond to what additional costs:</p>
<ul>
<li><p>1★ to 4★: no additonal cost!</p></li>
<li><p>5★ to 6★: one sacrifice</p></li>
<li><p>7★ to 8★: two sacrifices</p></li>
</ul></li>
</ul>
<p>Observations:</p>
<ul>
<li><p>There are three “tiers” of starriness, based on how how many sacrifices it costs to play the thing. You might expect there to be <em>some sort</em> of a functional distinction between, for example a 1★ and 4★, even if they both can be played for free. There is no such distinction. For all rules purposes a 1★ and a 4★ are exactly the same. <em>weird</em>! The cards in the manga have stars on them, roughly indicating how strong they are but otherwise having no associated mechanics. That’s why there are so many star amounts; they were flavor that had to be retrofitted to make them do <em>something</em> in an actual game.</p></li>
<li><p>I did a little bit of a fib when I wrote the above “stars to costs” table. On actual Yu-Gi-Oh cards, the stars are not represented by putting, e.g., “8★” on the card somewhere. Having 8 stars is represented by displaying 8 ★ symbols in a row. Humans can’t easily <a href="https://en.m.wikipedia.org/wiki/Subitizing">subitize</a> past <em>four</em> of something, so, figuring out how many stars something has by <em>reading the card</em> is a pain in the ass.</p>
<p>In light of this, I’m going to redraw the “star to costs” list now, but this time I’m going to template it the way actual Yu-Gi-Oh cards present this information. I hear these days they’ve added creatures that have even more than 8 ★, so, good luck with that:</p>
<ul>
<li><p>★ to ★★★★: no additonal cost!</p></li>
<li><p>★★★★★ to ★★★★★★: one sacrifice</p></li>
<li><p>★★★★★★★ to ★★★★★★★★: two sacrifices</p></li>
</ul></li>
</ul>
<p>Got it? Good!</p>
<ul>
<li>Wow! “two sacrifices”!? Those are some <strong>steep</strong> costs. You’re committing an extra <em>two cards and two turns worth of summons</em>, to cast your big shiny 7-star thing. There is no way this could be worthwhile to do. On one hand, a big expensive creature could be valuable if it sticks around for more than a turn. It might get to attack many times and so destroy several opposing creatures, which would be value, card advantage, etc. On the other hand, there are lots of 0-cost spells that basically read “destroy target creature”, so, the expensive creature won’t be able to do this.</li>
</ul>
<h3 id="localization"><a href="#localization">localization</a></h3>
<p>Yu-Gi-Oh’s first English-localized set is titled “Legend of Blue Eyes White Dragon”. I am going to refer to it as “E1”. When I talk about the first Japanese set (whose official name is “Vol.1”), I’ll be referring to it as “J1”. J1 and E1 are radically different.</p>
<p>E1’s <a href="https://yugioh.fandom.com/wiki/Set_Card_Galleries:Legend_of_Blue_Eyes_White_Dragon_(TCG-EN-UE)">contents</a> don’t make much sense. It has 126 cards, here is their type breakdown:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a>╿ <span class="dv">126</span> cards</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>├─╮ <span class="dv">87</span> creatures</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>│ ╰─╮</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>│   ├─╮<span class="dv">72</span> vanilla</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>│   │ ╰─╮</span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>│   │   ├╼ <span class="dv">60</span> <span class="dv">1</span>★ to <span class="dv">4</span>★</span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>│   │   ├╼ <span class="dv">6</span>  <span class="dv">5</span>★ to <span class="dv">6</span>★</span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>│   │   ╰╼ <span class="dv">6</span>  <span class="dv">7</span>★ to <span class="dv">8</span>★</span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>│   ├╼ <span class="dv">1</span> <span class="st">&quot;effect&quot;</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>│   ├╼ <span class="dv">4</span> <span class="st">&quot;flip effect&quot;</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>│   ╰─╮<span class="dv">10</span> <span class="st">&quot;fusion&quot;</span></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a>│     ╰─╮</span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a>│       ├╼ <span class="dv">6</span> <span class="dv">1</span>★ to <span class="dv">4</span>★</span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a>│       ├╼ <span class="dv">3</span> <span class="dv">5</span>★ to <span class="dv">6</span>★</span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a>│       ╰╼ <span class="dv">1</span> <span class="dv">7</span>★ to <span class="dv">8</span>★</span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a>├─╮ <span class="dv">36</span> spells</span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a>│ ╰─╮</span>
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a>│   ├╼ <span class="dv">15</span> <span class="st">&quot;normal&quot;</span></span>
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a>│   ├╼ <span class="dv">15</span> <span class="st">&quot;equip&quot;</span></span>
<span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a>│   ╰╼ <span class="dv">6</span> <span class="st">&quot;field&quot;</span></span>
<span id="cb1-21"><a href="#cb1-21" aria-hidden="true" tabindex="-1"></a>╰─╮ <span class="dv">3</span> traps</span>
<span id="cb1-22"><a href="#cb1-22" aria-hidden="true" tabindex="-1"></a>  ╰─╮</span>
<span id="cb1-23"><a href="#cb1-23" aria-hidden="true" tabindex="-1"></a>    ├╼ <span class="dv">2</span> <span class="st">&quot;normal&quot;</span></span>
<span id="cb1-24"><a href="#cb1-24" aria-hidden="true" tabindex="-1"></a>    ╰╼ <span class="dv">1</span> <span class="st">&quot;continuous&quot;</span></span></code></pre></div>
<p><em>I manually sorted the cards into these buckets to make the chart. I think visualizations like this are cool; I think it’s a shame there aren’t better automated tools for querying stuff like this.</em></p>
<p><strong>mechanical oddities</strong>:</p>
<ul>
<li><p>Stars (★) use an 8-point scale to represent a total of three possible states (“costs 0 sacrifices”, “costs 1 sacrifice”, “costs 2 sacrifices”).</p></li>
<li><p>Half the set consists of zero-cost <a href="https://mtg.fandom.com/wiki/Vanilla">vanilla</a> creatures. They come three flavors:</p>
<ol type="1">
<li><p>their attack/defense are roughly <span class="emoji"><img src="/images/emoji/2694.svg" class="emoji-img" draggable="false" alt="⚔" /><span class="emoji-text" aria-hidden="true">⚔</span></span>100/<span class="emoji"><img src="/images/emoji/1f6e1.svg" class="emoji-img" draggable="false" alt="🛡" /><span class="emoji-text" aria-hidden="true">🛡</span></span>100</p></li>
<li><p>their attack/defense are roughly <span class="emoji"><img src="/images/emoji/2694.svg" class="emoji-img" draggable="false" alt="⚔" /><span class="emoji-text" aria-hidden="true">⚔</span></span>0/<span class="emoji"><img src="/images/emoji/1f6e1.svg" class="emoji-img" draggable="false" alt="🛡" /><span class="emoji-text" aria-hidden="true">🛡</span></span>2000</p></li>
<li><p>and “their attack/defense are roughly <span class="emoji"><img src="/images/emoji/2694.svg" class="emoji-img" draggable="false" alt="⚔" /><span class="emoji-text" aria-hidden="true">⚔</span></span>1500/<span class="emoji"><img src="/images/emoji/1f6e1.svg" class="emoji-img" draggable="false" alt="🛡" /><span class="emoji-text" aria-hidden="true">🛡</span></span>1500</p></li>
</ol>
<p>It is weird that they want to spend sixty creatures worth of space in the set on expressing what are basically three ideas, especially since #1 is so underpowered nobody would want to use it.</p></li>
<li><p>About 10% of the creatures are “fusions”. Fusion is a mechanic where you can summon specific creatures from out of your sideboard &amp; without it costing you your summon for that turn. To do this, you cast a specific spell, <span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Polymerization</span><img src="/images/cards/yugioh/24094653.jpg" class="card-image" loading="eager" decoding="async" width="813" height="1185" alt="Polymerization - Spell Card (Normal) - Fusion Summon 1 Fusion Monster from your Extra Deck, using monsters from your hand or field as Fusion Material." /></span>, and sacrifice-or-discard two specific (as in, each fusion card lists exactly two other cards it is fused out of) other monsters as “fusion material”. <em>Wow! Those are some steep costs</em>. You’re committing <strong>three</strong> specific cards to do this, you need to find all three of them, one of those cards does nothing on its own, and the other two have no particular selling point other than that they can be used for this.</p>
<p>If you get a fusion out of a pack, you can’t use it unless you own the other three cards. If you get <em>any</em> fusion, you can’t use it without a polymerization. Polymerization is at one of the higher rarities; there is no particular reason you would expect to own it unless you went out and bought it third-party, which at this point is done out of mail-order magazines.</p>
<p>Fusions aren’t meaningfully stronger than their component material. They’re <em>slightly</em> stronger than their components, but the components are often really bad. You can often play stronger things of a given cost <em>for free</em>.</p></li>
</ul>
<p>Much of the strangeness is downstream of how E1 is not “an english translation of the first Japanese set”. E1 is “assorted cards sourced from various sets printed in the first year and a half of the Japanese game”. And during the timeframe those sets were printed in, there was a <em>fuckton</em> of power creep.</p>
<p>The first <a href="https://yugioh.fandom.com/wiki/Vol.1">Japanese set</a> comes out in January of ’99. Sets continue to come out at a rate of about one per month. Which might sound <em>deliriously quick</em> to someone used to the Magic standard-legal set release schedule, but, these sets are <em>small</em>; 40-50 cards small. They’re also fairly reprint heavy.</p>
<ul>
<li>Fusion: The first set’s creatures are all vanilla. The second set introduces the first “not a vanilla creature” creature idea: <em>fusion</em>. Why does fusion get away with requiring you own a suite of four cards? Because it was way more plausible that “every player that wants this card, has it” when there are a total of like fifty unique cards in your game. Why does the mechanic seem sort of weird and weak? It was in the manga; they didn’t want to deviate from how it worked in the source material <em>too</em> much. It just, is not a very strong mechanic.</li>
</ul>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/note.webp" class="admonition-icon" alt="" width="128" height="128" />Note</span>
<div class="admonition-content">
<p>I am a bit curious about just how much each of these early sets overlaps with the other ones. The information is out there but it I don’t think anyone has actually analyzed it in this way. For that matter: I don’t think there are any tools quite on Scryfall’s level, here.</p>
</div>
</div>
<p>Regardless: Japanese Yu-Gi-Oh got lots of new sets over next few years. One of these <a href="https://yugioh.fandom.com/wiki/Phantom_God">sets</a> came out in August of ’00. E1’s cards were sourced from Japense sets released between January ’99 and August ’00. That’s <a href="/images/ygo-history/ocg-set-dates.webp">a year and six months</a> and probably twenty or so sets and a few hundred cards.</p>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/note.webp" class="admonition-icon" alt="" width="128" height="128" />Note</span>
<div class="admonition-content">
<p>Checking the exact number of sets is hard, due to the aforementioned lack of good tools</p>
</div>
</div>
<ul>
<li>J1’s strongest 4★ has an attack of <span class="emoji"><img src="/images/emoji/2694.svg" class="emoji-img" draggable="false" alt="⚔" /><span class="emoji-text" aria-hidden="true">⚔</span></span>1200. The set contains three <span class="emoji"><img src="/images/emoji/2694.svg" class="emoji-img" draggable="false" alt="⚔" /><span class="emoji-text" aria-hidden="true">⚔</span></span>1200 creatures. J1 had exactly one 4★; the limited cardpool forced you to include some 3★s and probably some 2 and/or 1★s also. The player probably does not have the ability to field playsets of all the <span class="emoji"><img src="/images/emoji/2694.svg" class="emoji-img" draggable="false" alt="⚔" /><span class="emoji-text" aria-hidden="true">⚔</span></span>1200 creatures <em>anyway</em> since there are no card shops or vendors other than “the vending machine the packs come from”.</li>
</ul>
<p>By the time all the sets drawn on in E1 set had come out, the power level for a ≤5★ had risen <em>considerably</em>, in terms of how strong the individual options were, and in how many options existed. You no longer had to include a bunch of bad stuff just to reach the deck size requirement.</p>
<p>As for how the cards <em>selected for inclusion in E1</em> were selected: my best guess is that the localizers were selecting for iconic-ness and for hitting a target amount of cards at each amount of ★s, even though at this point 1★ 2★ and 3★ were now basically design relics rather than meaningful content in their own right. The same is probably true of the fusions. It certainly wasn’t done to improve the play experience or average competitive relevance of a typical pack.</p>
<ul>
<li>The names on the cards are weird: this was often done in localization &amp; not present on the originals!
<span class="card-preview"><span class="hanafuda" aria-hidden="true"><span class="emoji"><img src="/images/emoji/1f3b4.svg" class="emoji-img" draggable="false" alt="🎴" /><span class="emoji-text" aria-hidden="true">🎴</span></span></span><span class="card-name">Steel Ogre Grotto #1</span><img src="/images/cards/yugioh/29172562.jpg" class="card-image" loading="eager" decoding="async" width="813" height="1185" alt="Steel Ogre Grotto #1 - Normal Monster (Machine) [EARTH] - Level 5 - ATK 1400 / DEF 1800 - A steel idol worshipped in the Land of Machines." /></span>’s name in Japanese is
<span lang="ja"><ruby>鋼<rt>こう</rt></ruby><ruby>鉄<rt>てつ</rt></ruby>の<ruby>巨<rt>きょ</rt></ruby><ruby>神<rt>しん</rt></ruby><ruby>像<rt>ぞう</rt></ruby></span>, or Kōtetsu no Kyoshinzō, or “Giant Idol of Steel”. Very sensible! In english we get a silly name. Another card in a later set gets renamed from “Iron-Fist Golem” to “Steel Ogre Grotto #2” to make sure the numbering isn’t done in vain. Baffling. I don’t really have a take on why this was done; I just think it’s interesting and would be easy for a casual observer to miss.</li>
</ul>
<h3 id="conclusion"><a href="#conclusion">conclusion</a></h3>
<p>Making a game is really hard.</p>
<hr />
<h3 id="resources"><a href="#resources">resources</a></h3>
<p><a href="https://www.formatlibrary.com/formats/">Format Library</a> is a cool resource.</p>
<p><a href="https://www.goatformat.com/">Goat Format</a> is the most popular retro format.</p>]]></description>
    <pubDate>Sun, 12 Feb 2023 00:00:00 UT</pubDate>
    <guid>https://nyuu.page/posts/2023-02-12-early-yugioh/</guid>
    <dc:creator>nyuu</dc:creator>
</item>
<item>
    <title>How to make browsing fandom.com not suck</title>
    <link>https://nyuu.page/posts/2023-02-10-fandom/</link>
    <description><![CDATA[<h2 id="tldr"><a href="#tldr">tl;dr</a></h2>
<p>Fandom.com’s ads are egregious and their business strategy means they’re the top—and often the most convenient—result for most media property related searches. Your options are to use e.g. <a href="https://ublockorigin.com/">ublock origin</a> to block annoying page elements, or to use a wrapper service like those made easy to use by <a href="https://getindie.wiki/">Indie Wiki Buddy</a> to handle this hiding for you.</p>
<p>If you want to go the ublock route, filters for the extension are created like so:</p>
<video controls width="100%" style="max-width: 600px;">
  <source src="/images/fandom-post/howtofilter.webm" type="video/webm">
  <p><a href="/images/fandom-post/howtofilter.webm">Download video: how to create ublock filters</a></p>
</video>
<p>Use filters that are something like this:</p>
<pre class="text"><code>! 2023-02-10 fandom.com
fandom.com##.global-navigation
fandom.com##.WikiaRail.right-rail-wrapper
fandom.com##.mcf-wrapper
fandom.com##.global-footer
fandom.com##.page__right-rail
fandom.com##.render-wiki-recommendations &gt; div
! 2023-02-12 fandom.com
fandom.com###WikiaBar
fandom.com##.is-visible.fandom-sticky-header
fandom.com##.marketing-notifications
fandom.com##.page-footer
! 2023-02-12 fandom.com mobile-specific
fandom.com##.recirculation-prefooter
fandom.com##.article-footer</code></pre>
<h2 id="ehow"><a href="#ehow">eHow</a></h2>
<p><a href="https://en.wikipedia.org/wiki/Content_farm">Content farming</a> is as old as dirt. Getting on lots of high-ranking search results at low cost is a winning strategy for getting lots of ad views. So, the thinking is, users might <em>like</em> it if you spend lots on making the site great, but their liking it doesn’t bring in ad money commesurate to the effort. So, the farmer wants to make their content as cheaply as possible; the content being <em>useful</em> is but unnecessary. So you pay people <a href="https://server.moneysavingmom.com/how-to-make-money-writing-for-ehow-com/">$15 an article</a> to write articles like “<a href="https://worstofehow.wordpress.com/2011/01/01/how-to-put-on-a-speedo/">How to Put on a Speedo</a>” and Google dutifully rewards you with the top result for <code>🔎 » "how to put on speedo"</code>.</p>
<p>In this way, for a few years, eHow took over google search results, and mass-producing content-for-eHow became a semi-popular form of online menial labor. This was until <a href="https://en.wikipedia.org/wiki/Google_Panda">about a decade ago</a>. Today’s search result quality problems are a bit more subtle than yesteryear’s “Google=eHow”. Drowning the world in content nobody wanted to read or to write <em>might work</em> but it’s a lot harder to make it work when your host is trying to discourage that sort of thing.</p>
<h2 id="fandom-dot-inc"><a href="#fandom-dot-inc">Fandom dot inc</a></h2>
<p><a href="https://www.fandom.com/">Fandom</a> (né-wikia) is a wiki hosting service. It was cofounded by Jimmy Wales (of <em>Wikipedia</em> fame). It has been <em>aggressive</em> about acquiring other wiki hosting services. You’ve probably seen one of their holdings in the results if you’ve ever searched about a popular media franchise.</p>
<p>I think their overall strategy is shaped pretty similarly to eHow’s: as cheaply as possible be the top search result for as many questions as possible. Though these questions are trivia like <code>🔎 » "what country is bandit keith from"</code> rather than tutoral questions like the aforementioned <code>🔎 » "how to put on speedo"</code>. The content is even made for free by enthusiasts, which is a pretty sick deal. None of this is a <em>problem</em>; it’s a pretty clever business to be in!</p>
<div class="admonition" style="--adm-bg: #304f60; --adm-border: #007acc" role="note">
<span class="admonition-title"><img src="/images/icons/blobwizard.webp" class="admonition-icon" alt="" width="128" height="128" />Info</span>
<div class="admonition-content">
<p>The <a href="https://www.google.com/search?client=firefox-b-1-d&amp;q=what+country+is+bandit+keith+from">google infobox</a> currently gets this <a href="/images/fandom-post/bandit-keith.webp">wrong</a> due to how the “abridged series” fanwork gets this wrong as a joke, and that fanwork has a wiki.</p>
</div>
</div>
<p>The thing is, Fandom uses <em>hella</em> advertising on its pages. The user experience on their pages is <em>terrible</em>. Look at this nonsense:</p>
<div class="comparison">
<figure>
<img src="/images/fandom-post/full-nofilter.webp" width="1668" height="7398" alt="No adblock in use" />
<figcaption>No adblock</figcaption>
</figure>
<figure>
<img src="/images/fandom-post/full-nofilter-emphasis.webp" width="1668" height="7398" alt="Demonstration of how much screen area is wasted on cruft and ads" />
<figcaption>The green areas are the content</figcaption>
</figure>
</div>
<p>The first image is a full-page screenshot of a page on a fandom wiki as its owners intend it to be seen. The second image is a map of the <em>content</em> on that page. The green is content, the black is advertisements and cruft. You really should use an adblocker. Even <a href="https://www.ic3.gov/Media/Y2022/PSA221221?=8324278624">the FBI</a>’s position on this is “you, the user, should use an adblocker when going online”.</p>
<p>If you install <a href="https://ublockorigin.com/">ublock origin</a> and turn on the top one or two default filters, and try again: there’s <em>less</em> advertising, but half of the vertical length is still intrawiki advertisements, a lot of the horizontal length is cruft and more advertisements, and there’s an autoplay video advertisement down in the lower right corner. It’s really not a good scene and I’d strongly recommend filtering out the crap.</p>
<p>Here is a comparison, of what the page looks like with no filtering, with “standard filters”, and with the additional filters I’m using:</p>
<div class="comparison">
<figure>
<img src="/images/fandom-post/full-nofilter.webp" width="1668" height="7398" alt="No adblock in use" />
<figcaption>No adblock</figcaption>
</figure>
<figure>
<img src="/images/fandom-post/full-yesfilter-basic.webp" width="1668" height="5955" alt="Basic adblock in use" />
<figcaption>Blocking ads</figcaption>
</figure>
<figure>
<img src="/images/fandom-post/full-yesfilter-custom.webp" width="1668" height="2369" alt="Advanced adblock in use" />
<figcaption>Blocking ads and cruft</figcaption>
</figure>
</div>
<p>This could surely be improved on; I don’t even remove the padding allocated to the orange bar on the left. There is so much space on these pages just waiting to be put to useful purpose.</p>
<h2 id="benchmarking"><a href="#benchmarking">Benchmarking</a></h2>
<p>There isn’t much of a page size or load speed difference between the “some adblock” and “more adblock” views. The results for each are shown here:</p>
<figure>
<img src="/images/fandom-post/yesfilter-basic.webp" width="747" height="15" alt="Some adblock" />
<figcaption aria-hidden="true">Some adblock</figcaption>
</figure>
<figure>
<img src="/images/fandom-post/yesfilter-custom.webp" width="747" height="15" alt="More adblock" />
<figcaption aria-hidden="true">More adblock</figcaption>
</figure>
<div class="admonition" style="--adm-bg: #2d4a3e; --adm-border: #27ae60" role="note">
<span class="admonition-title"><img src="/images/icons/blobfingerguns.webp" class="admonition-icon" alt="" width="128" height="128" />Try it yourself</span>
<div class="admonition-content">
<p>Most browsers’ dev tools can show this; in Firefox: <code>f12</code> → network → <span class="emoji"><img src="/images/emoji/2611.svg" class="emoji-img" draggable="false" alt="☑" /><span class="emoji-text" aria-hidden="true">☑</span></span> ‘disable cache’ → <code>f5</code>.</p>
</div>
</div>
<p>The “more adblock” view pulls in about 2/3 as much stuff as “some adblock”, but both decompress to being of roughly equal size anyway. They finish loading at roughly the same time. Both blow the unfiltered version out of the water, in the sense that without adblock, the page continues loading more advertisements in the background forever. Below are two screenshots taken at arbitrarily-selected points after the visible content was finished loading.</p>
<figure>
<img src="/images/fandom-post/nofilter-a.webp" width="747" height="15" alt="Demonstration that unfiltered page continues transferring data forever" />
<figcaption>after a few seconds</figcaption>
</figure>
<figure>
<img src="/images/fandom-post/nofilter-b.webp" width="747" height="15" alt="Demonstration that unfiltered page continues transferring data forever" />
<figcaption>a bit later</figcaption>
</figure>]]></description>
    <pubDate>Fri, 10 Feb 2023 00:00:00 UT</pubDate>
    <guid>https://nyuu.page/posts/2023-02-10-fandom/</guid>
    <dc:creator>nyuu</dc:creator>
</item>

    </channel>
</rss>
