.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "api/gallery/fraud/scam_contracts/plot_05_squid_game_rug_pull.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code or to run this example in your browser via JupyterLite. .. rst-class:: sphx-glr-example-title .. _sphx_glr_api_gallery_fraud_scam_contracts_plot_05_squid_game_rug_pull.py: Rug pulls and hidden-mint tokens: the Squid Game token (2021) ============================================================= Anyone can issue a token and open a market for it on a decentralized exchange. In November 2021 a token named after the Squid Game series rose from a cent to 2,861 dollars in a week; its buyers could not sell, because the contract refused transfers into the market unless the seller held "marbles", which nobody could earn. Its creators then sold and vanished, and the price fell to nothing in minutes. The rule hid behind an innocent-looking override, of the kind many scam tokens use: .. code-block:: solidity function _transfer(address from, address to, uint amount) internal override { if (to == pair) require(antiDumpExempt[from], "anti-dump"); // no selling super._transfer(from, to, amount); } On a constant-product market :math:`xy = k`, whoever can sell when no one else can drains the quote reserve: selling :math:`\Delta x` returns :math:`y \Delta x / (x + \Delta x)`, close to all of :math:`y` for a large mint. The defence costs one fork of the chain: buy a little and sell it back before buying for real, as honeypot scanners do. .. GENERATED FROM PYTHON SOURCE LINES 28-32 .. code-block:: Python import matplotlib.pyplot as plt import blockchainkit as bk .. GENERATED FROM PYTHON SOURCE LINES 33-35 A market for a token only its owner can sell -------------------------------------------- .. GENERATED FROM PYTHON SOURCE LINES 35-49 .. code-block:: Python world = bk.contracts.World() usd = world.deploy("bank", bk.contracts.ERC20, 10**8, name="USD") squid = world.deploy("dev", bk.fraud.SellBlockToken, 10**6, name="SQUID") world.transact("bank", usd, "transfer", "dev", 10_000) pool = world.deploy("dev", bk.economics.ConstantProductPool, squid, usd, name="pool") world.transact("dev", squid, "set_pool", pool) for asset in (squid, usd): world.transact("dev", asset, "approve", pool, 10**6) world.transact("dev", pool, "add_liquidity", 500_000, 10_000) print("sell test before buying:", bk.fraud.sell_test(world, pool, squid, usd, "bank", 100)) assert not bk.fraud.sell_test(world, pool, squid, usd, "bank", 100) .. rst-class:: sphx-glr-script-out .. code-block:: none sell test before buying: False .. GENERATED FROM PYTHON SOURCE LINES 50-52 Buyers pile in; nobody can leave -------------------------------- .. GENERATED FROM PYTHON SOURCE LINES 52-64 .. code-block:: Python prices = [float(world.view(pool, "price"))] buyers = [f"buyer{k}" for k in range(15)] for k, name in enumerate(buyers): world.transact("bank", usd, "transfer", name, 2_000 + 500 * k) world.transact(name, usd, "approve", pool, 10**6) world.transact(name, pool, "swap", usd, 2_000 + 500 * k) prices.append(float(world.view(pool, "price"))) stuck = world.view(squid, "balance_of", buyers[0]) world.transact(buyers[0], squid, "approve", pool, stuck) print("a buyer tries to sell:", world.transact(buyers[0], pool, "swap", squid, stuck).error) .. rst-class:: sphx-glr-script-out .. code-block:: none a buyer tries to sell: anti-dump: selling is not enabled .. GENERATED FROM PYTHON SOURCE LINES 65-67 The owner sells everything it kept ---------------------------------- .. GENERATED FROM PYTHON SOURCE LINES 67-84 .. code-block:: Python before = world.view(usd, "balance_of", "dev") world.transact("dev", pool, "swap", squid, world.view(squid, "balance_of", "dev")) prices.append(float(world.view(pool, "price"))) gain = world.view(usd, "balance_of", "dev") - before paid_in = sum(2_000 + 500 * k for k in range(15)) print(f"buyers paid {paid_in:,} USD; the owner walked away with {gain:,}") assert gain > 0.9 * paid_in and prices[-1] < prices[0] fig, ax = plt.subplots(figsize=(8, 4)) ax.plot(prices, "o-", color="#dc2626") ax.set(xlabel="trade", ylabel="price of SQUID in USD", yscale="log") ax.set_title("Buys push the price up; one sale ends it") fig.tight_layout() plt.show() .. image-sg:: /api/gallery/fraud/scam_contracts/images/sphx_glr_plot_05_squid_game_rug_pull_001.png :alt: Buys push the price up; one sale ends it :srcset: /api/gallery/fraud/scam_contracts/images/sphx_glr_plot_05_squid_game_rug_pull_001.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none buyers paid 82,500 USD; the owner walked away with 83,400 .. GENERATED FROM PYTHON SOURCE LINES 85-90 Exercise -------- Replace the sell block with :class:`~blockchainkit.fraud.systems.rug_pulls.HiddenMintToken`. Does the sell test still warn the buyers? Which check on the token's source or its total supply would? .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 0.040 seconds) .. _sphx_glr_download_api_gallery_fraud_scam_contracts_plot_05_squid_game_rug_pull.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: lite-badge .. image:: images/jupyterlite_badge_logo.svg :target: ../../../../lite/lab/index.html?path=api/gallery/fraud/scam_contracts/plot_05_squid_game_rug_pull.ipynb :alt: Launch JupyterLite :width: 150 px .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_05_squid_game_rug_pull.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_05_squid_game_rug_pull.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_05_squid_game_rug_pull.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_