<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[The 0xMacro Blog]]></title><description><![CDATA[Get advanced content on Solidity, the EVM, and Web3.]]></description><link>https://0xmacro.com/blog/</link><image><url>https://0xmacro.com/blog/favicon.png</url><title>The 0xMacro Blog</title><link>https://0xmacro.com/blog/</link></image><generator>Ghost 5.87</generator><lastBuildDate>Tue, 07 Apr 2026 16:02:25 GMT</lastBuildDate><atom:link href="https://0xmacro.com/blog/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[How To Consume Chainlink Price Feeds Safely]]></title><description><![CDATA[<p>Chainlink price feeds are reliable, but it is crucial to have circuit breakers to prevent <a href="https://twitter.com/0xngmi/status/1524894553068691456?ref=0xmacro.com">any issues from a single source</a>. Using a single entity is not ideal from a decentralization perspective as well, and it is better to have backup plans in case of system failure. Many developers were</p>]]></description><link>https://0xmacro.com/blog/how-to-consume-chainlink-price-feeds-safely/</link><guid isPermaLink="false">640757a1f337fa0021203d5b</guid><dc:creator><![CDATA[curiousapple]]></dc:creator><pubDate>Mon, 20 Mar 2023 15:05:57 GMT</pubDate><media:content url="https://0xmacro.com/blog/content/images/2023/03/BIR-Environment-2-2048px_5_2_2048px-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://0xmacro.com/blog/content/images/2023/03/BIR-Environment-2-2048px_5_2_2048px-2.jpg" alt="How To Consume Chainlink Price Feeds Safely"><p>Chainlink price feeds are reliable, but it is crucial to have circuit breakers to prevent <a href="https://twitter.com/0xngmi/status/1524894553068691456?ref=0xmacro.com">any issues from a single source</a>. Using a single entity is not ideal from a decentralization perspective as well, and it is better to have backup plans in case of system failure. Many developers were unaware of circuit breakers they could implement when we pointed this out. <br>So here we go!<br><br><strong>Chainlink Price Feeds and Circuit Breakers !!!</strong></p><p><strong>Disclaimer:</strong> This document assumes that you always intend to fetch a price greater than zero.<br><strong>Credits:</strong> Shoutout to <a href="https://github.com/liquity/dev/blob/main/packages/contracts/contracts/PriceFeed.sol?ref=0xmacro.com">Liquity&apos;s price feed</a>; their code inspired a lot of the following content</p><hr><h2 id="implementing-circuit-breakers-with-chainlink-price-feeds"><strong>Implementing Circuit Breakers with Chainlink Price Feeds</strong></h2><h3 id="step-1-call-latestrounddata-on-price-feed-aggregator"><br><strong>Step 1: Call <code>latestRoundData()</code> on Price Feed Aggregator</strong></h3><p>Don&apos;t use <a href="https://docs.chain.link/data-feeds/api-reference?ref=0xmacro.com#latestanswer">latestAnswer</a>, it&apos;s deprecated</p><pre><code class="language-solidity">struct ChainlinkResponse {
    uint80 roundId;
    int256 answer;
    uint256 updatedAt;
    bool success;
}

ChainlinkResponse memory cl;

try priceAggregator.latestRoundData() returns (
    uint80 roundId,
    int256 answer,
    uint256 /* startedAt */,
    uint256 updatedAt,
    uint80 /* answeredInRound */
) {
    cl.success = true;
    cl.roundId = roundId;
    cl.answer = answer;
    cl.updatedAt = updatedAt;
}
</code></pre><h3 id="step-2-sanity-check"><strong>Step 2: Sanity Check</strong></h3><p>Perform a sanity check to verify that the fetched data is valid.</p><pre><code class="language-solidity">if (
    cl.success == true &amp;&amp;
    cl.roundId != 0 &amp;&amp;
    cl.answer &gt;= 0 &amp;&amp;
    cl.updatedAt != 0 &amp;&amp; 
    cl.updatedAt &lt;= block.timestamp
) {
    continue;
} else {
    step 6; // means chainlink failed the check
}
</code></pre><h3 id="step-3-staleness-check"><strong>Step 3: Staleness Check</strong></h3><p>Verify if the fetched data is stale.</p><pre><code class="language-solidity">if (block.timestamp - cl.updatedAt &gt; TIMEOUT) {
    step 6;
} else {
    continue;
}
</code></pre><p>Deprecation of <strong><code>answeredInRound</code></strong> check. </p><blockquote><em>In the past, it was recommended to perform a staleness check by using the <strong><code>answeredInRound</code></strong> parameter. However, this parameter is now deprecated, and it is no longer necessary to check for staleness. <br>You can verify this by examining the <strong><code>OffchainAggregator.sol</code></strong> contract, specifically at line 810 where the <strong><code>latestRoundData()</code></strong> function is defined. <br>Here, you will notice that <strong><code>answeredInRound</code> </strong>is always equal to <strong><code>roundId</code>.</strong></em><br><a href="https://etherscan.deth.net/address/0x780f1bD91a5a22Ede36d4B2b2c0EcCB9b1726a28?ref=0xmacro.com#code"><em>https://etherscan.deth.net/address/0x780f1bD91a5a22Ede36d4B2b2c0EcCB9b1726a28#code</em></a><br><em>But please be aware that this may not yet be the case for all feeds, so it is important to double-check the specific feed you are working with.</em></blockquote><h3 id="step-4-price-deviation-check"><strong>Step 4: Price Deviation Check</strong></h3><p>Perform a price deviation check (optional).<br>For some use cases, this is detrimental; choose wisely :)</p><pre><code class="language-solidity">if (abs(cl.answer - lastGoodPrice) / lastGoodPrice &gt; ACCETABLE_DEVIATON) {
    step 6; // means chainlink failed the check
} else {
    continue;
}
</code></pre><h3 id="step-5-store-last-good-price"><strong>Step 5: Store Last Good Price</strong></h3><p>Store the last good price fetched by Chainlink.</p><pre><code class="language-solidity">lastGoodPrice = cl.answer; // chainlink&apos;s fetched price
return lastGoodPrice;
</code></pre><h3 id="step-6-secondary-oracle-and-mitigating-circuit-breaks">Step 6: Secondary Oracle and <strong>Mitigating Circuit Breaks.</strong></h3><p>If you are open to adding a secondary oracle, start from A or skip to B.</p><h3 id="a-use-secondary-oracle"><strong>A.</strong>  Use Secondary Oracle</h3><p>When it comes to oracles, having a fallback option is always a good idea to avoid a single point of failure. There are various secondary oracle options to choose from, depending on your preferences and the asset being used.</p><ol><li><strong>Uniswap TWAP:</strong> For assets that have a pool with good liquidity on Uniswap.</li><li><strong>Another off-chain oracle:</strong> For example, Tellor.</li><li><strong>Your own oracle:</strong> Not recommended, but if nothing works from above, you can build a simple oracle with setPrice and getPrice functions, with access only for the owner. This will only be accessed when Chainlink fails, so it&apos;s a valid trade-off between security and decentralization. The risk with this is that you need to be cautious of your off-chain source and the security of owner keys.</li></ol><p>Once you have a secondary oracle in place, you can implement its own circuit breakers to ensure that your smart contract only uses reliable price data, and if they fail as well, go to B (Mitigating Circuit Breaks).</p><pre><code class="language-solidity">if (price fetch on 2nd oracle is successful and all of its own checks are passed) {
    lastGoodPrice = secondaryOracle&apos;s fetchedPrice;
    return lastGoodPrice;
} else {
    go to B;
}
</code></pre><h3 id="b-mitigating-circuit-breaks"><strong>B. Mitigating Circuit Breaks</strong></h3><p>When none of the oracles are working, <strong>it&apos;s up to you</strong> to determine the best course of action for your protocol. You should consider the best-case scenario for the protocol and the worst-case scenario for the users. For instance, in a lending protocol, you can still allow deposits and paybacks since they don&apos;t use oracles. However, you should revert borrow and withdraw operations to prevent accruing bad debt or allowing users to withdraw more collateral than they should.</p><p>When it comes to liquidations, you can revert or use the best price from the last good price and the current price. What counts as &quot;best&quot; is subjective. For collateral, you want to use the lowest price, while for debt, you want to use the highest.</p><p>If your price feeds are on L2, there is one more circuit break you need to be aware of  &#x1F447;</p><hr><h2 id="chainlink-l2-sequencer-uptime-feed-and-grace-period">Chainlink L2 Sequencer Uptime Feed and Grace Period</h2><p>Consider you have deployed a lending protocol on L2, and its sequencer goes down. This has happened in the past and may happen in the future. When the sequencer comes back online and oracles update their prices, all price movements that occurred during downtime are applied at once. If these movements are significant, they may cause chaos. Borrowers would rush to save their positions, while liquidators would rush to liquidate borrowers. Since liquidations are handled mainly by bots, borrowers are likely to suffer mass liquidations.</p><p>This is unfair to borrowers, as they could not act on their positions even if they wanted to due to the L2 downtime.</p><blockquote><em>One thing to note here is If an L2 goes offline, anyone can still submit a transaction for L2 through L1 by something called as delayed inbox (arbitrum) OR canonical transaction chain (optimism). <br>These transactions are always executed first when the sequencer comes back online. In theory, some borrowers can still avoid liquidation by closing their position through this delayed inbox. However, it is unlikely that normal borrowers would have the required knowledge to do so, creating unfair grounds for the same set of users.</em></blockquote><p>Hence, it would be ideal if your protocol gives borrowers a grace period once the sequencer returns.</p><p>The good thing is that Chainlink has a dedicated feed for sequencer uptimes. Check out their <a href="https://docs.chain.link/data-feeds/l2-sequencer-feeds?ref=0xmacro.com">documentation</a> on L2 Sequencer Uptime Feeds.</p><p>Basically, it works because Chainlink keeps pushing sequencer uptime updates from L1 to L2. So, the Chainlink sequencer update will go to the delayed inbox when the sequencer goes down. Since all transactions of the delayed inbox are executed before any others once the sequencer comes back online, it is guaranteed that your contract would consider a grace period.</p><p>Aave V3 follows the same approach as described in their <a href="https://github.com/aave/aave-v3-core/blob/master/techpaper/Aave_V3_Technical_Paper.pdf?ref=0xmacro.com">technical paper.</a></p><figure class="kg-card kg-image-card"><img src="https://0xmacro.com/blog/content/images/2023/03/Untitled.png" class="kg-image" alt="How To Consume Chainlink Price Feeds Safely" loading="lazy" width="941" height="427" srcset="https://0xmacro.com/blog/content/images/size/w600/2023/03/Untitled.png 600w, https://0xmacro.com/blog/content/images/2023/03/Untitled.png 941w" sizes="(min-width: 720px) 720px"></figure><p><br>Note that in the case of AAVE, if a position is heavily undercollateralized, liquidations are allowed even if the protocol is under a grace period.</p><p>Examples:<br><a href="https://github.com/aave/aave-v3-core/blob/master/contracts/protocol/configuration/PriceOracleSentinel.sol?ref=0xmacro.com">Aave&#x2019;s Price Sentinel Contract</a><br><a href="https://docs.chain.link/data-feeds/l2-sequencer-feeds?ref=0xmacro.com#example-code">Chainlink&apos;s Example Integration</a><br><br>That&#x2019;s All, Safe Travels &#x1F642;</p><figure class="kg-card kg-image-card"><img src="https://0xmacro.com/blog/content/images/2023/03/Untitled--1--2.png" class="kg-image" alt="How To Consume Chainlink Price Feeds Safely" loading="lazy" width="1920" height="1550" srcset="https://0xmacro.com/blog/content/images/size/w600/2023/03/Untitled--1--2.png 600w, https://0xmacro.com/blog/content/images/size/w1000/2023/03/Untitled--1--2.png 1000w, https://0xmacro.com/blog/content/images/size/w1600/2023/03/Untitled--1--2.png 1600w, https://0xmacro.com/blog/content/images/2023/03/Untitled--1--2.png 1920w" sizes="(min-width: 720px) 720px"></figure>]]></content:encoded></item><item><title><![CDATA[An Interview with Noah Litvin]]></title><description><![CDATA[Welcome to the first installment in the new Macro Alumni Interview series! We chat with alumni in our community to hear about what they are working on and to learn about real stories from professional devs in web3.]]></description><link>https://0xmacro.com/blog/an-interview-with-noah-litvin/</link><guid isPermaLink="false">62ffd704617a0b0021d50689</guid><category><![CDATA[alumni interview]]></category><dc:creator><![CDATA[dd0sxx]]></dc:creator><pubDate>Fri, 26 Aug 2022 15:00:24 GMT</pubDate><content:encoded><![CDATA[<p><em>[smart contract developer, polymath]</em></p><p>Welcome to the first Macro alumni interview! In conducting these interviews we hope to provide insight into what kind of problems developers are solving in web3, as well as learn about tips and tricks they use in their everyday work.</p><h3 id="where-do-you-work-and-what-team-are-you-on">Where do you work and what team are you on?</h3><p>I&#x2019;m a Core Contributor at <a href="https://synthetix.io/?ref=0xmacro.com">Synthetix</a>, and I primarily focus on <a href="https://sips.synthetix.io/sips/sip-300/?ref=0xmacro.com">V3</a></p><h3 id="tell-us-about-what-libraries-and-tech-stacks-you%E2%80%99re-working-with">Tell us about what libraries and tech-stacks you&#x2019;re working with :)</h3><p><a href="https://github.com/synthetixio?ref=0xmacro.com">Everything is open source</a>. Synthetix&#x2019;s stack is primarily Solidity with Hardhat and React with ethers. There are some <a href="https://thegraph.com/docs/en/about/?ref=0xmacro.com">subgraphs</a> and various off-chain tools (typically written in Typescript) as well.</p><p>Synthetix uses <a href="https://usecannon.com/?ref=0xmacro.com">Cannon</a> and <a href="https://github.com/Synthetixio/synpress?ref=0xmacro.com">Synpress</a>, both maintained by Core Contributors. I&#x2019;m also a fan of <a href="https://chakra-ui.com/?ref=0xmacro.com">Chakra UI</a>, <a href="https://github.com/foundry-rs/foundry?ref=0xmacro.com">Foundry</a>, <a href="https://wagmi.sh/?ref=0xmacro.com">wagmi</a>, and <a href="https://www.rainbowkit.com/?ref=0xmacro.com">Rainbowkit</a>.</p><h3 id="what-types-of-problems-do-you-solve-day-to-day-at-your-job">What types of problems do you solve day-to-day at your job?</h3><p>Fundamentally, the engineers implement <a href="https://sips.synthetix.io/?ref=0xmacro.com">SIPs</a>, though many are involved in authoring them as well. At a high level, the core contributors and the broader Synthetix community work to improve all aspects of the protocol including user experience, developer experience, scalability, capital efficiency, cross-chain functionality, composability, resilience, security, and decentralization.</p><h3 id="what-is-the-coolest-thing-youve-shipped-in-web3-what-was-cool-about-it">What is the coolest thing you&apos;ve shipped in web3? What was cool about it?</h3><p>I built <a href="https://usecannon.com/?ref=0xmacro.com">Cannon</a> with <a href="https://github.com/dbeal-eth?ref=0xmacro.com">dbeal</a> and <a href="https://github.com/mjlescano?ref=0xmacro.com">mjlescano</a> for the most recent ETHDenver hackathon, where it was a winner in the infrastructure and scalability track. Cannon is a tool to specify protocol deployments with Cannonfiles (inspired by Dockerfiles) and package deployment data. And, since Foundry <a href="https://github.com/foundry-rs/foundry/pull/2256?ref=0xmacro.com">added functionality to import and export a chain state</a>, it&#x2019;s super fast.</p><p>It&#x2019;s cool to work on dev tools because you need to do some &#x201C;meta&#x201D; thinking about software engineering. The design decisions in the tools need to be opinionated enough to be useful, but flexible enough to accommodate software design patterns that might not even be in use yet. We&#x2019;re still actively developing Cannon while using it with Synthetix, and we&#x2019;re interested in gathering more feedback/pull requests from the broader web3 community.</p><h3 id="tell-us-about-something-you%E2%80%99ve-had-to-troubleshoot-recently-and-what-tools-or-techniques-you-brought-to-bear-on-the-problem">Tell us about something you&#x2019;ve had to troubleshoot recently, and what tools or techniques you brought to bear on the problem.</h3><p>Nothing interesting enough to share comes to mind, but I&#x2019;ll usually reach for <a href="https://tenderly.co/?ref=0xmacro.com">Tenderly</a> first if something weird is going on.</p><h3 id="seasoned-web2-engineers-are-very-familiar-with-implementing-theilities-maintainability-extensibility-scalability-and-so-on-in-a-web2-context-how-have-you-found-these-system-characteristics-to-play-out-in-a-web3-context">Seasoned web2 engineers are very familiar with implementing the &quot;-ilities&quot; (maintainability, extensibility, scalability and so on) in a web2 context. How have you found these system characteristics to play out in a web3 context?</h3><p>I think there&#x2019;s a fantasy that you can just write an immutable smart contract, deploy it, and then walk off into the sunset with your bags of cash. Maybe this works in some cases but, even without <a href="https://mirror.xyz/0xB38709B8198d147cc9Ff9C133838a044d78B064B/M7oTptQkBGXxox-tk9VJjL66E1V8BUF0GF79MMK4YG0?ref=0xmacro.com">upgradeability proxies</a>, during development you&#x2019;re typically doing multiple deployments to local and test networks, performing automated and manual QA, tracking issues, adding features, and iterating. At the end of the day, it&#x2019;s just software engineering so all of these more abstract concerns are just as applicable.</p><h3 id="what-excited-you-about-web3-when-you-first-took-the-plunge-and-what-excites-you-about-the-space-now">What excited you about web3 when you first took the plunge, and what excites you about the space now?</h3><p>If you like building things, web3 is exciting because there&#x2019;s still so much to improve! The dev tools are very immature compared to web2. And even the most basic use cases for crypto&#x2014;like storing and sending assets&#x2014;are only just now catching up to TradFi services like Venmo in terms of user experience.</p><p>The pace is also very stimulating. The space is evolving rapidly, with many smart people shipping quickly and large amounts of money at stake. Assuming everything becomes more robust and usable, I&#x2019;d anticipate that the creation of a fully permissionless financial system will be considered one of the most significant technological breakthroughs in my lifetime.</p><h3 id="what-aspects-of-your-pre-macro-experience-prepared-you-for-the-work-youre-doing">What aspects of your <strong>pre-Macro</strong> experience prepared you for the work you&apos;re doing?</h3><p>I was previously working on a <a href="https://thecryptomuse.com/what-is-tradfi-cryptocurrency/?ref=0xmacro.com">TradFi</a> fintech start-up which helped me better understand the contours of the problem space that crypto/DeFi is addressing. If you&#x2019;re exclusively a consumer of fintech, it&#x2019;s not obvious how much could go into something like an ACH transfer, let alone that there could be viable alternatives.</p><h3 id="how-did-your-experience-at-macro-prepare-you-for-the-real-work-youre-doing">How did your experience <strong>at Macro</strong> prepare you for the real work you&apos;re doing?</h3><p>Macro did a great job of highlighting real use cases for smart contracts and relevant security considerations. Solidity syntax and patterns were covered throughly, but it was especially valuable to dig into the idiosyncrasies of blockchain development and the practical applications of protocols.</p><h3 id="what-tips-would-you-give-to-a-web2-developer-who-is-looking-to-join-the-web3-space">What tips would you give to a web2 developer who is looking to join the web3 space?</h3><p>Most legit projects are open source and have active Discord servers. Build stuff relevant to whatever you&#x2019;re most interested in and share it with the people involved.</p><hr><p>Huge shoutout to Noah for joining us as the first Macro alumni interview :) If you enjoyed the read and want to keep up with Noah, considering <a href="https://twitter.com/noahlitvin?ref=0xmacro.com">following him on twitter</a>.</p><p>If you have thoughts on how we can improve these interviews in the future, feel free to <a href="https://twitter.com/dd0sxx?ref=0xmacro.com">DM me</a>.</p><p>Thanks for reading!</p>]]></content:encoded></item><item><title><![CDATA[Fuzzing with Echidna]]></title><description><![CDATA[Fuzzing is a well-known technique in the security industry to discover bugs in software. Here you will get to know some tools available for fuzz testing and have a basic understanding of how Echidna works.]]></description><link>https://0xmacro.com/blog/fuzzing-with-echidna/</link><guid isPermaLink="false">63053444617a0b0021d50790</guid><category><![CDATA[security-team]]></category><category><![CDATA[audits]]></category><dc:creator><![CDATA[Tom]]></dc:creator><pubDate>Wed, 24 Aug 2022 16:52:43 GMT</pubDate><content:encoded><![CDATA[<h2 id="intro">Intro</h2><p>Fuzzing is a well-known technique in the security industry to discover bugs in software &#x2014; invalid, unexpected, or random data is generated automatically and injected into the software to find issues.</p><p>In the context of smart contract security, fuzzing tools are relatively new but are gaining more attraction recently. It is pivotal that a smart contract &#x2014; with its immutable character &#x2014; is tested thoroughly before any deployment to production. Having an adequate test coverage of your code using unit tests is essential, but there will always be edge cases you did not test for. Thus, it is best practice to extend your testing strategy by using additional security tools, such as static analyzers and fuzzers.</p><p>After reading this blog post, you should gain the following <strong>takeaways</strong>:</p><ul><li>The core component of an audit is a manual review &#x2014; this is where you catch the most bugs.</li><li>Fuzz tests can be very useful for catching edge cases.</li><li>There are different tools available for fuzz testing. One of the better-known tools is <strong>Echidna</strong>.</li><li>Have a basic understanding of how Echidna works.</li></ul><hr><p>Before introducing Echidna in more detail, here is a list of the more popular security-testing tools available today:</p><p>1.&#xA0;Slither &#x2013; static analysis tool (developed by TrailOfBits)<br><a href="https://github.com/crytic/slither?ref=0xmacro.com">https://github.com/crytic/slither</a></p><p>2. Manticore &#x2013; uses symbolic execution to detect vulnerabilities (developed by TrailOfBits)<br><a href="https://github.com/trailofbits/manticore?ref=0xmacro.com">https://github.com/trailofbits/manticore</a></p><p>3. Scribble &#x2013; allows one to annotate a smart contract with properties and raises exceptions when the property is violated.<br><a href="https://github.com/ConsenSys/scribble?ref=0xmacro.com">https://github.com/ConsenSys/scribble</a></p><p>4. MythX &#x2013; uses symbolic execution to detect vulnerabilities (developed by Consensys)<br><a href="https://mythx.io/?ref=0xmacro.com">https://mythx.io/</a></p><p>5. Mythril &#x2013; paid cloud service that includes static analysis, symbolic analysis, and fuzzing (developed by Consensys)<br><a href="https://github.com/ConsenSys/mythril?ref=0xmacro.com">https://github.com/ConsenSys/mythril</a></p><p>6. Foundry support for fuzz testing<br><a href="https://book.getfoundry.sh/forge/fuzz-testing.html?ref=0xmacro.com">https://book.getfoundry.sh/forge/fuzz-testing.html</a></p><p>7. Dapptools support for fuzz testing<br><a href="https://github.com/dapphub/dapptools/tree/master/src/dapp?ref=0xmacro.com#property-based-testing">https://github.com/dapphub/dapptools/tree/master/src/dapp#property-based-testing</a></p><p>8. Certora - paid service that uses formal verification<br><a href="https://www.certora.com/?ref=0xmacro.com">https://www.certora.com/</a></p><p><strong>9. Echidna</strong> &#x2013; fuzzing tool (developed by TrailOfBits)<br><a href="https://github.com/crytic/echidna?ref=0xmacro.com">https://github.com/crytic/echidna</a></p><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-emoji">&#x1F4A1;</div><div class="kg-callout-text">Reminder: None of these security tools can replace a real manual audit!</div></div><p>In the next chapter we will go deeper into Echidna, a program written in Haskell by the security experts from Trail of Bits.</p><hr><h2 id="echidna">Echidna</h2><p>Echidna uses a style of fuzzing called <strong>property-based fuzzing</strong>. Instead of looking for crashes like a traditional fuzzer, Echidna tries to break user-defined invariants (a.k.a. properties).</p><p>Invariants are properties of the program state that are expected to always be true. These invariants have to be manually written in Solidity, as opposed to writing unit tests in Javascript. Currently, Echidna does not support automated fuzz tests.</p><p>Once these invariants are defined, Echidna tries to falsify these invariants by generating random sequences of calls to the contract.</p><p>Enough theory for now &#x2014; let&#x2019;s look at the code.</p><h3 id="installation">Installation</h3><p>Run Echidna by using pre-compiled binary:<br><a href="https://github.com/crytic/echidna/releases/tag/v2.0.2?ref=0xmacro.com">https://github.com/crytic/echidna/releases/tag/v2.0.2</a></p><p>or</p><p>Another neat way to run Echidna is by using the <em>trailofbits eth-security-toolbox</em> docker image:<br><a href="https://github.com/trailofbits/eth-security-toolbox?ref=0xmacro.com">https://github.com/trailofbits/eth-security-toolbox</a></p><h3 id="example-1">Example 1</h3><p>Consider the following contract (similar vulnerability as <a href="https://ethernaut.openzeppelin.com/level/0x5732B2F88cbd19B6f01E3a96e9f0D90B917281E5?ref=0xmacro.com">Ethernaut&#x2019;s Fal1Out challenge</a>).</p><pre><code class="language-solidity">// ICO.sol
contract ICO {
    bool is_paused;
    address owner = msg.sender;

    function IC0() public {
        owner = msg.sender;
    }

    modifier isOwner() {
        require(owner == msg.sender);
        _;
    }
		
    function resume() public isOwner {
      is_paused = false;      
    }
}
</code></pre><p>The <em>resume()</em> function can only be called by the owner of the contract. Let&#x2019;s write a fuzz test to see if Echidna can find a way to break the contract and set the <em>is_paused</em> variable to true:</p><pre><code class="language-solidity">import &quot;./ICO.sol&quot;;

// ICOFuzzTest.sol
contract ICOFuzzTest is ICO {

    constructor() public {
        is_paused = true;
        owner = address(0x0);
    }

    function echidna_test_pause() public view returns (bool) {
        return is_paused == true;
    }
}
</code></pre><p>Initialization code goes into the constructor. In the above code, <em>is_paused</em> is set to <em>true</em> and the <em>owner</em> is set to <em>0x0</em>.</p><p>Next, we write the test which defines that <em>is_paused</em> should always return true. Note that for executing the tests, Echidna randomly uses the following caller addresses: <em>0x10</em>, <em>0x20</em>, and <em>0x30</em>. In other words, the above test says that there shouldn&#x2019;t be any way for the caller addresses to set the <em>is_paused</em> variable to <em>false</em>.</p><p><em>Note</em>: All fuzz tests must start with <em>echidna_</em> in order for Echidna to pick them up.</p><p>To start the fuzz test, run the following:</p><pre><code class="language-bash">echidna-test ICOFuzzTest.sol --contract ICOFuzzTest
</code></pre><p>Echidna immediately returns the result:</p><figure class="kg-card kg-image-card"><img src="https://0xmacro.com/blog/content/images/2022/08/Untitled.png" class="kg-image" alt loading="lazy" width="968" height="222" srcset="https://0xmacro.com/blog/content/images/size/w600/2022/08/Untitled.png 600w, https://0xmacro.com/blog/content/images/2022/08/Untitled.png 968w" sizes="(min-width: 720px) 720px"></figure><p>The test failed, as Echidna found a way to falsify the invariant by making the following calls:</p><ol><li><em>IC0()</em></li><li><em>resume()</em></li></ol><p>To the trained eye, the vulnerability was pretty obvious. The <em>IC0()</em> function is not a valid constructor as it is written with the number &#x2018;0&#x2019; instead of the letter &#x2018;O&#x2019;. In addition, with Solidity &gt; 4.21 you need to define the constructor using the <em>constructor</em> keyword instead of using the contract name.</p><p>As <em>IC0()</em> is a normal function and is lacking an access modifier, it can be called by anyone to gain ownership. After gaining ownership, the <em>resume</em> function can be called to set <em>is_paused</em> to <em>true</em>.</p><p>As simple as the above example was, it clearly demonstrates how Echidna works &#x2014; it automatically generates arbitrary transactions (with random input) to test the invariant.</p><h3 id="example-2">Example 2</h3><p>Consider the following contract:</p><pre><code class="language-solidity">pragma solidity 0.7.0;

contract Pausable {
    bool is_paused;

    function paused() public {
        is_paused = true;
    }

    function resume() public {
        is_paused = false;
    }
}

contract Token is Pausable {
    mapping(address =&gt; uint256) public balances;

    constructor() {
        is_paused = true;
    }

    function transfer(address to, uint256 value) public {
        require(!is_paused);

        uint256 initial_balance_from = balances[msg.sender];
        uint256 initial_balance_to = balances[to];

        balances[msg.sender] -= value;
        balances[to] += value;

        assert(balances[msg.sender] &lt;= initial_balance_from);
        assert(balances[to] &gt;= initial_balance_to);
    }
}
</code></pre><p>Note that the above code uses Solidity version 0.7.0. For Solidity version 0.8.0 and above the compiler has built in underflow/overflow checks but for older versions you need to take care of it yourself.</p><p>In the previous Example 1 we used the &#x201C;property&#x201D; testing mode. Echidna supports other testing modes such as &#x201C;assertion&#x201D; and &#x201C;dapptest&#x201D; (see <a href="https://github.com/crytic/building-secure-contracts/blob/master/program-analysis/echidna/testing-modes.md?ref=0xmacro.com" rel="noopener noreferrer">here</a>). In this example, we run Echidna in &#x201C;assertion&#x201D; testing mode. Hereby, Echidna looks out for Solidity assertions in your code and tries to falsify them by generating random transactions and inputs.</p><p>To start the fuzz test in &#x201C;assertion&#x201D; mode run:</p><pre><code class="language-solidity">echidna-test Token.sol --test-mode assertion --contract Token
</code></pre><p>Echidna prints out the following result:</p><figure class="kg-card kg-image-card"><img src="https://0xmacro.com/blog/content/images/2022/08/Untitled--1-.png" class="kg-image" alt loading="lazy" width="973" height="364" srcset="https://0xmacro.com/blog/content/images/size/w600/2022/08/Untitled--1-.png 600w, https://0xmacro.com/blog/content/images/2022/08/Untitled--1-.png 973w" sizes="(min-width: 720px) 720px"></figure><p>It checked every function for assertions and found 1 test that failed in the transfer(&#x2026;) function.</p><p>Can you figure out why?</p><p>The test failed by making the following call:</p><p><em>1.&#xA0;resume()</em><br><em>2. transfer(0x0, 1)</em></p><p>Echidna first called resume to set <em>is_paused = false</em> which is necessary to enter the <em>transfer</em> function. In the 2nd step, <em>transfer</em> was called with the parameters <em>0x0</em> for the <em>to</em> address and <em>1</em> for the <em>value</em>. The interesting line that brought the test to fail is this:</p><p><code>balances[msg.sender] -= value;</code></p><p>The balance for <em>msg.sender</em> is <em>0</em> and gets decreased by <em>1</em>. This results in an underflow that is not handled as we are using Solidity version 0.7.0. As a consequence, balance of msg.sender will be set to the maximum number of uint256. This behavior breaks the first assertion</p><p><code>assert(balances[msg.sender] &lt;= initial_balance_from);</code></p><p>as now the new balance is much higher than the initial one.&#xA3;</p><p>The easiest way to avoid the above issue is to use Solidity 0.8.0 or higher. If for whatever reason you can&#x2019;t do that, the 2nd best option is to use OpenZeppelin&#x2019;s <a href="https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeMath.sol?ref=0xmacro.com">SafeMath library</a>.</p><p>The best way to start with Echidna is at its official <a href="https://github.com/crytic/echidna?ref=0xmacro.com">Github page</a>. For advanced configuration and further examples, visit <a href="https://github.com/crytic/building-secure-contracts/tree/master/program-analysis/echidna?ref=0xmacro.com#echidna-tutorial">this tutorial page</a>.</p><h2 id="alternatives-to-echidna">Alternatives to Echidna</h2><p><strong>Scribble</strong></p><p>Scribble is a so-called specification language that allows you to annotate your smart contracts with properties. In a second step, Scribble transforms the annotations into Solidity code with concrete assertions.</p><p>The aim of Scribble is to have one universal annotation language for defining your fuzz tests and then to reuse this between different tools.</p><figure class="kg-card kg-image-card"><img src="https://0xmacro.com/blog/content/images/2022/08/Untitled--2-.png" class="kg-image" alt loading="lazy" width="2000" height="664" srcset="https://0xmacro.com/blog/content/images/size/w600/2022/08/Untitled--2-.png 600w, https://0xmacro.com/blog/content/images/size/w1000/2022/08/Untitled--2-.png 1000w, https://0xmacro.com/blog/content/images/size/w1600/2022/08/Untitled--2-.png 1600w, https://0xmacro.com/blog/content/images/2022/08/Untitled--2-.png 2221w" sizes="(min-width: 720px) 720px"></figure><p>(<em>Source:</em> <a href="https://docs.scribble.codes/?ref=0xmacro.com">https://docs.scribble.codes/</a>)</p><p>The above picture shows that Scribble can be used with fuzzing tools like Mythril and MythX (likely because all of these three tools have been developed by Consensys).</p><p>As Scribble compiles the annotations into simple Solidity assertions, it should also be possible to use Scribble in combination with Echidna, using the &#x201C;assertion&#x201D; testing mode (see <a href="https://github.com/crytic/building-secure-contracts/blob/master/program-analysis/echidna/testing-modes.md?ref=0xmacro.com#assertions">here</a>). Please reach out to us if you have experience with this setup!</p><p><strong>Foundry</strong></p><p>Foundry has become more and more popular over the recent months (see <a href="https://twitter.com/gakonst/status/1538201417764089856?s=20&amp;t=bauL8mwTLCTtPDKOoP0KLA&amp;ref=0xmacro.com">here</a>).</p><p>So if Foundry is already your development framework of choice, you don&#x2019;t have to look further. Foundry has built-in support for fuzz testing. When using Foundry, you already write your unit tests in Solidity. If the test function takes at least 1 parameter, then Foundry automatically runs the test as a property-based fuzz test (see <a href="https://book.getfoundry.sh/forge/fuzz-testing.html?ref=0xmacro.com">here</a>).</p><p>The approach Foundry follows is similar to writing fuzz tests with Echidna but quite different to the annotation-based approach Scribble uses.</p><p>While both Foundry and Echidna fall under the same category of property-based fuzzing, Echidna uses more advanced techniques like generating random transactions with random inputs and also keeps track of those transactions to achieve high coverage. On the other hand, Foundry focuses on generating random inputs for your test functions and has support for excluding certain values.</p><h2 id="final-thoughts">Final Thoughts</h2><p>Nobody said it&#x2019;s going to be easy!</p><p>Writing fuzz tests isn&#x2019;t trivial. In the beginning, you will probably spend a lot of time writing meaningful tests &#x2014; there is a deep learning curve. Additionally, there are a lot of different tools and setups available, and you must first find out what fits best for you and your team.</p><p>Nevertheless, the effort will pay off and will make your code more secure. As a builder or auditor, you should add fuzz tests to your toolbox.</p><hr><h2 id="referencesresources"><strong>References/Resources</strong></h2><p>A list of security tools:<br><a href="https://github.com/ConsenSys/ethereum-developer-tools-list?ref=0xmacro.com#security-tools">https://github.com/ConsenSys/ethereum-developer-tools-list#security-tools</a><br><a href="https://github.com/trailofbits/eth-security-toolbox?ref=0xmacro.com">https://github.com/trailofbits/eth-security-toolbox</a></p><p>Fuzzing complex projects with Echidna: <a href="https://ventral.digital/posts/2021/12/21/fuzzing-complex-projects-with-echidna-sushi-bentobox?ref=0xmacro.com">https://ventral.digital/posts/2021/12/21/fuzzing-complex-projects-with-echidna-sushi-bentobox</a></p><p>Comparison of Slither, MythX, Mythril, Manticore, SmartCheck: <a href="https://medium.com/@charingane/smart-contract-security-tools-comparison-4aaddf301f01?ref=0xmacro.com">https://medium.com/@charingane/smart-contract-security-tools-comparison-4aaddf301f01</a></p><p>Scribble:<br><a href="https://consensys.net/blog/news/introducing-scribble-by-consensys-diligence/?ref=0xmacro.com">https://consensys.net/blog/news/introducing-scribble-by-consensys-diligence/</a><br><a href="https://consensys.net/diligence/blog/2021/07/introducing-scribble-generator/?ref=0xmacro.com">https://consensys.net/diligence/blog/2021/07/introducing-scribble-generator/</a></p><p>Patrick Collins:<br><a href="https://github.com/PatrickAlphaC/hardhat-security-fcc?ref=0xmacro.com">https://github.com/PatrickAlphaC/hardhat-security-fcc</a><br><a href="https://www.youtube.com/watch?v=TmZ8gH-toX0&amp;ref=0xmacro.com">https://www.youtube.com/watch?v=TmZ8gH-toX0</a></p><hr><div class="kg-card kg-callout-card kg-callout-card-grey"><div class="kg-callout-text">&#x261D; <strong>Echidna Cheat Sheet:</strong><br><br>- Run <code>$ echidna-test contract.sol</code><br>- If you have multiple contracts in file, run <code>$ echidna-test contract.sol &#x2014;contract MyContract</code><br>- If you want to test assertions, run <code>$ echidna-test contract.sol &#x2014;test-mode assertion</code><br>- If you want to apply custom config, run <code>$ echidna-test contract.sol &#x2014;config cfg.yaml</code></div></div><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[What Solidity Devs Should Know about Ethereum’s Merge]]></title><description><![CDATA[The next proposed merge date for Ethereum to transfer from a proof-of-work (PoW) system to a proof-of-stake (PoS) system is September 15th-16th, barring any setbacks.

Here’s what you should know about the merge as a Solidity developer.]]></description><link>https://0xmacro.com/blog/what-solidity-devs-should-know-about-ethereums-merge/</link><guid isPermaLink="false">62fc5982617a0b0021d505c0</guid><category><![CDATA[solidity]]></category><category><![CDATA[evm]]></category><category><![CDATA[News]]></category><dc:creator><![CDATA[Lily]]></dc:creator><pubDate>Wed, 17 Aug 2022 17:14:30 GMT</pubDate><content:encoded><![CDATA[<p></p><h2 id="changes-to-be-aware-of">Changes to be aware of</h2><ul><li><code>block.difficulty</code> has a new source</li><li>Block times will be shorter by 1-2 seconds</li><li>Less new ETH being added to the ecosystem</li><li>Multi-block MEV == new possible attack vectors</li></ul><h2 id="blockdifficulty-has-a-new-source"><code>block.difficulty</code> has a new source</h2><p>In Solidity&apos;s PoW era, the global variable <code>block.difficulty</code> existed as a way to access the current difficulty level of the PoW&apos;s algorithm. As we shift to PoS and no longer have a concept of &apos;work&apos; we also no longer have a difficulty level to source <code>block.difficulty</code> from.</p><p>To keep the previous Solidity code functioning, the Ethereum Foundation <a href="https://eips.ethereum.org/EIPS/eip-4399?ref=0xmacro.com">decided to change</a> <code>block.difficulty</code>&apos;s underlying opcode <code>0x44</code> to return a new PoS field named <code>prevrandao</code>.</p><p>In the PoS world, this value is produced by the beacon chain and is used to help determine who the next set of validators are in the block proposal and attestation process. The &#x201C;<code>prev</code>&quot; part of <code>prevrandao</code> is derived from its value being the previous block&#x2019;s outputted <code>randao</code> value.<br></p><p><em>Do I need to take any action?</em></p><ul><li>If you were using <code>block.difficulty</code> to help create randomness in your code, firstly, don&#x2019;t do this because it is not actually random. Ultimately, your code should run the same.</li><li>If you were relying on <code>block.difficulty</code> to be in the previous PoW sensible range of 0-2^64, your code could break. <code>block.difficulty</code> will now range from 0-2^256.</li><li>If you had specialized logic to have your contract act differently based on the <code>block.difficulty</code> level, your code will not behave as intended as <code>block.difficulty</code> is now pseudorandom with an increased range.</li><li>Bonus: if you want to write up logic that behaves differently pre and post-merge, you can use <code>block.difficulty</code>&apos;s value to reasonably determine if the merge has occurred or not. Values less than 2^64 could be used to see that the chain is still PoW.</li></ul><p><em>Can I use this newfangled <code>prevrandao</code> instead of the fancy techniques like Chainlink&#x2019;s VRF when I want stronger randomness?</em></p><p>The consensus in the security community is a firm &#x2018;no&#x2019;. Use existing VRF infrastructure for security critical randomness needs.</p><p>Validators who are chosen to propose blocks will be able to know the value of <code>prevrandao</code> while selecting the transactions to construct their blocks out of. In other words, block proposers could choose to add or censor transactions if they find it beneficial to do so based on the current block&#x2019;s value of <code>prevrandao</code>.</p><h2 id="block-times-will-be-shorter-by-1-2-seconds">Block times will be shorter by 1-2 seconds</h2><p>A common misconception about the merge is that it will result in noticeably more capacity. This is not true. Capacity will increase a tiny bit, as block times will decrease from an average of 13 seconds (with a wide variation) to almost exactly every <a href="https://blog.ethereum.org/2021/11/29/how-the-merge-impacts-app-layer/?ref=0xmacro.com">12 seconds</a>. Important to note: blocks can be skipped if a validator goes offline or chooses to not submit a block when it is their turn. This currently happens &lt; 1% of the time.</p><p><em>Do I need to take any action?</em></p><ul><li>If your code assumes a block cadence of 13 seconds, be prepared for it to run faster than expected.</li></ul><h2 id="less-new-eth-being-added-to-the-ecosystem">Less new ETH being added to the ecosystem</h2><p><a href="https://ethereum.org/en/upgrades/merge/issuance/?ref=0xmacro.com#pre-merge-issuance-breakdown">According to the Ethereum Foundation</a>, the change to PoS will slow down the creation of new Ether by a drastic amount: from a current 4.1% per year to a projected 0.3%-0.4% per year.</p><ul><li>In the current PoW system ~14,600 new ETH is produced and ~1,600 ETH is burned each day.</li><li>In PoS, it&#x2019;s projected that ~1,600 ETH will be produced and ~1,600 ETH will continue to be burned, resulting in a non-inflationary total ETH supply.</li></ul><p><em>Do I need to take any action?</em></p><ul><li>This is a major change to the native currency in the ecosystem and could have large long-term impact on the value of ETH.</li><li>If you are in the practice of hardcoding ETH values into your protocols, consider adding options in the future to change the required amount of ETH to interact with your projects.</li></ul><h2 id="multi-block-mev-new-possible-attack-vectors">Multi-block MEV == new possible attack vectors</h2><p>In PoW it is prohibitively computationally expensive to know who the next miner of a block will be. This is changing dramatically in PoS: validators are selected and announced by the beacon chain in schedules of 32. Furthermore, <a href="https://hackmd.io/@flashbots/mev-in-eth2?ref=0xmacro.com#fn6">according to FlashBots</a>, it is possible that validator pools could have direct control over consecutive blocks.</p><p>Many PoW-era protocols rely on the security assumption that no one in the system can ensure that they will have control across multiple blocks. This has been used as a fundamental building block in protocol designs.</p><p>Take, for example, the common pattern of Automated Market Makers (AMMs). Protocols such as Uniswap use a time weighted average price (TWAP) across blocks to serve as a price oracle. If an actor can know that they will have control over a set of blocks, <a href="https://eprint.iacr.org/2022/445.pdf?ref=0xmacro.com">they could use this information to sway the TWAP price to exclusively benefit themselves</a>.</p><p><em>Do I need to take any action?</em></p><ul><li>Exactly how and if MEV groups will use the new PoS architecture to create new market opportunities is an open question.</li><li>Currently, the only courses of action are:</li></ul><ol><li>Be aware that new Multi-block MEV opportunities could come into existence using control over consecutive blocks, and</li><li>Adopt the new PoS protocol system designs which will emerge to accommodate the new security landscape.</li></ol><h2 id="conclusion">Conclusion</h2><p>The switch from PoW to PoS will be a substantial win for the Ethereum ecosystem but will not change your life as a Solidity developer in a major way.</p><p>Remember to:</p><ul><li>Practice good randomness hygiene</li><li>Keep up to date on new MEV strategies, and</li><li>Stay up to date for the Ethereum Foundation to roll out the rest of the planned <a href="https://twitter.com/milesdeutscher/status/1550315295402668032?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1550315295402668032%7Ctwgr%5E12155688fc66cd9ccba314ff660976be59449dae%7Ctwcon%5Es1_&amp;ref_url=https%3A%2F%2Fbeincrypto.com%2Fvitalik-updates-ethereum-roadmap-with-surges-and-purges%2F&amp;ref=0xmacro.com">next-gen Ethereum upgrades</a>.</li></ul><hr><h2 id="extended-learnings">Extended Learnings</h2><p>If reading this has tickled your curiosity and you are itching to learn more, we love that! Here are the sources that we used to construct this post to help you dive deeper:</p><ul><li><a href="https://github.com/ethereum/execution-specs?ref=0xmacro.com">Ethereum&#x2019;s previous and planned execution upgrades</a>. This is the place to look to see which EIPs are planned to be included in the next upgrade. <a href="https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/paris.md?ref=0xmacro.com">Here</a> is the spec specific to the PoS &#x2018;Paris&#x2019; upgrade.</li><li><a href="https://eips.ethereum.org/EIPS/eip-3675?ref=0xmacro.com">EIP-3675</a>: Included in the Paris upgrade, this EIP explains all of the major changes to the execution environment required to change from PoW to PoS.</li><li><a href="https://eips.ethereum.org/EIPS/eip-4399?ref=0xmacro.com">EIP-4399</a>: Also included in the Paris upgrade, this EIP changes the opCode <code>0x44</code> from returning the <code>difficulty</code> field to the <code>prevrandao</code> field. Solidity&#x2019;s <code>block.difficulty</code> global variable compiles down to opCode <code>0x44</code>.</li><li><a href="https://eth2book.info/altair/part2/building_blocks/randomness?ref=0xmacro.com">An information goldmine</a> on how the beacon chain constructs the <code>randao</code> value which <code>prevrandao</code> refers to.</li><li>An <a href="https://ethmerge.com/?ref=0xmacro.com">in-depth FAQ on the merge</a> unrelated to Solidity changes. Useful as a starting source if you want to learn how to participate in staking ETH with a validator.</li><li>A <a href="https://blog.ethereum.org/2021/11/29/how-the-merge-impacts-app-layer/?ref=0xmacro.com">blog of all of the application layer changes due to the merge</a>. Good to read if you&#x2019;re responsible for more than just your protocol&#x2019;s Solidity code.</li><li>A <a href="https://ultrasound.money/?ref=0xmacro.com">fun web app</a> showing the current and merge-simulated ETH issuance and burn rates.</li><li>For the hardcore learners, here is one of the Ethereum Engineering Group&#x2019;s <a href="https://www.youtube.com/watch?v=jy4QgwdTb7o&amp;ref=0xmacro.com">information stuffed video on the PoW to PoS upgrade</a>. This is an in-depth video directly from the people who are writing the EIPs for the merge.</li></ul>]]></content:encoded></item><item><title><![CDATA[Synthetix Staking Rewards Issue - Inefficient Reward Distribution]]></title><description><![CDATA[During an audit by Macro's security team, they found a bug in Synthetix Staking Rewards distribution. While the issue is not an exploitable bug, the Ethereum community should be made aware of it.]]></description><link>https://0xmacro.com/blog/synthetix-staking-rewards-issue-inefficient-reward-distribution/</link><guid isPermaLink="false">62e98768617a0b0021d50515</guid><category><![CDATA[audits]]></category><category><![CDATA[security-team]]></category><dc:creator><![CDATA[curiousapple]]></dc:creator><pubDate>Thu, 04 Aug 2022 16:00:13 GMT</pubDate><content:encoded><![CDATA[<p>*<em>Note, this issue was found by the Macro Audits team and is <strong>not an exploitable bug</strong>. Instead, it is a medium-to-low severity bug that affects the protocol rewards distribution cycle.</em></p><h2 id="context">Context</h2><p>Synthetix&#x2019;s <code>StakingRewards</code> is a battle-tested smart contract that distributes rewards to stakers. Synthetix has been a pioneer in DeFi and has established a well-audited standard for staking rewards that is used by many protocols across the Ethereum ecosystem.</p><p>Recently, <a href="https://0xmacro.com/audits?ref=0xmacro.com">Macro Audits</a> did an <a href="https://0xmacro.com/blog/sommelier-finance-macro-smart-contract-audit/">audit</a> of <a href="https://www.sommelier.finance/?ref=0xmacro.com">Sommelier&#x2019;s</a> cellar staking smart contract.</p><p>During the audit, one of Macro&#x2019;s auditors, <a href="https://twitter.com/0xcuriousapple?ref=0xmacro.com">Abhishek Vispute</a>, found a medium-to-low severity bug that, in certain cases, a portion of rewards can remain unused within the Sommelier&apos;s <code>StakingRewards</code> contract.</p><p>Macro Audits brought this issue to the attention of both the Sommelier and Synthetix teams.</p><p>This brief post summarizes the issue; and while the issue is <strong>not an exploitable bug</strong>, and therefore not a &#x201C;must fix&#x201D; issue, the Ethereum community should be made aware of it, in case your project &#x2014; or another project you know of &#x2014; is using the Synthetix <code>StakingRewards</code> contract.</p><p>As you may know, many projects either (a) fork the Synthetix <code>StakingRewards</code> contract or (b) implement a similar pattern. Therefore, we hope that sharing this issue will help any relevant projects out there.</p><p>Details can be found below. If you&#x2019;re interested in working with Macro Audits, please contact us by filling out our <a href="https://0xmacro.typeform.com/to/aGOErxKP?typeform-source=blogpost&amp;ref=0xmacro.com">Audit Request Form.</a></p><h2 id="summary">Summary</h2><p><strong>If <code>stake()</code> is not called in the same block of <code>notifyRewardAmount()</code>,</strong></p><p><strong>depending on delay, a portion of rewards will remain unused inside the contract.</strong></p><figure class="kg-card kg-image-card"><img src="https://0xmacro.com/blog/content/images/2022/08/Table1.png" class="kg-image" alt loading="lazy" width="1084" height="266" srcset="https://0xmacro.com/blog/content/images/size/w600/2022/08/Table1.png 600w, https://0xmacro.com/blog/content/images/size/w1000/2022/08/Table1.png 1000w, https://0xmacro.com/blog/content/images/2022/08/Table1.png 1084w" sizes="(min-width: 720px) 720px"></figure><p><strong>Description:</strong>Let&#x2019;s consider that you have a <code>StakingRewards</code> contract with a reward duration of one month seconds (2592000):</p><p><strong>Block N &#xA0; &#xA0; &#xA0; &#xA0; &#xA0; &#xA0; Timestamp = X</strong></p><p>You call <code>notifyRewardAmount()</code> with a reward of one month seconds (2592000) only. <strong>The intention</strong> is for a period of a month, 1 reward token per second should be distributed to stakers.</p><p><strong>State :</strong></p><p><code>rewardRate = 1</code></p><p><code>periodFinish = X +**2592000**</code></p><p><strong>Block M &#xA0; &#xA0; &#xA0; &#xA0; &#xA0;Timestamp = X + Y</strong></p><p><code>Y</code> time has passed, and the first staker stakes some amount:</p><p>1.<code>stake()</code><br>	2. <code>updateReward</code><br>				<code>rewardPerTokenStored = 0</code><br>				<code>lastUpdateTime = X + Y</code></p><p>Hence, for this staker, the clock has started from X+Y, and he or she will accumulate rewards from this point.</p><p>Please note, though, that the <code>periodFinish</code> is <code>X + rewardsDuration</code>, not <code>X + Y + rewardsDuration</code>. Therefore, the contract will only distribute rewards until <code>X + rewardsDuration</code>, losing &#xA0;<code>Y * rewardRate =&gt; Y * 1</code> &#xA0;inside of the contract, as <code>rewardRate = 1</code> (if we consider the above example).</p><p>Now, if we consider <code>delay(Y)</code> to be 30 minutes, then:</p><p>Only 2592000-1800= 2590200 tokens will be distributed, and these 1800 tokens will remain unused in the contract until the next cycle of <code>notifyRewardAmount()</code>.</p><p><em><strong>Whenever a protocol starts a reward cycle, it intends to distribute X amount of rewards during that time.</strong></em></p><p><em><strong>If a certain amount remains unused (like the above example inside the contract), and a new reward cycle is not started, that amount remains dormant inside the contract.</strong></em></p><p><em><strong>Even if the given protocol decides to start a new reward cycle to cover this unused amount, it is a redundant execution.</strong></em></p><p><em><strong>As there will likely be a delay between the first stake and the reward cycle initiation, consider resolving this issue.</strong></em></p><h2 id="recommended-remediation">Recommended Remediation</h2><p>Consider defining <code>periodFinish</code> in the first <code>stake()</code> that is done after <code>notifyRewardAmount()</code>, when total deposits are zero.</p><p>Check out how the Sommelier team tackled this issue with <code>_startProgram()</code>:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/PeggyJV/cellar-contracts/blob/afd970c36e9a520326afc888a11d40cdde75c6a7/src/CellarStaking.sol?ref=0xmacro.com#L219"><div class="kg-bookmark-content"><div class="kg-bookmark-title">cellar-contracts/CellarStaking.sol at afd970c36e9a520326afc888a11d40cdde75c6a7 &#xB7; PeggyJV/cellar-contracts</div><div class="kg-bookmark-description">Cellar Contracts for Sommelier. Contribute to PeggyJV/cellar-contracts development by creating an account on GitHub.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.com/fluidicon.png" alt><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">PeggyJV</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/596c0cfaa8e9a195a35a9a50bb52c6daaa2a60dbd2efc209f093b35d6bb9c153/PeggyJV/cellar-contracts" alt></div></a></figure>]]></content:encoded></item><item><title><![CDATA[Solidity Gas Optimizations Cheat Sheet]]></title><description><![CDATA[There are a number of things you should keep in mind to write the best and most gas efficient solidity code. In this post you can find a list of low-hanging fruits you can apply to your contracts today.]]></description><link>https://0xmacro.com/blog/solidity-gas-optimizations-cheat-sheet/</link><guid isPermaLink="false">62e30a96617a0b0021d50401</guid><category><![CDATA[audits]]></category><category><![CDATA[gas]]></category><category><![CDATA[solidity]]></category><category><![CDATA[evm]]></category><dc:creator><![CDATA[curiousapple]]></dc:creator><pubDate>Thu, 28 Jul 2022 13:00:00 GMT</pubDate><content:encoded><![CDATA[<p>Solidity is currently the most popular language for the EVM. However, Solidity&apos;s compiler is still in its early stages, meaning there are a number of things you should keep in mind while using it to write the best and most efficient code.</p><p>One of those things is <strong>gas optimizations</strong>. On Ethereum, gas is very expensive. While we don&apos;t recommend going crazy for minimal savings, below is a list of low-hanging fruit you can apply to your contracts today.</p><blockquote>&#x1F4A1; Also see <strong><strong><a href="https://0xmacro.com/library/gas-nums?ref=0xmacro.com">Gas Numbers Every Solidity Dev Should Know</a></strong></strong></blockquote><p><strong>1.&#xA0;Packing of storage variables</strong></p><p>Pack variables in one slot by defining them in a lower data type. Packing only helps when multiple variables of the packed slot are being accessed in the same call. If not done correctly, it increases gas costs instead, due to shifts required.</p><p> Before:</p><pre><code class="language-solidity">contract MyContract {
  uint32  x; // Storage slot 0
  uint256 y; // Storage slot 1
  uint32  z; // Storage slot 2
}
</code></pre><p>After:</p><pre><code class="language-solidity">contract MyContract {
  uint32 x;  // Storage slot 0
  uint32 z;  // Storage slot 0
  uint256 y; // Storage slot 1
}
</code></pre><p><strong>2. Local variable assignment</strong></p><p>Catch frequently used storage variables in memory/stack, converting multiple <code>SLOAD</code> into 1 <code>SLOAD</code>.</p><p>Before:</p><pre><code class="language-solidity">uint256 length = 10;

function loop() public {
    for (uint256 i = 0; i &lt; length; i++) {
        // do something here
    }
}
</code></pre><p>After:</p><pre><code class="language-solidity">uint256 length = 10;

function loop() {
    uint256 l = length;

    for (uint256 i = 0; i &lt; l; i++) {
        // do something here
    }
}
</code></pre><p><strong>3. Use fixed size bytes array rather than string or bytes[]</strong></p><p>If the string you are dealing with can be limited to max of 32 characters, use <code>bytes[32]</code> instead of dynamic <code>bytes</code> array or <code>string</code>.</p><p>Before:</p><pre><code class="language-solidity">string a;
function add(string str) {
    a = str;
}
</code></pre><p>After:</p><pre><code class="language-solidity">bytes32 a;
function add(bytes32 str) public {
    a = str;
}
</code></pre><p><strong>4. Use immutable and constant</strong></p><p>Use immutable if you want to assign a permanent value at construction. Use constants if you already know the permanent value. Both get directly embedded in bytecode, saving <code>SLOAD</code>.</p><pre><code class="language-solidity">contract MyContract {
    uint256 constant y = 10;
    uint256 immutable x;

    constructor() {
        x = 5;
    } 
 }
</code></pre><p><strong>5. Using unchecked</strong></p><p>Use unchecked for arithmetic where you are sure it won&apos;t over or underflow, saving gas costs for checks added from solidity v0.8.0.</p><p>In the example below, the variable <code>i</code> cannot overflow because of the condition <code>i &lt; length</code>, where <code>length</code> is defined as <code>uint256</code>. The maximum value <code>i</code> can reach is <code>max(uint)-1</code>. Thus, incrementing <code>i</code> inside <code>unchecked</code> block is safe and consumes lesser gas.</p><pre><code class="language-solidity">function loop(uint256 length) public {
	for (uint256 i = 0; i &lt; length; ) {
	    // do something
	    unchecked {
	        i++;
	    }
	}
}
</code></pre><p><strong>6. Use calldata instead of memory for function parameters</strong> <a href="https://gist.github.com/hrkrshnn/ee8fabd532058307229d65dcd5836ddc?ref=0xmacro.com#use-calldata-instead-of-memory-for-function-parameters">[Ref]</a></p><p>It is generally cheaper to load variables directly from calldata, rather than copying them to memory. Only use memory if the variable needs to be modified.</p><p>Before:</p><pre><code class="language-solidity">function loop(uint[] memory arr) external pure returns (uint sum) {
    for (uint i = 0; i &lt; arr.length; i++) {
        sum += arr[i];
    }
}
</code></pre><p>After:</p><pre><code class="language-solidity">function loop(uint[] calldata arr) external pure returns (uint sum) {
    for (uint i = 0; i &lt; arr.length; i++) {
        sum += arr[i];
    }
}
</code></pre><p><strong>7. Use custom errors to save deployment and runtime costs in case of revert</strong></p><p>Instead of using strings for error messages (e.g., <code>require(msg.sender == owner, &#x201C;unauthorized&#x201D;)</code>), you can use custom errors to reduce both deployment and runtime gas costs. In addition, they are very convenient as you can easily pass dynamic information to them.</p><p>Before:</p><pre><code class="language-solidity">function add(uint256 _amount) public {
    require(msg.sender == owner, &quot;unauthorized&quot;);

    total += _amount;
}
</code></pre><p>After:</p><pre><code class="language-solidity">error Unauthorized(address caller);

function add(uint256 _amount) public {
    if (msg.sender != owner)
        revert Unauthorized(msg.sender);

    total += _amount;
}
</code></pre><p><strong>8. Refactor a modifier to call a local function instead of directly having the code in the modifier, saving bytecode size and thereby deployment cost</strong> [<a href="https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol?ref=0xmacro.com#L36">Ref</a>]</p><p>Modifiers code is copied in all instances where it&apos;s used, increasing bytecode size. By doing a refractor to the internal function, one can reduce bytecode size significantly at the cost of one JUMP. Consider doing this only if you are constrained by bytecode size.</p><p>Before:</p><pre><code class="language-solidity">modifier onlyOwner() {
		require(owner() == msg.sender, &quot;Ownable: caller is not the owner&quot;);
		_;
}
</code></pre><p>After:</p><pre><code class="language-solidity">modifier onlyOwner() {
		_checkOwner();
		_;
}

function _checkOwner() internal view virtual {
    require(owner() == msg.sender, &quot;Ownable: caller is not the owner&quot;);
}
</code></pre><p><strong>9. Use indexed events as they are less costly compared to non-indexed ones</strong> [<a href="https://twitter.com/maurelian_/status/1488691543544320000?ref=0xmacro.com">Ref</a>]</p><p>Using the <code>indexed</code> keyword for value types such as uint, bool, and address saves gas costs, as seen in the example below. However, this is only the case for value types, whereas indexing bytes and strings are more expensive than their unindexed version.</p><p>Before:</p><pre><code class="language-solidity">event Withdraw(uint256, address);

function withdraw(uint256 amount) public {
    emit Withdraw(amount, msg.sender);
}
</code></pre><p>After:</p><pre><code class="language-solidity">event Withdraw(uint256 indexed, address indexed);

function withdraw(uint256 amount) public {
    emit Withdraw(amount, msg.sender);
}
</code></pre><p><strong>10. Use struct when dealing with different input arrays to enforce array length matching</strong></p><p>When the length of all input arrays needs to be the same, use a <code>struct</code> to combine multiple input arrays so you don&apos;t have to manually validate their lengths.</p><p>Before:</p><pre><code class="language-solidity">function vote(uint8[] calldata v, bytes[32] calldata r,  bytes[32] calldata s) public {
		require(v.length == r.length == s.length, &quot;not matching&quot;);
}
</code></pre><p>After:</p><pre><code class="language-solidity">struct Signature {
        uint8 v;
        bytes32 r;
        bytes32 s;
    }

function vote(Signature[] calldata sig) public {
    // no need for length check
}
</code></pre><p><strong>11. Provide methods for batch operations</strong></p><p>If applicable, provide a method for batch action to users, reducing the overall gas costs.</p><p>For example: In the following case, if the user wants to call <code>doSomething()</code> for 10 different inputs. In the optimized version, the user would need to spend the fixed gas cost of the transaction and the gas cost for <code>msg.sender check</code> only once.</p><p>Before:</p><pre><code class="language-solidity">function doSomething(uint256 x, uint256 y, uint256 z) public {
		require msg.sender == registeredUser
		....
}
</code></pre><p>After:</p><pre><code class="language-solidity">
function batchDoSomething(uint256[] x, uint256[] y, uint256[] z) public {
		require msg.sender == registeredUser
    loop
			_doSomething(x[i], y[i], z[i])
}
function doSomething(uint256 x, uint256 y, uint256 z) public {
		require msg.sender == registeredUser
		_doSomething(x, y, z);
}
function _doSomething(uint256 x, uint256 y, uint256 z) internal {
		....
}
</code></pre><p><strong>12. Short-circuit with || and &amp;&amp;</strong></p><p>For || and &amp;&amp; operators, the second case is not checked if the first case gives the result of the logical expression. &#xA0;Put the lower-cost expression first so the higher-cost expression may be skipped (short-circuit).</p><p>Before:</p><pre><code class="language-solidity">case 1: 100 gas
case 2: 50 gas

if(case1 &amp;&amp; case2) revert 
if(case1 || case2) revert 
</code></pre><p>After:</p><pre><code class="language-solidity">if(case2 &amp;&amp; case1) revert 
if(case2 || case1) revert 
</code></pre><hr><figure class="kg-card kg-image-card"><img src="https://0xmacro.com/blog/content/images/2022/07/Blog-post-table.png" class="kg-image" alt loading="lazy" width="1116" height="470" srcset="https://0xmacro.com/blog/content/images/size/w600/2022/07/Blog-post-table.png 600w, https://0xmacro.com/blog/content/images/size/w1000/2022/07/Blog-post-table.png 1000w, https://0xmacro.com/blog/content/images/2022/07/Blog-post-table.png 1116w" sizes="(min-width: 720px) 720px"></figure><hr><h3 id="general-rules"><strong>General Rules</strong></h3><p><br><strong>Optimize For</strong></p><p><strong>1.&#xA0;Common cases &gt;&gt; Rare cases</strong></p><p>One should optimize for common cases. Optimizing for rare cases can increase gas costs for all other cases. For example, skipping balance update in case of 0 amount transfer.</p><p>As 0 amount transfer is not common, it doesn&apos;t make sense to add the cost of one condition for all other cases.</p><p>However, if the case is common, like transfer in case of infinite allowance, one should do it.</p><p><a href="https://github.com/ethereum/EIPs/issues/717?ref=0xmacro.com">Unlimited ERC20 token allowance &#xB7; Issue #717 &#xB7; ethereum/EIPs</a></p><p><strong>2. Runtime cost &gt;&gt; Deployment cost</strong></p><p>Deployment costs are one-time, so always optimize for runtime costs.<br>If you are constrained by bytecode size, then optimize for deployment cost.</p><p><strong>3. User Interaction &gt;&gt; Admin Interaction</strong></p><p>As user interaction is most common, prioritize optimizing for it compared to admin actions.</p><hr><p>Soon we will follow up with <strong>degen</strong> gas optimizations, which go to extreme lengths to save gas costs.</p><p>For example: Function Ordering, &#x2265; and &gt; comparison, payable, address with leading zeros&#x2026;</p><p>We hope you found this post helpful. If you want to get in touch with us to chat about audits, please click the link below:</p><p><a href="https://0xmacro.com/audits?ref=0xmacro.com">Audits | Macro</a></p><p>References :</p><p><a href="https://gist.github.com/hrkrshnn/ee8fabd532058307229d65dcd5836ddc?ref=0xmacro.com#use-calldata-instead-of-memory-for-function-parameters">Some generic writeup about common gas optimizations, etc.</a></p><p><a href="https://mudit.blog/solidity-gas-optimization-tips/?ref=0xmacro.com">https://mudit.blog/solidity-gas-optimization-tips/</a></p>]]></content:encoded></item><item><title><![CDATA[Sommelier Finance]]></title><description><![CDATA[The Macro Audits team audited two of Sommelier’s cellar-contracts. Access the report and learn more about our smart contract auditing process.
]]></description><link>https://0xmacro.com/blog/sommelier-finance-macro-smart-contract-audit/</link><guid isPermaLink="false">62d473bc617a0b0021d50300</guid><category><![CDATA[audits]]></category><dc:creator><![CDATA[David Goldberg]]></dc:creator><pubDate>Sun, 17 Jul 2022 21:18:44 GMT</pubDate><content:encoded><![CDATA[<p><a href="https://www.sommelier.finance/?utm_source=0xmacro.com">Sommelier Finance</a> is a yield optimization protocol with a twist: a yield generating strategy on an arbitrary chain is executed by validators of the Cosmos chain, decentralizing the ownership of that strategy. They are introducing the next iteration of strategies on DeFi, which are controlled by off-chain computation. It&apos;s a marketplace allowing independent strategy providers to bring ML-powered strategies to users.</p><p>The <strong>Macro Audits</strong> team audited only 2 of Sommelier&#x2019;s <a href="https://github.com/PeggyJV/cellar-contracts/tree/4409661be89308e5c3a60f84e898bc068337b13d?ref=0xmacro.com">cellar-contracts</a>, at commit hash: <code>4409661be89308e5c3a60f84e898bc068337b13d</code></p><ol><li><strong>CellarStakingRewards</strong></li><li><strong>AaveV2StablecoinCellar</strong></li></ol><p><code>CellarStakingRewards</code> is an upgraded version of the OG <code>Synthetix Staking Rewards</code>, with unique features such as un-bonding, emergency actions, and locking boost.</p><p><code>AaveV2StablecoinCellar</code> is an ERC4626 vault intended to optimize stablecoin yields on AAVE. As a user, one simply deposits stables into the cellar, and then the cellar takes care of rebalancing the stables so that the user gets the best possible yield.</p><p>In our first review of <code>AaveV2StablecoinCellar</code>, we found a significant number of issues originating from the use of inactive assets. The Sommelier team was already thinking of changing the approach of using inactive assets, and after seeing our reported issues, they diligently decided to take the time required to change the approach they were taking. </p><p>After the approach changed, we proceeded with our second review.</p><p><strong>The report of our second audit can be found <a href="https://docs.google.com/document/d/1hHzFEYUPuH7VmAq3WCymTPtyHwWE6tfrnOhyZbK2HUA/edit?usp=sharing&amp;ref=0xmacro.com">here</a>.</strong></p><p><strong>We found 1 High, 3 Medium, 2 Low, 4 Informational, and 1 Quality Issues, as well as Several Gas optimizations.</strong></p><p>For our first review, we didn&apos;t publish the report; the findings were shared with the Sommelier team and were fixed.</p><p>Regarding our interaction with the Sommelier team, we were satisfied with their technical capability and open-mindedness. They were comfortable with delaying their launch until both parties were satisfied, which is generally a good sign.</p><p>We can&#x2019;t say that we are a catch-all service, as no audit is. Though we may miss some things, one thing we pride ourselves on is our effort and thoroughness. We had some good eyes going through the code, and we wish Sommelier the best for mainnet.</p><p>This is what <strong>Sam Patel, Head of Product @Sommelier Finance</strong> has to say:</p><div class="kg-card kg-callout-card kg-callout-card-grey"><div class="kg-callout-emoji">&#x1F377;</div><div class="kg-callout-text">&#x201C;Working with Macro felt like having an exceptional extended team that worked besides our team and invested time to understand our platform&apos;s complex architecture which enabled them to find in-depth vulnerabilities.<br><br>We had an opportunity to work with multiple auditors through the past 6 months and Macro&apos;s team and findings were by far the most insightful and critical in our redesign. We look forward to continuing our relationship as we launch future cellars&#x201D;</div></div><p>This is what <strong>Kevin Kennis, Co-Founder @Sommelier Finance</strong> has to say:</p><div class="kg-card kg-callout-card kg-callout-card-grey"><div class="kg-callout-emoji">&#x1F377;</div><div class="kg-callout-text">&quot;Not only was the Macro auditing team extremely thorough in their review, they have time and again gone above and beyond communication-wise in complex and time-sensitive situations. I especially loved how each finding in our audit report included a drop-in, fully coded test case that we could use as a benchmark in our fix for the reported issue. As a developer, having such a strong partner working towards our launch helped our team achieve high level of confidence in a smooth release.&#x201D;</div></div><hr><p>If you are interested in an audit, check us out:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://0xmacro.com/audits?ref=0xmacro.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Audits | Macro</div><div class="kg-bookmark-description">Macro is trusted by multiple leading industry names in Defi and Crypto for Smart Contract auditing.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://webflow-assets.0xmacro.com/626062ed773a7c6b10369600/6287a027fd9f6c4c622015c5_logo-favicon.png" alt><span class="kg-bookmark-author">Macro</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://webflow-assets.0xmacro.com/626062ed773a7c6b10369600/6287a806894b6a8a99a9f402_logotype-padding%402x.png" alt></div></a></figure><p><a href="https://0xmacro.com/audits?ref=0xmacro.com">https://0xmacro.com/audits</a></p><p><strong>We will do our best to exceed your expectations.</strong></p>]]></content:encoded></item><item><title><![CDATA[How to Prep for an Audit]]></title><description><![CDATA[It's no secret that smart contract auditing firms have long backlogs. Learn how to better prepare your project so it can get booked sooner than later.]]></description><link>https://0xmacro.com/blog/how-to-prep-for-an-audit/</link><guid isPermaLink="false">62a286034398cf0021eacaf0</guid><category><![CDATA[security-team]]></category><dc:creator><![CDATA[David Goldberg]]></dc:creator><pubDate>Wed, 01 Jun 2022 12:00:00 GMT</pubDate><content:encoded><![CDATA[<p>As auditors, it&#x2019;s no secret that we have long backlogs. Consequently, we&#x2019;re always assessing projects on whether or not we should work with them, just as much as those projects are assessing us.</p><p>So, what are some things we look for that makes an audit customer a good fit?</p><h2 id="overview">Overview</h2><p>Here we offer a quick set of tips on how <em>you</em> can prepare your smart contract project for an audit. The goal is to make your project attractive to work with, even for the busy top smart contract audit firms.</p><ol><li><a href="#1-write-great-documentation-%E2%9C%8D%EF%B8%8F">Write Great Documentation &#x270D;&#xFE0F;</a></li><li><a href="#2-write-great-tests-%F0%9F%A7%A0">Write Great Tests &#x1F9E0;</a></li><li><a href="#3-prepare-your-repo-for-the-audit-%F0%9F%93%90">Prepare your Repo for the Audit &#x1F4D0;</a></li></ol><h2 id="1-write-great-documentation-%E2%9C%8D%EF%B8%8F">1. Write Great Documentation &#x270D;&#xFE0F;</h2><p>Quality of documentation is a major factor in how auditors assess your project. Too often do we see projects with little to no documentation.</p><p>Poor documentation makes it a pain to give a proper estimate for <em>how long</em> an audit would take. Not everything is deducible from the code, and even if it is, it&apos;s much faster and more accurate to get <strong>intent</strong> from the authors themselves.</p><p>Poor documentation may even lengthen the audit <em>itself</em>, either costing you more money, or leaving less time for a high quality audit.</p><p>With that said, great documentation usually has at least these:</p><ul><li><strong>High level intentions, features, and goals.</strong> <em>What</em> are you trying to accomplish?</li><li><strong>Detailed use case descriptions.</strong> <em>Who</em> is using your protocol, and why?</li><li><strong>Explanations of technical decisions.</strong> <em>Why</em> did you take your approach?</li><li><strong>Architecture diagrams.</strong> <em>How</em> do components of the system interact?</li><li>Perhaps most importantly, <strong>how the contracts in question fit in the overall system.</strong> We often see projects provide overall documentation, but then leave us to ask or figure out which parts of those docs apply to which contracts they want audited.</li></ul><p>For an example of great documentation, see any of ThirdWeb&apos;s design docs, such as their <a href="https://github.com/thirdweb-dev/contracts/blob/main/contracts/marketplace/marketplace.md?ref=0xmacro.com">marketplace contract docs</a>.</p><h2 id="2-write-great-tests-%F0%9F%A7%A0">2. Write Great Tests &#x1F9E0;</h2><p>It goes without saying that testing is critical to writing secure code. A project with a lack of tests is guaranteed to have problems, and is not something we&apos;re interested in booking.</p><p>Of course, testing does not catch all bugs either. But here are some quick tips for writing tests for smart contracts.</p><h3 id="test-all-use-cases">Test all use cases</h3><p>This may seem obvious, but it needs to be said. Every use case needs a proper test. Don&apos;t miss a single one.</p><p>Ideally, each use case has an end-to-end test. This isn&apos;t strictly necessary when developing smart contracts, but doing so helps you iterate on your contract&apos;s ABI design, since you&apos;d be using it in frontend code.</p><h3 id="test-as-many-edge-cases-as-possible">Test as many edge cases as possible</h3><p>Missed edge cases are the primary reason smart contracts lose money. But it&apos;s almost impossible to think of them all by yourself, and you shouldn&apos;t treat auditors as a bug-free guarantee.</p><p>The best, low-hanging fruit you can do for your project today is introduce <a href="https://en.wikipedia.org/wiki/Fuzzing?ref=0xmacro.com"><strong>fuzz testing</strong></a>. Fuzz testing is essentially an automated way of finding edge cases in your code. It will try input combinations on your code that you&apos;d never thought to test.</p><p>Fuzz testing is <a href="https://book.getfoundry.sh/forge/fuzz-testing.html?ref=0xmacro.com">built into Foundry</a>. Hardhat users are not completely <a href="https://github.com/NomicFoundation/hardhat/issues/2136?ref=0xmacro.com">out of luck</a>, but they will need to learn and implement a tool like <a href="https://github.com/crytic/echidna?ref=0xmacro.com">Echidna</a>.</p><h3 id="achieve-high-test-coverage">Achieve high test coverage</h3><p>High test coverage is not an end-goal, but it <em>is</em> a decent measurement of health. Low test coverage means you <strong>certainly</strong> don&apos;t have enough tests. High test coverage means you <em>might</em>. 100% coverage is desirable for smart contracts, but beware, as even that won&apos;t even save you &#x2013; we&apos;ve found bugs in a project with 100% test coverage before!</p><p>Use <a href="https://github.com/sc-forks/solidity-coverage?ref=0xmacro.com">solidity-coverage</a> to measure your test coverage in your hardhat projects. Foundry users are currently out of luck, but may have access to superior <a href="https://github.com/foundry-rs/foundry/issues/478?ref=0xmacro.com">mutation testing</a> in the future.</p><h2 id="3-prepare-your-repo-for-the-audit-%F0%9F%93%90">3. Prepare your Repo for the Audit &#x1F4D0;</h2><p>Handing your code to the auditor is not a simple matter of <code>git push</code> and link to GitHub. There are certain things that you should do to save everyone valuable time you&apos;re paying for.</p><h3 id="be-code-complete">Be code complete</h3><p>Changes to code are inevitable. However, during the audit, you <strong>should not</strong> make <em>major</em> changes to the codebase &#x2013; doing so may change the audit timeline, and could even require a full re-audit!</p><p>Fixes to the issues an auditor finds are usually covered, given they are not large enough to trigger the above.</p><h3 id="tag-the-commit-you-want-audited">Tag the commit you want audited</h3><p>Adding a git tag on a commit helps ensure everyone is on the same page on what exactly is being audited.</p><p>When auditors find issues and you fix them, create another tag when those fixes are ready for review.</p><h3 id="clean-up-the-codebase">Clean up the codebase</h3><p>Another seemingly-obvious point, but be sure to do things such as:</p><ul><li>Write Natspec docs for your external/public functions</li><li>Document expected invariants</li><li>Use standard terminology over &quot;cute&quot; or &quot;creative&quot; terminology (e.g. &quot;LendingPool&quot; over &quot;DragonHoard&quot;)</li><li>Comment on unconventional design choices</li><li>Remove any commented out code / unused files</li></ul><h2 id="conclusion">Conclusion</h2><p>Audit bookings are hard to get. By following this advice, you&apos;ll make your project more attractive to auditors and more likely to get booked.</p><p>We hope you found this post helpful. If you want to get in touch with us to chat about audits, please click the link below:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://0xmacro.com/audits?ref=0xmacro.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Audits | Macro</div><div class="kg-bookmark-description">Macro is trusted by multiple leading industry names in Defi and Crypto for Smart Contract auditing.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://webflow-assets.0xmacro.com/626062ed773a7c6b10369600/6287a027fd9f6c4c622015c5_logo-favicon.png" alt><span class="kg-bookmark-author">Macro</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://webflow-assets.0xmacro.com/626062ed773a7c6b10369600/6287a806894b6a8a99a9f402_logotype-padding%402x.png" alt></div></a></figure><p><a href="https://0xmacro.com/audits?ref=0xmacro.com">https://0xmacro.com/audits</a></p>]]></content:encoded></item></channel></rss>