<?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>kyrers</title>
        <link>https://paragraph.com/@kyrers</link>
        <description>https://github.com/kyrers</description>
        <lastBuildDate>Sat, 27 Jun 2026 21:15:12 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <image>
            <title>kyrers</title>
            <url>https://storage.googleapis.com/papyrus_images/f696ad063677c688ebe08165d68b15c52a270328c3a186ea290862dcc40aef6c.png</url>
            <link>https://paragraph.com/@kyrers</link>
        </image>
        <copyright>All rights reserved</copyright>
        <item>
            <title><![CDATA[Damn Vulnerable DeFI 11 - 13 Solutions]]></title>
            <link>https://paragraph.com/@kyrers/damn-vulnerable-defi-11-13-solutions</link>
            <guid>Jg3xyS4eozPiL38ixnC9</guid>
            <pubDate>Wed, 05 Oct 2022 16:39:40 GMT</pubDate>
            <description><![CDATA[In this post, I will share my explanations for DamnVulnerableDeFI challenges 6 through 10. You can find the code here. Let’s begin.BackdoorThis took me a long time to solve, the main reason being unfamiliarity with the GnosisSafe contracts. So don&apos;t take this explanation as a fact. It did involve a lot of trial and error, and maybe luck was a key factor. First things first - the challenge consists of 4 users that upon creating a GnosisSafe wallet according to the WalletRegistry specifica...]]></description>
            <content:encoded><![CDATA[<p>In this post, I will share my explanations for DamnVulnerableDeFI challenges 6 through 10.</p><p>You can find the code <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/kyrers/damn-vulnerable-defi">here</a>.</p><p>Let’s begin.</p><h2 id="h-backdoor" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Backdoor</h2><p>This took me a long time to solve, the main reason being unfamiliarity with the <code>GnosisSafe</code> contracts. So don&apos;t take this explanation as a fact. It did involve a lot of trial and error, and maybe luck was a key factor.</p><p>First things first - the challenge consists of 4 users that upon creating a <code>GnosisSafe</code> wallet according to the <code>WalletRegistry</code> specifications will receive <code>10 DVT</code> tokens. Our goal is to steal them all in one transaction. This is our first clue, we will need a smart contract to do the dirty work.</p><p>Since I did not know the <code>GnosisSafe</code> contracts, I started by checking the setup for this challenge. Unexpectedly, it is quite easy. There are four contracts: <code>WalletRegistry</code>, <code>GnosisSafeProxyFactory</code> aka <code>walletFactory</code>, <code>GnosisSafe</code> aka <code>masterCopy</code>, and the <code>DamnValuableToken</code> contract. We also know who the allowed users are.</p><p>Next, I decided to look through the contracts. <code>GnosisSafeProxyFactory</code> and <code>GnosisSafe</code> contracts do not contain code exploits as far as I can tell. <code>WalletRegistry</code> was the only contract left to check, and after spending more time than I care to admit looking for code exploits, I couldn&apos;t find one in this contract either.</p><p>Not sure what to do, I decided to list what I found out while looking through the contracts:</p><ol><li><p>We know that <code>WalletRegistry</code> is the contract that has the tokens, so we&apos;ll have to execute the <code>proxyCreated(...)</code> function to get them;</p></li><li><p>The <code>proxyCreated(...)</code> function makes sure that the wallet was created using the <code>GnosisSafe</code> <code>setup(...)</code> function;</p></li><li><p>To execute the <code>proxyCreated(...)</code> function we have to create the wallet using <code>GnosisSafeProxyFactory createProxyWithCallback(...)</code> function;</p></li></ol><p>I decided to take a deeper look at the <code>createProxyWithCallback(...)</code> function, which has to be executed first. According to the comments, <code>createProxyWithCallback(...)</code> allows us to create a new <code>GnosisSafeProxy</code> and call it after it is initialized. It also allows us to call a specified <code>callback</code> function afterward.</p><p>From that, I assumed two things: the <code>callback</code> must be the <code>WalletRegistry</code> <code>proxyCreated(...)</code> function and that this is how we reach the <code>GnosisSafe</code> <code>setup(...)</code> function.</p><p>After making the above assumptions, I decided to look at the <code>setup(...)</code> function. I noticed two more things: some parameters weren&apos;t important and it also allows us to perform a <code>delegatecall</code> to a specified address.</p><p>This looked promising. If I&apos;m able to successfully pass the verifications on the <code>WalletRegistry</code> <code>proxyCreated(...)</code> function, I can then execute a <code>callback</code> defined by me on the <code>proxy</code> itself, which by now will have the <code>10 DVT</code> according to the <code>WalletRegistry</code> <code>proxyCreated(...)</code> function.</p><p>All that was left was implementing the contract. Most of it was pretty easy, but I was having trouble making a correct call to the <code>setup(...)</code>. The <code>initializer</code> variable passed to the <code>createProxyWithCallback(...)</code> must contain the <code>setup(...)</code> function selector and parameters. Most of it can be ignored, but I was also ignoring the <code>threshold</code> parameter - which was a mistake. The <code>proxyCreated(...)</code> callback verifies that, so don&apos;t make the same mistake as I did.</p><p>I realize that this isn&apos;t a very clear explanation. It might even contain errors. But it was most of my thought process until finally reaching a solution. I rather find a solution myself even if it involves luck and trial and error than simply copy someone else&apos;s. Besides, after solving this I looked online for explanations and couldn&apos;t find much better explanations. I did find contract improvements though, so there&apos;s that.</p><h2 id="h-climber" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Climber</h2><p>he goal of this challenge is clearly stated: steal 10 million <code>DVT</code> from the <code>ClimberVault</code> contract.</p><p>We are also given a couple of extra hints:</p><ol><li><p>The <code>ClimberVault</code> is upgradeable, following the <code>UUPS</code> pattern;</p></li><li><p><code>ClimberVault</code> has the role of <code>Sweeper</code> which can sweep all funds from the vault;</p></li><li><p>The owner of <code>ClimberVault</code> is the <code>ClimberTimelock</code> contract;</p></li><li><p>The <code>ClimberTimelock</code> contract can withdraw a limited amount of tokens from the vault every 15 days;</p></li><li><p>The <code>ClimberTimelock</code> contract allows accounts with the <code>Proposer</code> role to <code>schedule</code> actions that will be executed 1 hour later;</p></li></ol><p>Since we are given so much information, I instantly assumed this would be a tough challenge.</p><p>First I used my very limited knowledge of the <code>UUPS</code> pattern to look for a pattern error in the <code>ClimberVault</code> contract. However, it does have an empty constructor and instead is initialized by a <code>initialize</code> function. This is not the way in.</p><p>I then tried to find a way to get the <code>Sweeper</code> role. I couldn&apos;t find any. If you can, let me know.</p><p>However, while looking through the <code>ClimberTimelock</code> contract, I did notice that it has the role of <code>Admin</code> of itself, meaning it can grant the roles defined. I also noticed that anyone can call <code>execute()</code> to execute a proposal, as long as it has been scheduled. This function contains an enormous error, it only checks that a given proposal was ready for execution after executing it!</p><p>This is the point at which I knew I was onto something. Theoretically, we could create a contract to execute a proposal that grants itself the <code>Proposer</code> role and transfers the ownership of the <code>ClimberVault</code> to an account controlled by us. After that, it would be a simple matter of creating a new <code>ClimberVault</code> that allows us to call the <code>sweepFunds()</code> function, and upgrading the proxy to use our new <code>ClimberVault</code>.</p><p>While implementing the proposal I forgot one thing: we know from the challenge description that the delay to execute a proposal is 1 hour. Fortunately, we can just set it to 0 without any issue.</p><p>Also, don&apos;t forget that even though the <code>checks-effects-interaction</code> pattern is violated, the <code>ClimberTimelock</code> does check that the proposal is ready to be executed, so we&apos;ll have to schedule it otherwise it will revert and the attack won&apos;t work. Plus, the proposal can&apos;t call the <code>schedule()</code> function itself because the parameters won&apos;t match. So, we need to set a task that calls a function in our attacker contract that schedules the task, which will work because we already have the <code>Proposer</code> role.</p><p>So, to recap:</p><ol><li><p>Implement a <code>ClimberVault</code> version that allows us to call the <code>sweepFunds()</code> function;</p></li><li><p>Create a contract that executes a proposal with the following tasks:</p><ul><li><p>Set the delay to 0;</p></li><li><p>Grant the contract the proposer role;</p></li><li><p>Transfer the ownership of the vault to our attacker account;</p></li><li><p>Schedule the proposal;</p></li></ul></li><li><p>Execute the proposal;</p></li><li><p>Update the proxy to use our <code>ClimberVault</code></p></li><li><p>Sweep the funds;</p></li></ol><h2 id="h-safe-miners" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Safe Miners</h2><p>This is not an explanation of the solution, this is an unfiltered account of how I reached a solution. This is because I don&apos;t really understand this challenge. Then again, even the challenge description says it will be modified for a future version of <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.damnvulnerabledefi.xyz/">damnvulnerabledefi</a>.</p><p>With that caveat, let me explain how I reached a solution.</p><p>From the description, I immediately assumed I had to deploy a contract using the <code>attacker</code> to the specified address, because it clearly says that the address that has the tokens is empty.</p><p>My first instinct was to use <code>CREATE2</code>, but then it occurred to me it probably would take eternities to find the correct salt to get that same address.</p><p>So I decided to try brute forcing it first using <code>CREATE</code>, since paying for gas is not a concern in this scenario.</p><p>My first attempt consisted of having the <code>attacker</code> deploy 100k contracts that just transferred the <code>DVT</code> tokens to the attacker. Not only did this take a long time, but it also didn&apos;t work.</p><p>Since I am not sure how hardhat deploys contracts, I decided to give it another shot using a <code>SafeMinersAttackerFactory</code> to deploy the <code>SafeMinersAttacker</code> before giving up.</p><p>At first, I tried having the factory deploy 1000 instances of the attacker until the <code>attacker</code> account had the tokens. This ran into an out-of-gas error because I, naively, forgot that there&apos;s a limit to the gas I can send to the contract.</p><p>So I decided to modify how this would work. The <code>attacker</code> account would deploy a <code>SafeMinersAttackerFactory</code> that would create 500 instances of the <code>SafeMinersAttacker</code>. Then, if the <code>attacker</code> had the tokens, I would stop, otherwise, I would have the <code>attacker</code> deploy another factory.</p><p>I was expecting this to run for a while, but since I had to leave my computer at the time it was cool. If it didn&apos;t work, I would know brute force was the wrong approach. To my surprise, it worked on the second batch of 500 <code>SafeMinersAttacker</code> deployments.</p>]]></content:encoded>
            <author>kyrers@newsletter.paragraph.com (kyrers)</author>
        </item>
        <item>
            <title><![CDATA[Damn Vulnerable DeFi 6 - 10 Solutions]]></title>
            <link>https://paragraph.com/@kyrers/damn-vulnerable-defi-6-10-solutions</link>
            <guid>VMbY4kWSDPCCAMzo9iem</guid>
            <pubDate>Wed, 05 Oct 2022 16:28:22 GMT</pubDate>
            <description><![CDATA[In this post, I will share my explanations for DamnVulnerableDeFI challenges 6 through 10. You can find the code here. Let’s begin.SelfieAs per usual, this challenge involves a pool providing flash loans of 1.5 million DVT tokens. Our goal is to take them all. Fortunately, we can immediately see that the pool has a drainAllFunds(...) function, which sends all pool DVT tokens to the address passed as a parameter. Unfortunately for us, it can only be called by governance. SelfiePool is the firs...]]></description>
            <content:encoded><![CDATA[<p>In this post, I will share my explanations for DamnVulnerableDeFI challenges 6 through 10.</p><p>You can find the code <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/kyrers/damn-vulnerable-defi">here</a>.</p><p>Let’s begin.</p><h2 id="h-selfie" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Selfie</h2><p>As per usual, this challenge involves a pool providing flash loans of 1.5 million <code>DVT</code> tokens. Our goal is to take them all.</p><p>Fortunately, we can immediately see that the pool has a <code>drainAllFunds(...)</code> function, which sends all pool <code>DVT</code> tokens to the <code>address</code> passed as a parameter. Unfortunately for us, it can only be called by governance.</p><p><code>SelfiePool</code> is the first flash loan provider that has a governance mechanism attached to it, which, as stated in the challenge description, will be our way in. Looking into it we see that the <code>SimpleGovernance</code> contract allows for <code>actions</code> to be queued, provided they have enough votes. <code>_hasEnoughVotes()</code> checks that the <code>msg.sender</code> <code>DVT</code> balance is higher than half of the pool token balance.</p><p><code>SelfiePool</code> also allows for an <code>action</code> to be executed, provided it has never been executed before and two days have passed since being <code>queued</code>. During a given <code>action</code> execution, the <code>action.receiver</code> will be called using the <code>action.data</code> and <code>action.weiAmount</code> as the <code>call</code> function parameters.</p><p>While looking through the <code>SimpleGovernance</code> contract, you&apos;ll hopefully have noticed that there are practically no access control mechanisms in place. This means that, as long as we can bypass <code>queueAction(...)</code> and <code>executeAction(...)</code> verifications, we are able to queue an <code>action</code> that will call the <code>SelfiePool</code> <code>drainAllFunds(...)</code> function and send them to us. It will work because the call is coming from governance.</p><p>To bypass <code>queueAction(...)</code> we need to have more than 750k <code>DVT</code> tokens at the time of the last <code>snapshot</code>. This is new - the pool implements an <code>ERC20Snapshot</code> version of the <code>DVT</code> token. Fortunately for us, anyone can take a <code>DVT</code> snapshot.</p><p>However, we are only interested in taking a <code>snapshot</code> when we do have enough <code>DVT</code> tokens, which we can get by implementing a contract that gets a <code>SelfiePool</code> flash loan.</p><p>All that&apos;s left is finding a way to bypass <code>executeAction(...)</code>, which is easily done by waiting two days!</p><p>So, one way to solve this challenge is to:</p><ol><li><p>Implement a contract that is able to get a flash loan from the <code>SelfiePool</code> contract;</p></li><li><p>After receiving the flash loan, take a <code>snapshot</code> and queue an <code>action</code> with:</p><ul><li><p><code>data</code> to make a call to the <code>drainAllFunds(...)</code> with our address as a parameter;</p></li><li><p><code>receiver</code> as the <code>SelfiePool</code> address;</p></li><li><p><code>weiAmount</code> must be 0, unless you funded the attacker contract;</p></li></ul></li><li><p>Pay the flash loan back;</p></li><li><p>Wait two days;</p></li><li><p>Execute the action.</p></li></ol><h2 id="h-compromised" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Compromised</h2><p>To me, the hardest challenge so far. I had to use some guessing to get this to work. I&apos;ll explain my rationale below.</p><p>The challenge setup is simple: We have an <code>Exchange</code> selling and buying <code>DVNTF</code> tokens at a <code>median price</code> obtained from averaging 4 <code>TrustfulOracle</code> price feeds. The goal is simple as well: Drain <code>Exchange</code> using only our 0.1 ETH.</p><p>Looking at the contracts, I did not notice any obvious exploit. The only possible way to drain the <code>Exchange</code> contract that I found consisted of manipulating the <code>DVNFT</code> price. To that effect, the challenge description came in handy. This is where the guessing started.</p><p>Since it is called &quot;Compromised&quot; I assumed the leaked information from the <code>HTTP</code> response would contain some private keys.</p><p>I looked at the leaked data and decided to convert it to a <code>string</code>. Unfortunately, that did not result in a private key. Eventually, it occurred to me that the <code>string</code> I obtained may very well be encoded, as it is an <code>HTTP</code> response. I used google and found out that often <code>HTTP</code> response data is <code>base64</code> encoded. So I converted the leaked data <code>string</code> using <code>base64</code>. At last, something that resembles a private key. I created wallets using the decoded leaked data and was happy to see that they corresponded to two trusted oracle addresses.</p><p>After that, it was just a question of manipulating the price using the compromised oracles.</p><p>Here&apos;s every step:</p><ol><li><p>Decode the leaked data and obtain two private keys;</p></li><li><p>Create 2 wallets using the private keys obtained;</p></li><li><p>Set the price to an affordable value. I used <code>0.005</code> ETH;</p></li><li><p>Buy one <code>DVNFT</code> using the <code>attacker</code> account;</p></li><li><p>Set the price to equal <code>Exchange</code> ETH balance;</p></li><li><p>Sell the <code>attacker</code> <code>DVNFT</code>;</p></li><li><p>Reset the price to the original value;</p></li></ol><h2 id="h-puppet" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Puppet</h2><p>This challenge is quite easy.</p><p>There is a <code>PuppetPool</code> that allows users to borrow <code>DVT</code> tokens, as long as the user deposits double that amount in <code>ETH</code> as collateral. The pool has a balance of <code>100000 DVT</code>. Our goal is to get our hands on all of them.</p><p>The pool uses an <code>Uniswap V1 DVT/ETH</code> pair to calculate the collateral needed. This pair starts with <code>10 ETH / 10 DVT</code> liquidity.</p><p>Lastly, our <code>attacker</code> starts with a balance of <code>25 ETH</code> and <code>1000 DVT</code>.</p><p>Since there are no flash loans, our best option is to somehow lower the collateral needed to borrow the <code>100000 DVT</code> tokens from the <code>PuppetPool</code>.</p><p>Looking at how the price is calculated we see the following equation <code>amount * _computeOraclePrice() * 2 / 10 ** 18;</code>.</p><p>Looking at the <code>_computeOraclePrice()</code> we see that the equation used is <code>uniswapPair.balance * (10 ** 18) / token.balanceOf(uniswapPair);</code>. This is problematic, because if the <code>Uniswap V1</code> exchange has a sufficiently larger balance of <code>DVT</code> tokens than <code>ETH</code>, the price to borrow tokens will decrease significantly.</p><p>Luckily for us, our attacker has <code>1000 DVT</code> tokens, so if we deposit these to the <code>Uniswap V1</code> exchange, our <code>25 ETH</code>, plus whatever <code>ETH</code> we receive from depositing to the <code>Uniswap V1</code> exchange, will be more than enough to borrow the <code>PuppetPool</code> <code>100000 DVT</code> tokens.</p><p>The only detail we must not forget is that to pass the challenge the attacker <code>DVT</code> balance must be higher than the initial <code>100000 DVT</code> <code>PuppetPool</code> balance. This means we cannot deposit all of the attackers <code>1000 DVT</code> tokens to the <code>Uniswap V1</code> exchange.</p><p>To recap:</p><ol><li><p>As the attacker, deposit an amount of <code>DVT</code> tokens large enough to lower the borrowing price to acceptable levels but less than 1000;</p></li><li><p>Determine the amount of <code>ETH</code> needed as collateral to borrow the <code>PuppetPool</code> <code>100000 DVT</code> tokens;</p></li><li><p>Borrow them.</p></li></ol><p>It&apos;s this simple.</p><h2 id="h-puppet-v2" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Puppet V2</h2><p>The set up of this challenge is very similar to the previous one.</p><p>The major differences are:</p><ol><li><p>The <code>PuppetV2Pool</code> now uses an <code>Uniswap V2</code> exchange to calculate the price;</p></li><li><p><code>WETH</code> is used instead of <code>ETH</code>;</p></li><li><p>We are now required to deposit triple the borrow amount in <code>WETH</code> as collateral;</p></li></ol><p>Despite the challenge description mentioning that developers learned from the original <code>Puppet</code> implementation, and in fact this is a more secure implementation, the same problem remains.</p><p>The <code>Uniswap V2</code> pair used to calculate the borrowing price still has low liquidity, meaning that users with sufficient amounts of either of the pair tokens can affect significant price swings.</p><p>Luckily for us, our <code>attacker</code> has a significant amount of <code>DVT</code> tokens, meaning we can swing the price in our favor once again.</p><p>So, the steps to solve this challenge are similar to the previous one:</p><ol><li><p>Swap the <code>attacker</code> <code>DVT</code> tokens for <code>ETH</code> using the <code>Uniswap V2</code> pair;</p></li><li><p>Convert the <code>attacker</code> <code>ETH</code> to <code>WETH</code>;</p></li><li><p>Borrow all <code>PuppetV2Pool</code> <code>DVT</code> tokens;</p></li></ol><h2 id="h-free-rider" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Free Rider</h2><p>The set up of this challenge consists of a <code>FreeRiderNFTMarketplace</code> that is selling 6 NFTs for <code>15 ETH</code> each. We also have a <code>FreeRiderBuyer</code> which told us that the marketplace is exploitable, and if we exploit it and send them the 6 NFTs, it will pay us <code>45 ETH</code>. This is our goal.</p><p>The challenge description mentions that we start with <code>0.5 ETH</code> - which is clearly not enough to buy the 6 NFTs. It also implies that there&apos;s a way to get some more ETH. If we look at the script that sets up the challenge, we can see that there&apos;s an <code>Uniswap V2 WETH/DVT</code> pair.</p><p>First things first, we need to find the exploit in the <code>FreeRiderNFTMarketplace</code>. Looking at the contract we can see that we can only call the <code>buyMany(...)</code> function to buy NFTs. This function calls the <code>_buyOne(...)</code>, which is the function that actually handles the purchase. The exploit must be here.</p><p>Luckily for us, it is easy to find what&apos;s wrong with this function - it is the way that it checks the price we have to pay. Suppose we call the <code>buyMany(...)</code> function with the ids of the 6 NFTs, the <code>require(msg.value &gt;= priceToPay, &quot;Amount paid is not enough&quot;)</code> check is wrong because it is only checking the price of one NFT, not the sum of all 6. This means that for the price of one NFT, <code>15 ETH</code>, we can buy all six!</p><p>As a bonus, there&apos;s also another bug. It sends the <code>15 ETH</code> to <code>token.ownerOf(tokenId)</code>, the owner of the NFT. However, before doing so it transfers the NFT to the buyer - meaning that not only is <code>15 ETH</code> enough to buy all 6 NFTs, we actually get the <code>90 ETH</code> we were supposed to pay, because we are the new owner.</p><p>All that&apos;s left is figuring out how to get the <code>15 ETH</code> we need. For that, you&apos;ll need to look into the <code>Uniswap V2</code> documentation. This is the difficult part of the challenge.</p><p>You&apos;ll hopefully find that we can take a <code>flashswap</code> from the <code>WETH/DVT</code> pair, which we will be able to payback easily due to our expected profit from the attack.</p><p>We will need to perform this attack using a contract, not only because we need to implement a <code>uniswapV2Call(...)</code> function to receive the <code>flashswap</code>, but also because we need an <code>onERC721Received</code> to receive the NFTs.</p><p>Here&apos;s the full attack:</p><ol><li><p>Get a <code>flashswap</code> of <code>15 WETH</code>;</p></li><li><p>Unwrap that <code>WETH</code>;</p></li><li><p>Buy the 6 NFTs;</p></li><li><p>Send them to the buyer;</p></li><li><p>Pay the <code>flashswap</code> back;</p></li><li><p>Send the all profits to the <code>attacker</code> account;</p></li></ol>]]></content:encoded>
            <author>kyrers@newsletter.paragraph.com (kyrers)</author>
        </item>
        <item>
            <title><![CDATA[Damn Vulnerable DeFi 1 - 5 Solutions]]></title>
            <link>https://paragraph.com/@kyrers/damn-vulnerable-defi-1-5-solutions</link>
            <guid>aRgrTz1bA2e4cu6o5aO4</guid>
            <pubDate>Wed, 05 Oct 2022 15:27:23 GMT</pubDate>
            <description><![CDATA[In this post, I will share my explanations for DamnVulnerableDeFI challenges 1 through 5. You can find the code here. Let’s begin.UnstoppableIf you&apos;re like me, your first instinct might be to drain the pool. However, as you read through the contracts, you&apos;ll hopefully realize that there&apos;s a much easier way to stop the pool from giving out flashloans. Let&apos;s start with the ReceiverUnstoppable contract. It has two functions receiveTokens(...) which, as the comment says, will ...]]></description>
            <content:encoded><![CDATA[<p>In this post, I will share my explanations for DamnVulnerableDeFI challenges 1 through 5.</p><p>You can find the code <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/kyrers/damn-vulnerable-defi">here</a>.</p><p>Let’s begin.</p><h2 id="h-unstoppable" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Unstoppable</h2><p>If you&apos;re like me, your first instinct might be to drain the pool. However, as you read through the contracts, you&apos;ll hopefully realize that there&apos;s a much easier way to stop the pool from giving out <code>flashloans</code>.</p><p>Let&apos;s start with the <code>ReceiverUnstoppable</code> contract. It has two functions <code>receiveTokens(...)</code> which, as the comment says, will be called during the execution of the <code>executeFlashLoan(...)</code> function. Looking at the <code>executeFlashLoan(...)</code> function, we can see that it must be called by the <code>owner</code> and that it will in turn call the <code>flashLoan(...)</code> function of the <code>UnstoppableLender</code> contract, so let&apos;s go to that function. The <code>flashLoan(...)</code> function first checks that the loan amount is higher than 0 but not greater than the pool token balance. It then checks that the <code>poolBalance</code> value corresponds to the actual amount of tokens the pool has. Only after does it execute the <code>flashloan</code> and check that it has been repaid.</p><p>So, the <code>flashLoan(...)</code> function will revert in case the loan amount is invalid or the loan isn&apos;t repaid. These make sense. However, it will fail in one extra scenario - if the actual amount of tokens in the pool differs from the stateful <code>poolBalance</code> value, which raises the question: where is the <code>poolBalance</code> value updated? It&apos;s in the <code>depositTokens(...)</code> function of the pool, which was intended as the only way users would deposit tokens in the pool. But, considering our balance of <code>100 DVT</code> tokens, what&apos;s stopping us from using <code>transfer</code> to deposit <code>1 DVT</code> token in the pool?</p><h2 id="h-naive-receiver" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Naive Receiver</h2><p>Ok, so we&apos;re told exactly what to do: Drain <code>FlashLoanReceiver</code> funds. If you look at the contract it has three functions, but only <code>receiveEther(...)</code> actually does something - it receives the <code>flashloan</code> and pays it back. As the comment says, this function is called while the <code>NaiveReceiverLenderPool</code> contract <code>flashLoan(...)</code> function is executed. Let&apos;s take a look.</p><p>We can see that the <code>flashLoan(...)</code> function checks that there&apos;s enough ETH in the pool for the requested <code>flashloan</code> amount. Then, it checks that the borrower is a contract. Finally, it verifies if the <code>flashloan</code> plus the fixed fee of <code>1 ether</code> has been paid back.</p><p>Do you see the issue? The <code>borrower</code> is passed as a parameter! This means that we can say that the borrower is the <code>FlashLoanReceiver</code> contract and request a <code>flashloan</code> of <code>0 ether</code>, which will cost the <code>FlashLoanReceiver</code> <code>1 ether</code> in fees. Do this enough times and the receiver is drained!</p><p>To do this in one transaction, we just need to deploy a contract that does the attack for us.</p><h2 id="h-truster" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Truster</h2><p>So far, this is the most to-the-point challenge. We have to drain <code>1000000 DVT</code> from the <code>TrusterLenderPool</code>.</p><p>Looking at the <code>flashloan(...)</code> function we immediately see that it has two strange parameters: <code>address target</code> and <code>bytes calldata data</code>. Examining further we find that this is a classic flash loan function except that before checking that the loan is repaid, it unexpectedly calls the <code>target</code> address using the <code>data</code> parameters. Well, this is obviously our way in.</p><p>Since no checks are performed, we can simply say that we want to borrow <code>0 DVT</code> tokens, the <code>target</code> is the <code>DVT</code> token contract and the <code>data</code> is a call to the <code>approve(...)</code> function, which allows us to approve a transfer from the pool to ourselves of any amount of the pool <code>DVT</code> tokens. So two transactions are needed: one to call <code>flashloan(...)</code> in order to sneak in that <code>approve(...)</code> transaction, and another to <code>transferFrom()</code> to send the <code>DVT</code> tokens to ourselves.</p><p>To do this in one transaction, we just need to deploy a contract that does the attack for us.</p><h2 id="h-side-entrance" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Side Entrance</h2><p>Once again, we have a <code>1000 ether</code> pool that provides free <code>flashloans</code>. Our job is to drain the pool.</p><p>Looking at the <code>SideEntranceLenderPool</code> contract we can see that it allows users to <code>deposit</code> and <code>withdraw</code> funds from the pool. Of course, it also allows us to use the <code>flashloan(...)</code> function to request a flash loan.</p><p>Aside from repaying the flash loan, this <code>flashloan(...)</code> function also requires that the borrower implement the <code>IFlashLoanEtherReceiver</code> interface, which has the function <code>execute()</code> responsible for handling the flash loan funds.</p><p>So one thing is for sure, we need to implement an attacker contract that asks for the flash loan and receives it in the <code>execute()</code> function. But what do we do with it? Remember the <code>deposit(...)</code> and <code>withdraw(...)</code> functions? We just <code>deposit</code> the funds back in the pool, which will make the flash loan successful and set the funds as the property of our attacker contract, which in turn means we can <code>withdraw</code> those funds from the pool. All that&apos;s left to do is send the withdrawn funds from our contract to our wallet.</p><h2 id="h-rewarder" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Rewarder</h2><p>The first challenge where things get more complex. However, there are several tips in the challenge description that will provide us with a path to find the exploit.</p><p>First, we find out that there&apos;s a pool offering rewards in 5-day increments to users that deposit <code>DVT</code> tokens. We also discover that we have no <code>DVT</code> tokens, but that there&apos;s a pool offering free flash loans.</p><p>Let&apos;s look at the <code>FlashLoanPool</code> <code>flashloan(...)</code> function. It requires that the borrower is a deployed contract with the <code>receiveFlashLoan(uint256)</code> function to handle the flash loan. We now have a way of getting the <code>DVT</code> tokens, but how do we use them in regard to <code>TheRewarderPool</code>?</p><p>Looking at the pool the first thing we notice is that it uses three tokens: <code>LiquidityToken</code>, <code>AccountingToken</code> and <code>RewardToken</code>. Again, from the challenge description, it becomes obvious that we need to get some <code>RewardToken</code> tokens.</p><p>It seems that the only way to mint <code>RewardToken</code> is inside the <code>distributeRewards(...)</code> function. To execute that code, the function checks that <code>rewards &gt; 0 &amp;&amp; !_hasRetrievedReward(msg.sender)</code>. Let&apos;s find a way to pass this verification.</p><p><code>hasRetrievedReward(msg.sender)</code> will return <code>false</code> if we have never received a reward, which is true in our case - easy. <code>rewards</code> will be greater than 0 if we have a positive balance of <code>AccountingToken</code> tokens considering the last snapshot taken. Ok, so how do we get a positive balance of <code>AccountingToken</code> and our snapshot taken?</p><p>Snapshots are taken earlier in the <code>distributeRewards(...)</code> function execution via a call to <code>_recordSnapshot()</code>. However, to execute this call we need to pass the verification <code>isNewRewardsRound()</code> which checks that at least 5 days have passed since the last snapshot. This means that we need to wait 5 days before calling <code>distributeRewards(...)</code>.</p><p>That was easy, but we still need to figure out how to get a positive balance of <code>AccountingToken</code>. Looking at the pool we see that <code>AccountingToken</code> are minted in the <code>deposit(...)</code> function, in proportion to the deposited <code>LiquidityToken</code> which is the <code>DVT</code> token. We also see that <code>AccountingToken</code> tokens are burned in the <code>withdraw(...)</code> function which, in addition to sending us our <code>RewardToken</code>, sends the <code>DVT</code> tokens back to us - allowing us to pay the flash loan.</p><p>We now have a clear picture of how to get <code>RewardToken</code>, and since we already know how to get our hands on free <code>DVT</code> tokens, we have all the information we need.</p><p>Let&apos;s recap what we know:</p><ol><li><p>We know we have to get some amount of <code>RewardToken</code> to pass the challenge;</p></li><li><p>The only place where <code>RewardToken</code> is minted is in the <code>TheRewarderPool</code> <code>distributeRewards(...)</code> function;</p></li><li><p>To be able to reach that place of the code, the function needs that the caller:</p><ol><li><p>Have a positive balance of <code>AccountingToken</code> since the last snapshot;</p></li><li><p>Have never received a reward;</p></li></ol></li><li><p>To clear the verifications in the previous step, we need to:</p><ol><li><p>Wait 5 days;</p></li><li><p>Deposit <code>DVT</code> tokens in the pool;</p></li></ol></li><li><p>We have no <code>DVT</code> tokens, but we know how to get them for free provided we pay them back - which we can since we can call the pool <code>withdraw(...)</code> function which will give us our <code>DVT</code> tokens back after we have successfully gotten our <code>RewardToken</code> rewards;</p></li></ol><p>All that&apos;s left is implementing a <code>RewardAttacker</code> contract that does all the above for us.</p>]]></content:encoded>
            <author>kyrers@newsletter.paragraph.com (kyrers)</author>
        </item>
        <item>
            <title><![CDATA[Capture The Ether Miscellaneous Solutions]]></title>
            <link>https://paragraph.com/@kyrers/capture-the-ether-miscellaneous-solutions</link>
            <guid>iTxzRUd6UN4ipDjfPwKq</guid>
            <pubDate>Sun, 11 Sep 2022 19:01:00 GMT</pubDate>
            <description><![CDATA[In this post, I will share my explanations for the Miscellaneous section of the Capture The Ether challenges. There are plenty of solutions around the web - my goal was to solve the challenges locally, avoiding Etherscan when possible, and writing code locally. You can find the code here. Let’s begin.Assume OwnershipThis challenge might be the easiest. Solidity now allows you to use the constructor keyword so constructors stand out. However, the challenge contract doesn&apos;t use that keywor...]]></description>
            <content:encoded><![CDATA[<p>In this post, I will share my explanations for the Miscellaneous section of the Capture The Ether challenges. There are plenty of solutions around the web - my goal was to solve the challenges locally, avoiding Etherscan when possible, and writing code locally.</p><p>You can find the code <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/kyrers/CTE-Solutions">here</a>.</p><p>Let’s begin.</p><h2 id="h-assume-ownership" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Assume Ownership</h2><p>This challenge might be the easiest.</p><p>Solidity now allows you to use the <code>constructor</code> keyword so constructors stand out. However, the challenge contract doesn&apos;t use that keyword. If you look at the code you&apos;ll notice a severe error: the function that&apos;s meant to be the constructor is misspelled as <code>AssumeOwmershipChallenge</code>, allowing anyone to call it and become the owner.</p><p>There&apos;s not much to this challenge, just:</p><ol><li><p>Get the contract abi and address;</p></li><li><p>Get the private key of the ropsten account you are using to interact with Capture The Ether. Otherwise, you can&apos;t pass the challenge as CTE doesn&apos;t know who you are;</p></li><li><p>Get the contract and connect with it using your account;</p></li><li><p>Call <code>AssumeOwmershipChallenge</code>;</p></li><li><p>Call <code>authenticate</code>;</p></li><li><p>Win;</p></li></ol><h2 id="h-token-bank" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Token Bank</h2><p>This challenge involves two contracts: <code>TokenBankChallenge</code> which acts as a bank, as the name suggests. It deploys the <code>SimpleERC223Token</code> and assigns half to the CTE challenge factory, given that it created the <code>TokenBankChallenge</code> contract, and half to the player, meaning us. Our goal is to withdraw all 1000000 tokens, not just our 500000.</p><p>It&apos;s important to know that one difference between the <code>ERC20</code> and <code>ERC223</code> token standards is that the <code>ERC223</code> notifies the recipient of a transfer by calling the <code>tokenFallback</code> function in case it is a contract.</p><p>Now, as you&apos;ve probably guessed, the <code>TokenBankChallenge</code> <code>withdraw</code> function must be used. If you look through the function, you&apos;ll see that it is vulnerable to reentrancy attacks, as it only updates the <code>msg.sender</code> balance after sending the funds.</p><p>So, even though this looks like a lot of code, the solution isn&apos;t all that complicated. We just need to create a contract that has a <code>tokenFallback</code> function that keeps withdrawing until the contract is empty. This <code>tokenFallback</code> function will be called by the <code>SimpleERC223Token</code> contract on each withdrawal, allowing us to check if there are tokens left and keep withdrawing until it is empty.</p><p>Even though it is obvious, you must not forget that you can only withdraw funds that you have, so before initiating our attack we&apos;ll need to send our tokens to the attack contract and deposit them in the bank again.</p><p>So, here are the steps needed:</p><ol><li><p>Get the bank contract abi and address;</p></li><li><p>Get the token contract abi;</p></li><li><p>Deploy the <code>TokenBankHelper</code> contract;</p></li><li><p>Get the bank contract;</p></li><li><p>Get the token contract that the challenge bank is using;</p></li><li><p>Withdraw your 500000 tokens;</p></li><li><p>Send your 500000 tokens to the <code>TokenBankHelper</code>;</p></li><li><p>Deposit them in the bank;</p></li><li><p>Initiate the attack by withdrawing 500000;</p></li><li><p>Wait until the <code>TokenBank</code> contract is empty;</p></li><li><p>Win;</p></li></ol>]]></content:encoded>
            <author>kyrers@newsletter.paragraph.com (kyrers)</author>
        </item>
        <item>
            <title><![CDATA[Capture The Ether Account Solutions]]></title>
            <link>https://paragraph.com/@kyrers/capture-the-ether-account-solutions</link>
            <guid>hvAlgvXTXPaRN4i1c1S2</guid>
            <pubDate>Sun, 11 Sep 2022 18:32:08 GMT</pubDate>
            <description><![CDATA[In this post, I will share my explanations for the Account section of the Capture The Ether challenges. There are plenty of solutions around the web - my goal was to solve the challenges locally, avoiding Etherscan when possible, and writing code locally. You can find the code here. Let’s begin.Fuzzy IdentityTo solve this challenge we need successfully authenticate as "smarx". The challenge gives us the conditions we need to meet:Have a contract that returns "smarx" when the function name is ...]]></description>
            <content:encoded><![CDATA[<p>In this post, I will share my explanations for the Account section of the Capture The Ether challenges. There are plenty of solutions around the web - my goal was to solve the challenges locally, avoiding Etherscan when possible, and writing code locally.</p><p>You can find the code <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/kyrers/CTE-Solutions">here</a>.</p><p>Let’s begin.</p><h2 id="h-fuzzy-identity" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Fuzzy Identity</h2><p>To solve this challenge we need successfully authenticate as &quot;smarx&quot;. The challenge gives us the conditions we need to meet:</p><ol><li><p>Have a contract that returns &quot;smarx&quot; when the function <code>name</code> is called;</p></li><li><p>That same contract must be deployed at an address that ends with <code>badc0de</code>.</p></li></ol><p>Step 1 is pretty simple, we just need a function called <code>name</code> that returns <code>bytes32(&quot;smarx&quot;)</code>. As for step 2, the EVM now has an opcode called <code>CREATE2</code> that allows us to deploy a contract to a pre-computed address, provided we give it the contract bytecode and an <code>uint256 salt</code> to use. This is probably not what the author had in mind, but we should take advantage of improvements to the EVM.</p><p>To achieve step 2, take a look at <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/kyrers/contract-factory">this repo</a>. It allows you to deploy a factory contract that will use the <code>CREATE2</code> opcode to deploy our <code>FuzzyIdentityHelper</code> contract to an address that ends with <code>badc0de</code>, provided we send the correct salt along with the <code>FuzzyIdentityHelper</code> bytecode. This will allow us to solve the challenge. The repository contains instructions on how it should be done.</p><p>Our <code>FuzzyIdentityHelper</code> contract will have our challenge contract address hardcoded, although it&apos;s entirely possible to deploy bytecode with constructor params. It&apos;s just that this way is easier and does not require you to change the factory repo code.</p><p>So, to recap, here are the steps needed:</p><ol><li><p>Deploy the factory contract to the Ropsten network;</p></li><li><p>Get our <code>FuzzyIdentityHelper</code> contract bytecode;</p></li><li><p>Determine the salt to use to deploy it to an address ending with <code>badc0de</code>. When introducing the needed information in the <code>findHash.js</code> script, remember that the <code>deployerAddress</code> is the address of the factory contract you deployed on step 1, not your own;</p></li><li><p>Use the factory contract to deploy our <code>FuzzyIdentityHelper</code> to the address determined in step 3;</p></li><li><p>Get the <code>FuzzyIdentityHelper</code> contract we just deployed;</p></li><li><p>Call the <code>FuzzyIndentityHelper</code> <code>authenticate</code> function;</p></li><li><p>Win;</p></li></ol><h2 id="h-public-key" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Public Key</h2><p>This challenge isn&apos;t about hacking a smart contract. It&apos;s about understanding how signatures work. So, you should read the docs before solving this.</p><p>A couple of important things to know:</p><ul><li><p>Ethereum signatures use the ECDSA algorithm. They consist of two integers <code>r,s</code> and <code>v</code> which Ethereum uses as a recover identifier;</p></li><li><p>What is actually signed is the serialized transaction hash, according to the current docs;</p></li><li><p><code>recoverPublicKey</code> come with a prefix, such as <code>0x04</code> which means that both <code>r</code> and <code>s</code> follow;</p></li></ul><p>Now, we will actually need some help from etherscan to begin with. The challenge contract contains the owner address, but to get its public key, we need a transaction signed by said address. If you search ropsten etherscan for the address you&apos;ll find an outgoing transaction, just what we need.</p><p>So, here&apos;s what&apos;s needed to solve this challenge:</p><ol><li><p>Get the challenge owner outgoing transaction hash from etherscan;</p></li><li><p>Get the transaction object;</p></li><li><p>Reconstruct both the transaction data and signature objects;</p></li><li><p>Serialize the transaction data object;</p></li><li><p>Hash it;</p></li><li><p>Recover the public key using both the transaction data hash and the signature object;</p></li><li><p>Format it;</p></li><li><p>Get the challenge contract;</p></li><li><p>Authenticate yourself.</p></li></ol><h2 id="h-account-takeover" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Account Takeover</h2><p>This challenge is actually harder than the scoring suggests. It implies having knowledge about how ECDSA works and how to exploit its vulnerabilities. The math behind this is beyond the scope of this explanation and, to be honest, I am not knowledgeable enough to explain it. Here&apos;s a <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://bitcoin.stackexchange.com/questions/35848/recovering-private-key-when-someone-uses-the-same-k-twice-in-ecdsa-signatures">stackoverflow discussion</a> that should get you started.</p><p>As a basic overview, ECDSA signatures can be exploited with the goal of recovering private keys when the same nonce is used to sign two transactions. We&apos;ve determined in the previous challenge that a signature object consists of <code>r</code>, <code>s</code>, and <code>v</code> values. If two transactions have the same <code>r</code>, it means the same nonce was used.</p><p>ECDSA signatures are determined using <code>s = k⁻¹ (z + r * privateKey) (mod p)</code>, where: - <code>k</code> is the nonce; - <code>z</code> is the transaction hash; - <code>r</code> is the <code>r</code> value of the signature object. This is what must be common between two transactions for this exploit to work; - <code>(mod p)</code> is a congruence modulo where <code>p</code> is a constant.</p><p>First, we need to determine all the possible <code>k</code> values. Then, we determine the private key that matches those <code>k</code>&apos;s and find out which one matches our account to hack address. After that, it&apos;s a matter of connecting to it using our new wallet and authenticating ourselves.</p><p>Note that everybody solving this challenge uses the same account, so if you&apos;re authenticate transaction is failing, it may be because the account has no ETH. Check on ropsten on etherscan and send it some if needed.</p><p>So, here are the steps:</p><ol><li><p>Find two transactions sent by the account to hack that have the same <code>r</code> for the signature. This is hard to find because there are so many, so I found out which one were by searching different solutions to this challenge and kept them in the <code>accountTakeover.js</code> script so you don&apos;t have to;</p></li><li><p>Calculate the <code>s</code> and <code>z</code> values needed to determine our possible <code>k</code>&apos;s;</p></li><li><p>Determine our possible <code>k</code>&apos;s and the matching private keys;</p></li><li><p>Determine which private key corresponds to the address we need;</p></li><li><p>Get the challenge contract and connect to it using the hacked account wallet;</p></li><li><p>Authenticate ourselves;</p></li></ol><p>Again, I advise you to research how ECDSA allows for private key recovery if the same nonce is used twice before solving this. And if you understand the math, feel free to hit me up and explain it to me :)</p>]]></content:encoded>
            <author>kyrers@newsletter.paragraph.com (kyrers)</author>
        </item>
        <item>
            <title><![CDATA[Capture The Ether Math Solutions]]></title>
            <link>https://paragraph.com/@kyrers/capture-the-ether-math-solutions</link>
            <guid>CUH8Rj96hW7bMOdBmbzW</guid>
            <pubDate>Sun, 11 Sep 2022 18:17:34 GMT</pubDate>
            <description><![CDATA[In this post, I will share my explanations for the Math section of the Capture The Ether challenges. There are plenty of solutions around the web - my goal was to solve the challenges locally, avoiding Etherscan when possible, and writing code locally. You can find the code here. Let’s begin.Token SaleLooking at the contract, it may seem like everything is correct. However, if you look closely, you&apos;ll see that this contract does not implement SafeMath. Remember, SafeMath is implemented o...]]></description>
            <content:encoded><![CDATA[<p>In this post, I will share my explanations for the Math section of the Capture The Ether challenges. There are plenty of solutions around the web - my goal was to solve the challenges locally, avoiding Etherscan when possible, and writing code locally.</p><p>You can find the code <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/kyrers/CTE-Solutions">here</a>.</p><p>Let’s begin.</p><h2 id="h-token-sale" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Token Sale</h2><p>Looking at the contract, it may seem like everything is correct. However, if you look closely, you&apos;ll see that this contract does not implement SafeMath.</p><p>Remember, SafeMath is implemented on the language level since solidity version 0.8. This challenge uses an older version, so there&apos;s the possibility of overflows. This is how we game the contract.</p><p>If you look at the buy function, <code>require(msg.value == numTokens * PRICE_PER_TOKEN)</code> has the potential to overflow. Overflowing here would allow us to get a gigantic amount of tokens for a low price. We then sell 1 token for 1 ether, making a profit on the way and leaving the contract with a balance &lt; 1, which is the required condition for us to solve the challenge.</p><p>Once again, the code is explained. Still, here are the steps needed:</p><ol><li><p>Get the contract abi and address;</p></li><li><p>Get the private key of the ropsten account you are using to interact with Capture The Ether. Otherwise, you can&apos;t pass the challenge as CTE doesn&apos;t know who you are;</p></li><li><p>Get the contract and connect with it using your account;</p></li><li><p>Determine the amount of tokens to send to cause an overflow;</p></li><li><p>Determine the amount of ether to send;</p></li><li><p>Buy our tokens and wait for them to arrive;</p></li><li><p>Sell 1 token;</p></li><li><p>Profit;</p></li></ol><p>To keep this description short, steps 4 and 5 are detailed in the <code>tokenSale.js</code> script. Take a look.</p><h2 id="h-token-whale" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Token Whale</h2><p>Looking at this contract, you&apos;ll hopefully notice that, once again, it is subject to over and underflows. However, this is part of the solution. Not all of it.</p><p>If you look at the <code>_transfer</code> function, it spends <code>msg.sender</code> tokens instead of tokens from the <code>from</code> address passed to the <code>transferFrom</code> function. This means that, if we successfully call <code>transferFrom</code> from an account with 0 tokens, <code>balanceOf[msg.sender] -= value</code> will underflow, causing the said account to receive a gigantic amount of tokens - 2**256 - 1 to be exact.</p><p>After that, all we need is to send 1000000 tokens from the helper account to our account, and we&apos;ll have successfully solved the challenge.</p><p>You may be thinking &quot;Why do I need a second account? Couldn&apos;t I do this just using my account?&quot;. You couldn&apos;t. You&apos;d never pass the <code>require(balanceOf[from] &gt;= value)</code> check, as you&apos;d need <code>value</code> to be 1001 to cause an underflow.</p><p>Once again, the code is explained. Still, here are the steps needed:</p><ol><li><p>Get the contract abi and address;</p></li><li><p>Get the private key of the ropsten account you are using to interact with Capture The Ether. Otherwise, you can&apos;t pass the challenge as CTE doesn&apos;t know who you are;</p></li><li><p>Get a second ropsten account;</p></li><li><p>Approve the second account to spend funds from your account. Sign this transaction using your main account;</p></li><li><p>Transfer 1 token from your main account, to that same account. Sign this transaction using the second account. This will cause the underflow and give the second account an enormous amount of tokens;</p></li><li><p>Send the required 1000000 tokens from the second account back to your main account. Sign this transaction using the second account.</p></li><li><p>Wait for them to arrive, and you&apos;ll have solved the challenge.</p></li></ol><h2 id="h-retirement-fund" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Retirement Fund</h2><p>Looking at this contract, you&apos;ll hopefully notice that, once again, it is subject to over and underflows. However, this is part of the solution. Not all of it.</p><p>If you look at the contract, you&apos;ll see that <code>withdraw</code> checks that <code>msg.sender == owner</code>, since the <code>owner</code> is the CTE factory, this function is of no use to us. Meaning, that our solution can only make use of the <code>collectPenalty</code> function.</p><p>As we&apos;ve established, the contract is subject to over and underflows, meaning that <code>uint256 withdrawn = startBalance - address(this).balance;</code> can be underflowed, allowing us to drain all the ETH the contract has.</p><p>To achieve this, <code>address(this).balance</code> has to be &gt; 1, which in turn means that we&apos;ll have to find a way to add some ether to the contract.</p><p>The contract has no payable functions, so how can we send ether to the contract? If you look through the Ethereum documentation, you&apos;ll hopefully realize that the easiest way to do this is to self-destruct another contract that has some ether in it, and send that contract ETH to the CTE challenge contract.</p><p>Once again, the code is explained. Still, here are the steps needed:</p><ol><li><p>Get the contract abi and address;</p></li><li><p>Get the private key of the ropsten account you are using to interact with Capture The Ether. Otherwise, you can&apos;t pass the challenge as CTE doesn&apos;t know who you are;</p></li><li><p>Get the contract and connect with it using your account;</p></li><li><p>Deploy our helper contract. Send 1 eth as the msg.value. Don&apos;t forget to add the challenge address to the contract kill function;</p></li><li><p>Destroy our helper contract;</p></li><li><p>Call the challenge contract <code>collectPenalty</code> function;</p></li><li><p>Wait for challenge contract to be drained and you&apos;ll have solved the challenge</p></li></ol><h2 id="h-mapping" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Mapping</h2><p>To solve this challenge, we need to somehow set <code>isComplete</code> to true, or 1.</p><p>First, you should read the Ethereum docs to understand how contract storage works. You&apos;ll hopefully reach the conclusion that <code>isComplete</code> is at <code>slot 0</code>. Then, <code>slot 1</code> has the <code>map[]</code> length.</p><p>From the documentation, we can also gather that: <code>keccak256(1)</code> has the <code>map[0]</code> value, <code>keccak256(1) + 1</code> has the <code>map[1]</code> value and so forth. This is because the contract array is a dynamic size array, so the EVM reserves one slot to store the array length.</p><p>From this, we can expect that if we set the map length to 2**256 - 1, the slot that contains the <code>isComplete</code> value will be occupied by the array, allowing us to modify it if we know the corresponding storage address.</p><p>Since we know that <code>map[0]</code> is at <code>keccak256(1)</code>, we also know that <code>map[isComplete] = 2**256 - keccack256(1)</code>.</p><p>Once again, the code is explained. Still, here are the steps needed:</p><ol><li><p>Get the contract abi and address;</p></li><li><p>Get the private key of the ropsten account you are using to interact with Capture The Ether. Otherwise, you can&apos;t pass the challenge as CTE doesn&apos;t know who you are;</p></li><li><p>Get the contract and connect with it using your account;</p></li><li><p>Expand the array bounds to occupy the <code>isComplete</code> slot;</p></li><li><p>Determine the storage address of the <code>isComplete</code> value;</p></li><li><p>Change it to 1 (true);</p></li></ol><h2 id="h-donation" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Donation</h2><p>Looking at the contract, you&apos;ll hopefully notice two things almost immediately: the <code>donate</code> function calculates <code>scale</code> wrong, as it results in <code>10**36</code> since <code>1 ether == 10**18</code> already, and that we&apos;ll need to somehow call <code>withdraw</code> to drain the contract.</p><p>Taking a deeper look, the <code>withdraw</code> function requires us to be the contract <code>owner</code>, so we know what our goal is: become the contract owner.</p><p>If you read the storage layout docs in the previous challenge you&apos;ll remember that struct and array data use their own slots. Since the contract struct is only initialized when the <code>donate</code> function is called, we can assume that slot 0 has the <code>Donation[]</code> size and that slot 1 has the <code>owner</code> address. So, we must write to slot 1 of the contract storage, but how?</p><p>This is where the <code>donate</code> function is wrong again. It declares <code>Donation donation</code> without using either the <code>memory</code> or <code>storage</code> keywords, which means that this is just an uninitialized pointer to the contract storage. Since the struct has to <code>uint256</code> values, <code>etherAmount</code> will write to slot 1, where the <code>owner</code> address is stored! All we need to do is determine the <code>uint256</code> value of our address and send that as the <code>etherAmount</code>, with the needed <code>msg.value</code> to pass the <code>require</code> check.</p><p>Once again, the code is explained. Still, here are the steps needed:</p><ol><li><p>Get the contract abi and address;</p></li><li><p>Get the private key of the ropsten account you are using to interact with Capture The Ether. Otherwise, you can&apos;t pass the challenge as CTE doesn&apos;t know who you are;</p></li><li><p>Get the contract and connect with it using your account;</p></li><li><p>Determine the <code>uint256</code> value of our address;</p></li><li><p>Calculate the needed <code>msg.value</code>;</p></li><li><p>Make the donation;</p></li><li><p>Withdraw the eth;</p></li></ol><h2 id="h-fifty-years" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Fifty Years</h2><p>This is the challenge that awards the most points for a reason. It requires an orderly combination of transactions, with the intent to exploit the contract using the techniques we&apos;ve used in the previous challenges.</p><p>First, let&apos;s try to determine our goal. Looking at the <code>withdra</code>w function, particularly the second <code>require</code> check, we can see that we need to send an <code>index</code> for a contribution that has an <code>unlockTimestamp</code> in the past and corresponds to the last contribution made, so we drain all the contributions. This is our goal. Now, how do we do this?</p><p>It should be clear that the <code>upsert</code> function is key. If we look through its code, we can identify two potential issues: <code>require(timestamp &gt;= queue[queue.length - 1].unlockTimestamp + 1 days)</code> is subject to overflows, and the <code>else</code> statement relies on a previous declaration of <code>contribution</code>, which makes it an uninitialized storage pointer, which allows us to access storage slots 0 (<code>queue.length</code>) and 1 (<code>head</code>) (remember this from the previous challenge?). Knowing this, we can determine two steps needed:</p><ul><li><p>Call <code>upsert</code> once with a new contribution designed to prepare an overflow of the <code>timestamp</code> when we make the second contribution, allowing the second contribution to have <code>timestamp = 0</code>. Since the <code>contribution.unlockTimestamp = timestamp</code> writes to the <code>head</code> storage slot, after this first contribution <code>head</code> will have a gigantic value.</p></li><li><p>Make another <code>upsert</code> call that resets <code>head</code> to 0, while also having an <code>unlockTimestamp == 0</code>, which will work, because we&apos;ve prepared the overflow in the first <code>upsert</code> call.</p></li></ul><p>This will total, 3 contributions (adding to the one that is made when we begin the challenge on CTE). There are three things we need to pay attention to while executing the two contributions:</p><ul><li><p>Time units are parsed to seconds, so we need to prepare the overflow taking that into account;</p></li><li><p>Ether units are handled in <code>wei</code>, so if we send ETH to the contract the actual <code>queue.length</code> will be <code>x ETH * 10**18</code>. So we need to send <code>wei</code>, not ether as the <code>msg.value</code>;</p></li><li><p><code>queue.push</code> increments the <code>queue.length</code> before actually inserting the contribution. We&apos;ve determined that the <code>queue.length</code> will be manipulated by the line <code>contribution.amount = msg.value</code>. This means that if we want to keep an accurate <code>queue.length</code> value, we need to be wary of the <code>msg.value</code> we send with each <code>upsert</code> call. We know that before our first <code>upsert</code> call the <code>queue.length</code> is 1, because one contribution was made when we began the challenge. However, we need to send 1 <code>wei</code> in the first contribution because, even though the line <code>contribution.amount = msg.value</code> will maintain the <code>queue.length</code> at 1 (when it&apos;s actually 2 since this is the second contribution made), the line <code>queue.push(contribution)</code> will increment it by 1, which will give us the correct <code>queue.length</code> of 2. We follow the same logic for the second <code>upsert</code> call and send 2 <code>wei</code>, since 2 + 1 = 3, which by then will be the correct <code>queue.length</code>.</p></li></ul><p>At first glance, we may assume that, after these steps, calling <code>withdraw(2)</code> would drain the contract. However, this transaction would fail. Since <code>queue.push</code> increments the <code>queue.length</code> before actually pushing the contribution, <code>contribution.amount = msg.value</code> will be incremented too. Visualize it this way:</p><pre data-type="codeBlock" text="- Contribution 0 (made by CTE): contribution.amount == msg.value == 1 ETH;
- Contribution 1 (us): contribution.amount == msg.value == 1 wei + `queue.push` == 2 wei;
- Contribution 2 (us): contribution.amount == msg.value == 2 wei + `queue.push` == 3 wei;
- Contract total == 1.00...03 ETH, Contributions total == 1.00...05 ETH.
"><code><span class="hljs-operator">-</span> Contribution <span class="hljs-number">0</span> (made by CTE): contribution.amount <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">1</span> ETH;
<span class="hljs-operator">-</span> Contribution <span class="hljs-number">1</span> (us): contribution.amount <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">1</span> <span class="hljs-literal">wei</span> <span class="hljs-operator">+</span> `queue.<span class="hljs-built_in">push</span>` <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">2</span> <span class="hljs-literal">wei</span>;
<span class="hljs-operator">-</span> Contribution <span class="hljs-number">2</span> (us): contribution.amount <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">2</span> <span class="hljs-literal">wei</span> <span class="hljs-operator">+</span> `queue.<span class="hljs-built_in">push</span>` <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">3</span> <span class="hljs-literal">wei</span>;
<span class="hljs-operator">-</span> Contract total <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">1.00</span>...03 ETH, Contributions total <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">1.00</span>...05 ETH.
</code></pre><p>Hence, the transaction will fail until we add <code>2 wei</code> to the contract, because we&apos;re trying to withdraw more ETH than the contract has. This can be done by taking a page out of the Retirement Fund challenge. Just create a contract that receives <code>2 wei</code> on deploy, and then self-destruct said contract, sending the <code>2 wei</code> to our challenge contract. After that, call <code>withdraw(2)</code> and we win!</p><p>Once again, the code is explained. Still, here are the steps needed:</p><ol><li><p>Get the contract abi and address;</p></li><li><p>Get the private key of the ropsten account you are using to interact with Capture The Ether. Otherwise, you can&apos;t pass the challenge as CTE doesn&apos;t know who you are;</p></li><li><p>Get the contract and connect with it using your account;</p></li><li><p>Deploy our FiftyYearsHelper contract and fund it with <code>2 wei</code>;</p></li><li><p>Call <code>upsert</code> a first time to prepare the <code>timestamp</code> overflow;</p></li><li><p>Call <code>upsert</code> a second time to set <code>head</code> to 0;</p></li><li><p>Kill our FiftyYearsHelper contract;</p></li><li><p>Call <code>withdraw(2)</code>;</p></li></ol>]]></content:encoded>
            <author>kyrers@newsletter.paragraph.com (kyrers)</author>
        </item>
        <item>
            <title><![CDATA[Capture The Ether Lottery Solutions]]></title>
            <link>https://paragraph.com/@kyrers/capture-the-ether-lottery-solutions</link>
            <guid>2bBaZFfA6sUZh1C7NmtF</guid>
            <pubDate>Sun, 11 Sep 2022 17:24:21 GMT</pubDate>
            <description><![CDATA[In this post, I will share my explanations for the Lottery section of the Capture The Ether challenges. There are plenty of solutions around the web - my goal was to solve the challenges locally, avoiding Etherscan when possible, and writing code locally. You can find the code here. Let’s begin.Guess The NumberThis is very similar to the warmup challenges. In the code, you will find the script guessTheNumber.js. The code has comments explaining what each line does. Still, here is what we need...]]></description>
            <content:encoded><![CDATA[<p>In this post, I will share my explanations for the Lottery section of the Capture The Ether challenges. There are plenty of solutions around the web - my goal was to solve the challenges locally, avoiding Etherscan when possible, and writing code locally.</p><p>You can find the code <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/kyrers/CTE-Solutions">here</a>.</p><p>Let’s begin.</p><h2 id="h-guess-the-number" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Guess The Number</h2><p>This is very similar to the warmup challenges. In the code, you will find the script <code>guessTheNumber.js</code>. The code has comments explaining what each line does. Still, here is what we need to do:</p><ol><li><p>Looking at the constructor you will notice that you need to have 1 Ropsten ETH in your account before pressing the <code>Begin Challenge</code> button, otherwise the transaction will fail;</p></li><li><p>After deploying the contract we can now solve the challenge locally. Again, we need to get the contract abi and address. Then, we need to connect to it using our account.</p></li><li><p>As you must have already noticed, the answer is in the code. The number is 42. However, look at the <code>guess()</code> function. Where have you seen that <code>require</code> statement before? Exactly, you need to send 1 ETH to the function in order to solve it.</p></li></ol><h2 id="h-guess-the-secret-number" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Guess The Secret Number</h2><p>This is almost equal to the previous challenge. In the code, you will find the script <code>guessTheSecretNumber.js</code>. The code has comments explaining what each line does. Still, here is what we need to do:</p><ol><li><p>Do steps 1 and 2 from the previous challenge;</p></li><li><p>This time we only have the hash of the number we need to send to the <code>guess()</code> function. We need to figure out the number by running a loop, hashing the current loop counter value, and then checking if the hash matches. You probably saw that the <code>guess()</code> function takes an <code>uint8</code> as a parameter. This tells us that the number is less than 256 because the <code>uint8</code> max value is <code>2⁸-1 = 255</code>;</p></li><li><p>When we have the correct number, we just need to call the <code>guess()</code> function and send 1 ETH to it again.</p></li></ol><h2 id="h-guess-the-random-number" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Guess The Random Number</h2><p>This challenge requires a bit more work. There are at least three ways to solve this:</p><ol><li><p>Check the Etherscan contract creation transaction, and look for state changes. You will find the solution there. This is not the goal of this solution;</p></li><li><p>Get the value in position 0 of the contract storage;</p></li><li><p>Compute the solution using the same formula that the challenge uses.</p></li></ol><p>These last two options allow us to interact with the contract. Option 2 is the easiest, but both can be found in the <code>guessTheRandomNumber.js</code> script. As always, the code has comments explaining what each line does. Still, here is what&apos;s needed for each solution:</p><p>For both possible solutions, we need to do steps 1 and 2 from the previous challenge, and then:</p><p><strong>Solution 2:</strong></p><ol start="2"><li><p>Get the value from position 0 of the contract storage and convert it to uint8;</p></li><li><p>When we have the correct number, we just need to call the <code>guess()</code> function and send 1 ETH to it again.</p></li></ol><p><strong>Solution 3:</strong></p><ol start="2"><li><p>We need the hash of the contract creation transaction, which we can get from Etherscan.</p></li><li><p>Get the contract creation transaction itself using the hash;</p></li><li><p>Get the block in which the transaction was included;</p></li><li><p>Get the block parent hash and block timestamp. If you look at the code, you&apos;ll notice that <code>block.blockhash(block.number - 1)</code> - that&apos;s why we get the parent hash of the block the transaction was included in;</p></li><li><p>Compute the hash using the above values;</p></li><li><p>Get the last byte of the hash, because the solution is an <code>uint8</code>, and convert it to a number.</p></li><li><p>When we have the correct number, we just need to call the <code>guess()</code> function and send 1 ETH to it again.</p></li></ol><h2 id="h-guess-the-new-number" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Guess The New Number</h2><p>This challenge gets a little bit trickier because the answer is calculated when we call the guess function.</p><p>One approach to solve this challenge is to create a contract that computes the answer and calls the challenge <code>guess()</code> function in the same block. This way, our answer is always correct.</p><p>You will find the contract in <code>contracts/GuessTheNewNumberSolver.sol</code>. Once again, the code is explained. Still, here are the steps needed:</p><ol><li><p>Look at the contract and understand what it is doing. The contract has comments explaining everything.</p></li><li><p>We need to deploy the contract. User your account so you can get your ETH back later, after solving the challenge;</p></li><li><p>Call the <code>guess()</code> function of the contract you just deployed. As a parameter, we need to send it the challenge address;</p></li><li><p>Call the withdraw function to get your ETH back;</p></li></ol><h2 id="h-predict-the-future" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Predict The Future</h2><p>This challenge gets even trickier because you have to lock in your guess before an answer is calculated.</p><p>Luckily for us, we know the answer is between 0 and 9 because we <code>mod</code> the calculated <code>uint8</code> by 10. However, knowing this isn&apos;t enough.</p><p>The key to solving this challenge is settling in the correct block. So, one approach to solve this challenge is to create a contract that locks a guess between 0 and 9. Then, we repeatedly call the <code>predict()</code> function of our contract until it determines that settling on the current block will produce the result that matches our locked guess.</p><p>You will find the contract in <code>contracts/PredictTheFutureSolver.sol</code>. Once again, the code is explained. Still, here are the steps needed:</p><ol><li><p>Look at the contract and understand what it is doing. The contract has comments explaining everything.</p></li><li><p>We need to deploy the contract. User your account so you can get your ETH back later, after solving the challenge;</p></li><li><p>Call the <code>lockGuess()</code> function of the contract you just deployed. As a parameter, we need to send our guess;</p></li><li><p>Call the predict function until it determines that settling will produce the result we guessed;</p></li><li><p>Call the withdraw function to get your ETH back;</p></li></ol><h2 id="h-predict-the-future-block-hash" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Predict The Future Block Hash</h2><p>At first, this challenge may seem like a more complicated version of the previous one. However, it is not.</p><p>Looking at the contract, you&apos;ll see that the solution is determined by calculating the blockhash of the block you locked your guess in + 1. It may seem that this will require a tremendous amount of luck to guess correctly. However, what you should do first is to go to the solidity documentation and read about the blockhash function. Do it.</p><p>You&apos;ll hopefully see that it returns the hash of the last 256 blocks. For earlier blocks it will return 0 - this is how we solve the challenge! We simply lock our guess that the hash will be 0, then we get the block number our transaction was included in, wait for 257 blocks, and settle. It will return 0 and we will solve the challenge.</p><p>Once again, the code is explained. Still, here are the steps needed:</p><ol><li><p>Get the contract abi and address;</p></li><li><p>Get the private key of the ropsten account you are using to interact with Capture The Ether. Otherwise, you can&apos;t pass the challenge as CTE doesn&apos;t know who you are;</p></li><li><p>Get the contract and connect with it using your account;</p></li><li><p>Lock your guess. Remember, guess 0.</p></li><li><p>Wait for 257 blocks. This will take some time. Go rest a little bit :)</p></li><li><p>Settle and get your ETH back;</p></li></ol>]]></content:encoded>
            <author>kyrers@newsletter.paragraph.com (kyrers)</author>
        </item>
        <item>
            <title><![CDATA[Capture The Ether Warmup Solutions]]></title>
            <link>https://paragraph.com/@kyrers/capture-the-ether-warmup-solutions</link>
            <guid>IISfBhPgO1Nla7mz3IyQ</guid>
            <pubDate>Sun, 11 Sep 2022 16:52:19 GMT</pubDate>
            <description><![CDATA[In this post, I will share my explanations for the Warmup section of the Capture The Ether challenges. There are plenty of solutions around the web - my goal was to solve the challenges locally, avoiding Etherscan when possible, and writing code locally. You can find the code here. Let’s begin.Call Me / Set NicknameCall Me and Set Nickname are very similar, so there is code only for the more complex one - Set Nickname. In the code, you will find the script setNickname.js. The code has comment...]]></description>
            <content:encoded><![CDATA[<p>In this post, I will share my explanations for the Warmup section of the Capture The Ether challenges. There are plenty of solutions around the web - my goal was to solve the challenges locally, avoiding Etherscan when possible, and writing code locally.</p><p>You can find the code <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/kyrers/CTE-Solutions">here</a>.</p><p>Let’s begin.</p><h2 id="h-call-me-set-nickname" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Call Me / Set Nickname</h2><p><em>Call Me</em> and <em>Set Nickname</em> are very similar, so there is code only for the more complex one - <em>Set Nickname</em>. In the code, you will find the script <code>setNickname.js</code>. The code has comments explaining what each line does. Still, here is what we need to do:</p><ol><li><p>Get the contract abi and address;</p></li><li><p>Get the private key of the ropsten account you are using to interact with Capture The Ether. Otherwise, you can&apos;t pass the challenge as CTE doesn&apos;t know who you are;</p></li><li><p>Get the contract and connect with it using your account;</p></li><li><p>Call the <code>setNickname(…)</code> function sending the nickname you want as a parameter; For the <em>Call Me</em> challenge, it&apos;s even easier, as the function requires no parameters.</p></li></ol>]]></content:encoded>
            <author>kyrers@newsletter.paragraph.com (kyrers)</author>
        </item>
    </channel>
</rss>