.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "api/gallery/fraud/phishing/plot_01_ice_phishing_approvals.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_phishing_plot_01_ice_phishing_approvals.py: Approval ("ice") phishing on ERC-20 allowances (2022) ===================================================== An ERC-20 ``approve`` lets a spender move the owner's tokens later without asking again. Exchanges ask once for an unlimited allowance, so users learn to sign approvals without reading them. In February 2022 Microsoft named *ice phishing* the attack that exploits this: a fake airdrop or mint page asks the victim to approve the attacker's contract, and the attacker empties the wallet whenever it likes. Nothing is stolen from the keys; the signature the victim reads in the wallet is the whole attack: .. code-block:: solidity token.approve(0x9a1f...c3d7, type(uint256).max); // "Claim your airdrop" What a wallet stands to lose is the sum, over its tokens, of .. math:: \min\Big(\text{balance},\; \sum_{\text{spenders}} \text{allowance}\Big), and revoking, approving 0, brings a spender's share back to nothing. .. GENERATED FROM PYTHON SOURCE LINES 27-31 .. code-block:: Python import matplotlib.pyplot as plt import blockchainkit as bk .. GENERATED FROM PYTHON SOURCE LINES 32-34 One signature on a fake airdrop page ------------------------------------ .. GENERATED FROM PYTHON SOURCE LINES 34-51 .. code-block:: Python world = bk.contracts.World() usdc = world.deploy("issuer", bk.contracts.ERC20, 10**6, name="USDC") dai = world.deploy("issuer", bk.contracts.ERC20, 10**6, name="DAI") world.transact("issuer", usdc, "transfer", "victim", 5_000) world.transact("issuer", dai, "transfer", "victim", 3_000) drainer = world.deploy("attacker", bk.fraud.Drainer, name="AirdropClaim") receipts = [ world.transact("victim", usdc, "approve", "dex", bk.fraud.UNLIMITED), # A real exchange. world.transact("victim", usdc, "approve", drainer, bk.fraud.UNLIMITED), # The phish. world.transact("victim", dai, "approve", drainer, 1_000), ] approvals = bk.fraud.open_approvals(receipts, "victim") exposed = bk.fraud.allowance_exposure(world, "victim", approvals) print("standing approvals:", len(approvals), "| at risk:", exposed) assert exposed == 6_000 .. rst-class:: sphx-glr-script-out .. code-block:: none standing approvals: 3 | at risk: 6000 .. GENERATED FROM PYTHON SOURCE LINES 52-54 Months later: one revoked, one forgotten ---------------------------------------- .. GENERATED FROM PYTHON SOURCE LINES 54-73 .. code-block:: Python world.advance(blocks=200_000) receipts.append(world.transact("victim", dai, "approve", drainer, 0)) remaining = bk.fraud.open_approvals(receipts, "victim") print("after revoking DAI:", bk.fraud.allowance_exposure(world, "victim", remaining), "at risk") swept = [world.transact("attacker", drainer, "sweep", t, "victim").result for t in (usdc, dai)] print("swept USDC, DAI:", swept) assert swept == [5_000, 0] fig, ax = plt.subplots(figsize=(7, 3.5)) labels = ["USDC (approved, forgotten)", "DAI (approved, revoked)"] ax.barh(labels, [5_000, 3_000], color="#cbd5e1", label="held") ax.barh(labels, swept, color="#dc2626", label="taken by the drainer") ax.set(xlabel="tokens", title="An allowance outlives the page that asked for it") ax.legend() fig.tight_layout() plt.show() .. image-sg:: /api/gallery/fraud/phishing/images/sphx_glr_plot_01_ice_phishing_approvals_001.png :alt: An allowance outlives the page that asked for it :srcset: /api/gallery/fraud/phishing/images/sphx_glr_plot_01_ice_phishing_approvals_001.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none after revoking DAI: 5000 at risk swept USDC, DAI: [5000, 0] .. GENERATED FROM PYTHON SOURCE LINES 74-79 Exercise -------- EIP-2612 replaces the ``approve`` transaction with a signed ``permit`` message that anyone can submit. Why does this make ice phishing easier to carry out and harder to notice? .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 0.029 seconds) .. _sphx_glr_download_api_gallery_fraud_phishing_plot_01_ice_phishing_approvals.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/phishing/plot_01_ice_phishing_approvals.ipynb :alt: Launch JupyterLite :width: 150 px .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_01_ice_phishing_approvals.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_01_ice_phishing_approvals.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_01_ice_phishing_approvals.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_