.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "api/gallery/fraud/solvency/plot_04_ftx_commingled_funds.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_solvency_plot_04_ftx_commingled_funds.py: FTX, commingled customer funds, and proof of liabilities (2022) =============================================================== In November 2022 FTX, then one of the largest exchanges, could not meet a rush of withdrawals and filed for bankruptcy. Its affiliated trading firm, Alameda Research, had been allowed a negative balance on the exchange and had spent billions of dollars of customer deposits. The books still showed every customer's balance; the coins were gone. With reserves :math:`R` and liabilities :math:`L`, a run pays the first customers in full and the rest nothing once .. math:: \rho = \frac{R}{L} < 1, \qquad \text{paid in a run} = \min(R, L) = \rho L . A proof of reserves alone could not have shown this, since reserves were real and large; only reserves set against a proof of the liabilities can. Exchanges began publishing Merkle-sum-tree proofs of liabilities weeks after the collapse. .. GENERATED FROM PYTHON SOURCE LINES 25-29 .. code-block:: Python import matplotlib.pyplot as plt import blockchainkit as bk .. GENERATED FROM PYTHON SOURCE LINES 30-32 An exchange lends deposits to its affiliate ------------------------------------------- .. GENERATED FROM PYTHON SOURCE LINES 32-45 .. code-block:: Python world = bk.contracts.World() customers = [f"customer{k:02}" for k in range(20)] for name in customers: world.fund(name, 1_000) exchange = world.deploy("operator", bk.fraud.Custodian, "affiliate", 15_000, name="exchange") for name in customers: world.transact(name, exchange, "deposit", value=1_000) print("before:", world.view(exchange, "reserves"), "held for", world.view(exchange, "liabilities")) world.transact("operator", exchange, "lend_to_affiliate", 12_000) reserves, liabilities = world.view(exchange, "reserves"), world.view(exchange, "liabilities") print(f"after: reserves {reserves:,}, owed {liabilities:,}") .. rst-class:: sphx-glr-script-out .. code-block:: none before: 20000 held for 20000 after: reserves 8,000, owed 20,000 .. GENERATED FROM PYTHON SOURCE LINES 46-48 Reserves against a proof of liabilities --------------------------------------- .. GENERATED FROM PYTHON SOURCE LINES 48-54 .. code-block:: Python tree = bk.fraud.liability_tree(world.view(exchange, "balances"), salt=b"2022-11") ratio = bk.fraud.reserve_ratio(reserves, tree.total) print(f"proof of liabilities: total {tree.total:,}, reserve ratio {ratio:.0%}") assert tree.total == liabilities and ratio == 0.4 .. rst-class:: sphx-glr-script-out .. code-block:: none proof of liabilities: total 20,000, reserve ratio 40% .. GENERATED FROM PYTHON SOURCE LINES 55-57 The run ------- .. GENERATED FROM PYTHON SOURCE LINES 57-75 .. code-block:: Python results = [world.transact(name, exchange, "withdraw", 1_000) for name in customers] paid = [r.success for r in results] print("withdrawals paid:", sum(paid), "of", len(paid), "->", results[-1].error) assert sum(paid) == ratio * len(customers) fig, ax = plt.subplots(figsize=(8, 4)) ax.bar( range(len(paid)), [1_000 if ok else 0 for ok in paid], color=["#16a34a" if ok else "#dc2626" for ok in paid], ) ax.set(xlabel="order in the queue", ylabel="ether recovered") ax.set_title(f"A run on an exchange with a reserve ratio of {ratio:.0%}") fig.tight_layout() plt.show() .. image-sg:: /api/gallery/fraud/solvency/images/sphx_glr_plot_04_ftx_commingled_funds_001.png :alt: A run on an exchange with a reserve ratio of 40% :srcset: /api/gallery/fraud/solvency/images/sphx_glr_plot_04_ftx_commingled_funds_001.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none withdrawals paid: 8 of 20 -> withdrawals paused .. GENERATED FROM PYTHON SOURCE LINES 76-82 Exercise -------- The affiliate returns its loan the day before a published proof of reserves, then borrows it again. Which checks pass, and what would a proof of reserves need to rule this out? A worked solution is in :doc:`/exercises/fraud`. .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 0.034 seconds) .. _sphx_glr_download_api_gallery_fraud_solvency_plot_04_ftx_commingled_funds.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/solvency/plot_04_ftx_commingled_funds.ipynb :alt: Launch JupyterLite :width: 150 px .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_04_ftx_commingled_funds.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_04_ftx_commingled_funds.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_04_ftx_commingled_funds.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_