<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.1.1">Jekyll</generator><link href="https://yos.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://yos.io/" rel="alternate" type="text/html" /><updated>2026-01-22T13:31:49+00:00</updated><id>https://yos.io/feed.xml</id><title type="html">Yos Riady · Software Craftsman</title><subtitle>Personal blog of Yos Riady. Yos is a Software Engineer based in Singapore.</subtitle><author><name>Yos Riady</name><email>hello@yos.io</email></author><entry><title type="html">Building for Onchain Builders</title><link href="https://yos.io/2025/10/29/building-for-onchain-builders/" rel="alternate" type="text/html" title="Building for Onchain Builders" /><published>2025-10-29T00:00:00+00:00</published><updated>2025-10-29T00:00:00+00:00</updated><id>https://yos.io/2025/10/29/building-for-onchain-builders</id><content type="html" xml:base="https://yos.io/2025/10/29/building-for-onchain-builders/">&lt;p&gt;&lt;img src=&quot;https://yos.io/assets/building-for-onchain-builders.jpg&quot; alt=&quot;Building for Onchain Builders&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article was originally posted on the &lt;a href=&quot;https://formo.so/blog/we-built-formo-for-onchain-builders&quot;&gt;Formo Blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Building a successful onchain app is &lt;em&gt;hard&lt;/em&gt;. It gets even harder when you don’t know how people are using it. You’re shipping features, running campaigns, and trying to find product-market fit, but without clear data, you’re lost in a dark forest. &lt;a href=&quot;https://formo.so/blog/actionable-insights-for-onchain-apps&quot;&gt;Analytics remains as one of the biggest challenges in crypto&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Think about the questions you’re trying to answer every day:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Who are my top users?&lt;/li&gt;
  &lt;li&gt;What drove them to us? Where do they come from?&lt;/li&gt;
  &lt;li&gt;Which channels or campaigns are working?&lt;/li&gt;
  &lt;li&gt;How are users using my app?&lt;/li&gt;
  &lt;li&gt;What’s my CAC? LTV? ROI?&lt;/li&gt;
  &lt;li&gt;What is moving the needle onchain?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To answer the above in web3 you’d need an in-house data team, complicated data pipelines, and juggle multiple fragmented tools. What if there’s an easy way to understand who your users are and what they do so you can build a better app, faster?&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;introducing-formo&quot;&gt;Introducing Formo&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://formo.so/&quot;&gt;Formo&lt;/a&gt; is the data platform for onchain apps and builders. It’s the tool we wished we had as builders when we were struggling to turn raw onchain data into something useful.&lt;/p&gt;

&lt;p&gt;Formo transforms the messy data silos of wallets, transactions, web, and in-app events into clear, actionable insights for your whole team from product to marketing.&lt;/p&gt;

&lt;p&gt;We built Formo to give scrappy founders, product, and marketing teams in web3 the clarity they need to grow. It helps you:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;See the full user journey from offchain to onchain, to spot exactly where users are dropping off, helping you fix bottlenecks and improve your app.&lt;/li&gt;
  &lt;li&gt;Identify your most valuable users—the whales and power users—so you can more effectively engage and retain them.&lt;/li&gt;
  &lt;li&gt;Segment wallets into cohorts based on their behavior to see which users stick around and to help refine your ICP.&lt;/li&gt;
  &lt;li&gt;When you ship a new feature or launch a marketing campaign, you can measure its impact immediately on metrics that matter, not vanity metrics.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Many builders we talk to went so far as to cobble together their own analytics solution in-house, because of data silos and fragmented tools. There wasn’t an existing solution that worked for them. A few scripts, an internal database, Google Analytics, and BI tools. But that DIY stack quickly becomes a time sink. It’s expensive to run, complex to maintain, and the data is often out of date.&lt;/p&gt;

&lt;p&gt;Formo replaces that headache. From analytics to forms, we handle the infrastructure so you can focus on your core product, not data plumbing. Built with &lt;a href=&quot;https://formo.so/blog/privacy-friendly-web3-analytics-a-guide-to-user-privacy-for-onchain-apps-and-protocols&quot;&gt;privacy&lt;/a&gt; and &lt;a href=&quot;https://formo.so/security&quot;&gt;security&lt;/a&gt; in mind, Formo integrates with the tools you already use, allowing you to push insights into dashboards, set up alerts, or export data in less time.&lt;/p&gt;

&lt;p&gt;Stop guessing and start measuring what matters in crypto.&lt;/p&gt;

&lt;h2 id=&quot;next-steps&quot;&gt;Next Steps&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://docs.formo.so/install&quot;&gt;Getting started&lt;/a&gt; is simple. Spin up a workspace and get actionable insights in less than an hour.&lt;/p&gt;

&lt;p&gt;If you’re building onchain, give &lt;a href=&quot;https://app.formo.so/&quot;&gt;Formo’s free plan&lt;/a&gt; a try so you can focus on growth.&lt;/p&gt;

&lt;p&gt;—&lt;a href=&quot;https://www.linkedin.com/in/yosriady/&quot;&gt;Yos Riady&lt;/a&gt;, Founder&lt;/p&gt;</content><author><name>Yos Riady</name><email>hello@yos.io</email></author><category term="data" /><category term="crypto" /><category term="analytics" /><summary type="html">This article was originally posted on the Formo Blog. Building a successful onchain app is hard. It gets even harder when you don’t know how people are using it. You’re shipping features, running campaigns, and trying to find product-market fit, but without clear data, you’re lost in a dark forest. Analytics remains as one of the biggest challenges in crypto. Think about the questions you’re trying to answer every day: Who are my top users? What drove them to us? Where do they come from? Which channels or campaigns are working? How are users using my app? What’s my CAC? LTV? ROI? What is moving the needle onchain? To answer the above in web3 you’d need an in-house data team, complicated data pipelines, and juggle multiple fragmented tools. What if there’s an easy way to understand who your users are and what they do so you can build a better app, faster?</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://yos.io/assets/building-for-onchain-builders.jpg" /><media:content medium="image" url="https://yos.io/assets/building-for-onchain-builders.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Actionable Insights for Onchain Apps</title><link href="https://yos.io/2025/05/22/actionable-insights-for-onchain-apps/" rel="alternate" type="text/html" title="Actionable Insights for Onchain Apps" /><published>2025-05-22T00:00:00+00:00</published><updated>2025-05-22T00:00:00+00:00</updated><id>https://yos.io/2025/05/22/actionable-insights-for-onchain-apps</id><content type="html" xml:base="https://yos.io/2025/05/22/actionable-insights-for-onchain-apps/">&lt;p&gt;&lt;img src=&quot;https://yos.io/assets/actionable-insights-for-onchain-apps.jpg&quot; alt=&quot;Actionable Insights for Onchain Apps&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article was originally posted on the &lt;a href=&quot;https://formo.so/blog/actionable-insights-for-onchain-apps&quot;&gt;Formo Blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Developer tools remove barriers to innovation. Analytics remove barriers to growth&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Data is the lifeblood of any business. It helps you understand your customers and where they came from, make impactful data-driven decisions, and drive sustainable growth. &lt;strong&gt;Without data, you’re lost in a dark forest.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;However, understanding onchain user behavior is hard. Teams struggle to set up analytics and attribution from fragmented tools, data pipelines, and databases. Many teams give up altogether.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://formo.so&quot;&gt;Formo&lt;/a&gt; is the data platform for onchain apps. &lt;strong&gt;Formo makes analytics easy for crypto.&lt;/strong&gt; Get the best of web, product, and onchain analytics on one versatile platform.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;the-biggest-challenges-in-web3&quot;&gt;The biggest challenges in web3&lt;/h2&gt;

&lt;p&gt;User acquisition and product analytics remain among &lt;a href=&quot;https://www.privy.io/blog/consumer-crypto&quot;&gt;the biggest challenges&lt;/a&gt; in crypto.&lt;/p&gt;

&lt;p&gt;A web3 user’s journey spans across both on-chain and off-chain channels. Instead of email or IRL identifiers, users log in through crypto wallets. Key conversion events such as swapping on a DEX or purchasing on an NFT marketplace happen onchain, beyond the reach of existing tools. Traditional analytics tools like Mixpanel and Google Analytics cannot see onchain data, so you miss out on crucial information.&lt;/p&gt;

&lt;p&gt;Today’s top engagement and retention tools ignore the wealth of data available onchain. For example, marketing solutions like Hubspot and Klaviyo do not support on-chain actions and events, while product analytics systems like Mixpanel and Amplitude do not natively handle blockchain data. Data about user acquisition, drop-off, and retention from a large chunk of the web3 user’s journey is missing.&lt;/p&gt;

&lt;p&gt;Answering even simple queries is hard in Web3:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Where do my users come from?&lt;/li&gt;
  &lt;li&gt;Which channels/campaigns are driving the most revenue? What’s the ROI?&lt;/li&gt;
  &lt;li&gt;Who are my top users, and how can I retain them?&lt;/li&gt;
  &lt;li&gt;What were the biggest retention factors, and at which step of the funnel did most users drop off?&lt;/li&gt;
  &lt;li&gt;What is my ARPU or LTV : CAC ratio, and how can I increase it?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Uncovering your true growth and retention drivers and acquisition channels has been a big challenge in Web3. The vast percentage of onchain activity is disconnected from Web2 and hard to decipher. A side-effect of this problem is web3’s unhealthy obsession with &lt;em&gt;vanity metrics&lt;/em&gt;, which is much easier to get (and easy to fake.) Vanity metrics help projects get exchange listings and investment, but it doesn’t translate to building meaningful products.&lt;/p&gt;

&lt;p&gt;Data is the lifeblood of any business. It helps you understand your customers, make data-driven decisions, and drive growth. Without accurate data and attribution, you are lost in a dark forest.&lt;/p&gt;

&lt;h2 id=&quot;high-barriers-for-onchain-attribution-and-profiling&quot;&gt;High barriers for onchain attribution and profiling&lt;/h2&gt;

&lt;p&gt;Web3 projects struggle to get the data they need to make impactful decisions. Data is scattered across separate blockchains and data silos. Blockchains are optimized for writes, and reading data efficiently and reliably at scale is challenging. It takes serious engineering work to collect all this data, much less analyze it. Collecting and aggregating data from multiple blockchains and offchain sources requires deep expertise and complex tools (such as Databricks, Looker, Snowflake, BigQuery, and more.)&lt;/p&gt;

&lt;p&gt;To do it right, you need extensive SQL and data engineering expertise to collect, process, and analyze data. You’d need a dedicated team of data engineers and analysts to create data pipelines and dashboards for your project. As a result, product teams spend valuable resources on infrastructure and integrations instead of shipping user-facing features.&lt;/p&gt;

&lt;p&gt;Building in-house data pipelines and analytics infrastructure is beyond the means of many web3 teams. Not every team can allocate resources away from building their core product. As a result, analytics often falls by the wayside. They remain in the backlog forever.&lt;/p&gt;

&lt;p&gt;Teams across web3 struggle to get the data they need to measure what matters and make impactful decisions. The absence of tools has made measuring the impact of growth initiatives and targeting users unsolved.&lt;/p&gt;

&lt;h2 id=&quot;onchain-data-is-an-untapped-wealth-of-insights&quot;&gt;Onchain data is an untapped wealth of insights&lt;/h2&gt;

&lt;p&gt;On the other hand, data on blockchains provides unparalleled accessibility and insight into user behaviour. Onchain, you can observe any onchain users’ holdings and past activity, even when they don’t interact directly with your product. In Web2, this is unheard of. Onchain data is a public and permissionless data goldmine. We need only a better tool to access it.&lt;/p&gt;

&lt;p&gt;In web2, third-party data, cookies, and sessions are foundational building blocks of cohort segmentation. They perform two core functions: attribution and identity.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Attribution refers to granular event analytics around who, how, and when users interact with your apps and websites (funnels, UTM, referral headers).&lt;/li&gt;
  &lt;li&gt;Identity refers to the sum of user activity used to construct a profile for targeting (country, device, onchain activity).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Blockchain networks represent a paradigm shift in the transfer of information and value. We believe it will reshape the foundations of trust within legacy systems. To get there, we need accessible data tools for onchain users, builders, and apps.&lt;/p&gt;

&lt;p&gt;With unified onchain attribution, we can construct rich profiles and user segments that can be targeted more effectively. Minting, staking, swapping, and voting are high-intent actions that signal meaningful interest in a topic. Wallet addresses, tokens, attestations, and onchain user activity offer a new, meaningful set of attributes that can be used to construct customer profiles. Blockchain data opens up new doors for you to identify and target real, active users.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Identity and attribution are key ingredients for growth&lt;/strong&gt;, and linking crypto-native web3 data (wallets, tokens, and transactions) with web2 data (dapp and browser interactions) unlocks a clear path for growth and retention.&lt;/p&gt;

&lt;h2 id=&quot;formo-makes-it-easy-to-digest-web3-data&quot;&gt;Formo makes it easy to digest web3 data&lt;/h2&gt;

&lt;p&gt;User acquisition and product analytics remain among the biggest challenges in crypto. As we transition from infrastructure to apps, we need meaningful and accessible data about apps and users. &lt;strong&gt;Formo is a data platform&lt;/strong&gt; that helps crypto teams measure what matters and make impactful decisions with data, without a dedicated data team of SQL wizards. Instead of juggling several tools (GA, Looker, Mixpanel, Dune, block explorers), use a single data platform that gives you the full picture of what matters in less time.&lt;/p&gt;

&lt;p&gt;Designed to be an alternative to Mixpanel and Google Analytics for onchain teams, it combines the best features from web, product, and onchain analytics into one versatile platform. Save time and money from having to manage your own data infrastructure and dashboards.&lt;/p&gt;

&lt;p&gt;Formo makes it easy to digest web3 data, streamlining data collection, processing, and analysis for data-driven product teams. Unify offchain &amp;amp; onchain data with web3-native product analytics to get full onchain attribution. Understand who your users are and how they engage with your app with powerful wallet intelligence.&lt;/p&gt;

&lt;p&gt;Focus on building amazing onchain experiences. Leave the data engineering to us.&lt;/p&gt;

&lt;h2 id=&quot;key-features&quot;&gt;Key Features&lt;/h2&gt;

&lt;p&gt;Here’s a quick overview of what Formo can do: product analytics, wallet intelligence, and forms.&lt;/p&gt;

&lt;p&gt;Say hello to &lt;strong&gt;Web3-native Product Analytics&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Growth analytics:&lt;/strong&gt; Track visitor counts, DAU, WAU, MAU, transactions, retention, and churn. Measure engagement and growth over time.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Real-time activity feed:&lt;/strong&gt; See what users are doing in real-time. Uncover hidden drop-off points and retention drivers.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Onchain Attribution:&lt;/strong&gt; Identify the top channels and growth initiatives that drive onchain activity. Understand where users come from.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Privacy-friendly:&lt;/strong&gt; No third-party cookies, no IP, and no fingerprinting. Just clear, privacy-friendly insights. Formo helps your dapp align with GDPR standards and avoid collecting unnecessary data.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Lightweight:&lt;/strong&gt; Formo’s tracking script ensures your site remains fast.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Wallet intelligence&lt;/strong&gt; activates your high-intent users and whales:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Wallet profiles:&lt;/strong&gt; Turn anonymous wallets into high-value users with unified onchain and offchain data. Track usage of specific, high-value wallets on your dapp.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Wallet scoring:&lt;/strong&gt; Use wallet labels, onchain attestations, and proof-of-personhood to segment and rank your users.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Wallet holdings:&lt;/strong&gt; View your users’ token holdings and top apps. Uncover users using similar apps.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Token Gated Forms&lt;/strong&gt; helps you effortlessly launch waitlists, forms, and surveys:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Verified socials:&lt;/strong&gt; Verify Twitter accounts, Discord usernames, Farcaster, and more.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Token gating:&lt;/strong&gt; Capture wallet data, token balances, attestations, and other onchain signals.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Zapier integration:&lt;/strong&gt; Connect Formo with thousands of other apps to get things done faster.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;formo-handles-the-data-so-you-can-focus-on-building&quot;&gt;Formo handles the data so you can focus on building&lt;/h2&gt;

&lt;p&gt;Formo makes analytics for onchain apps easy.&lt;/p&gt;

&lt;p&gt;Spend less time building analytics and more time building products. Get data superpowers with the data platform designed for crypto-native teams:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Resilient Infrastructure:&lt;/strong&gt; Zero-maintenance, high-reliability data pipelines built on a modern data engineering stack. Formo uses industry-leading technologies such as Clickhouse and data streaming.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Universal Data Access:&lt;/strong&gt; Capture web2 and web3 data as standardized event schemas with the Formo SDK. Easily track attribution from initial engagement offchain to transactions onchain.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;No-code Analytics:&lt;/strong&gt; Formo eliminates the need for a dedicated data team of SQL wizards to create dashboards and data pipelines.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Leading crypto teams use Formo to drive growth and impact onchain. Understand your onchain users, where they come from, and what they do so you can build a better product.&lt;/p&gt;

&lt;h2 id=&quot;next-steps&quot;&gt;Next steps&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Create a workspace&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sign in to &lt;a href=&quot;https://app.formo.so/&quot;&gt;app.formo.so&lt;/a&gt; to create your project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Install Formo&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://docs.formo.so/install&quot;&gt;Install Formo&lt;/a&gt;. The Formo SDK supports Browser, React, and Next.js.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Success!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Light up the dark forest with Formo.&lt;/strong&gt; &lt;a href=&quot;https://cal.com/formo&quot;&gt;Book a demo&lt;/a&gt; or &lt;a href=&quot;https://docs.formo.so&quot;&gt;learn more&lt;/a&gt;.&lt;/p&gt;</content><author><name>Yos Riady</name><email>hello@yos.io</email></author><category term="data" /><category term="crypto" /><category term="analytics" /><summary type="html">This article was originally posted on the Formo Blog. Developer tools remove barriers to innovation. Analytics remove barriers to growth Data is the lifeblood of any business. It helps you understand your customers and where they came from, make impactful data-driven decisions, and drive sustainable growth. Without data, you’re lost in a dark forest. However, understanding onchain user behavior is hard. Teams struggle to set up analytics and attribution from fragmented tools, data pipelines, and databases. Many teams give up altogether. Formo is the data platform for onchain apps. Formo makes analytics easy for crypto. Get the best of web, product, and onchain analytics on one versatile platform.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://yos.io/assets/actionable-insights-for-onchain-apps.jpg" /><media:content medium="image" url="https://yos.io/assets/actionable-insights-for-onchain-apps.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Onchain is the New Online</title><link href="https://yos.io/2024/09/02/onchain-is-the-new-online/" rel="alternate" type="text/html" title="Onchain is the New Online" /><published>2024-09-02T00:00:00+00:00</published><updated>2024-09-02T00:00:00+00:00</updated><id>https://yos.io/2024/09/02/onchain-is-the-new-online</id><content type="html" xml:base="https://yos.io/2024/09/02/onchain-is-the-new-online/">&lt;p&gt;&lt;img src=&quot;https://yos.io/assets/recently.png&quot; alt=&quot;Onchain is the new online&quot; /&gt;&lt;/p&gt;

&lt;p&gt;gm! It’s been a long while. 👋&lt;/p&gt;

&lt;p&gt;Onchain summer is here. A new wave of consumer crypto apps is coming. 🕶️&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;whats-happening&quot;&gt;What’s happening?&lt;/h2&gt;

&lt;p&gt;In the past year, consumer dapps have driven substantial growth in unique active wallets.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://yos.io/assets/consumer-dau.avif&quot; alt=&quot;Consumer crypto has seen some success.&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;decentralized-social-is-booming&quot;&gt;Decentralized social is booming&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;https://yos.io/assets/farcaster.avif&quot; alt=&quot;Farcaster DAU is going up and to the right.&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Web3 social apps are no longer a niche use case. &lt;a href=&quot;https://warpcast.com/&quot;&gt;Farcaster&lt;/a&gt; and &lt;a href=&quot;https://hey.xyz/&quot;&gt;Lens&lt;/a&gt; are breaking records in user activity.&lt;/p&gt;

&lt;h3 id=&quot;prediction-markets-entered-the-mainstream&quot;&gt;Prediction markets entered the mainstream&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;https://yos.io/assets/polymarket.png&quot; alt=&quot;Polymarket lets you bet on the outcome of future events in a wide range of topics.&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Last month, &lt;a href=&quot;https://polymarket.com/&quot;&gt;Polymarket&lt;/a&gt;, an onchain prediction market, saw a massive increase in activity with a volume of $472.87 million and over 50,000 active users.&lt;/p&gt;

&lt;h3 id=&quot;stablecoins-are-everywhere-with-tradfi-joining-in&quot;&gt;Stablecoins are everywhere, with TradFi joining in&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://tomtunguz.com/allium/&quot;&gt;Stablecoins are experiencing rapid growth.&lt;/a&gt;. Today, 56% of Fortune 500 companies are working on on-chain projects. Stablecoins now process more than twice as much transaction value as Visa every month. Bitcoin ETFs counts $63b in assets under management. BlackRock &amp;amp; Fidelity have launched tokenized Treasury products with nearly $1b in assets combined. Stripe now allows its merchants to accept payments in Ethereum, Solana, &amp;amp; Polygon without transaction fees. PayPal’s stablecoin has more than $0.5b in assets.&lt;/p&gt;

&lt;p&gt;This trend continues as &lt;a href=&quot;https://bridge.xyz/&quot;&gt;stablecoin APIs&lt;/a&gt; are laying more and more crypto rails. I believe stablecoin-based products will replace traditional payment networks. It’s already faster (days vs seconds) and cheaper (10s of dollars vs cents). It will bring billions of new users onchain.&lt;/p&gt;

&lt;h3 id=&quot;blockchains-are-now-scalable&quot;&gt;Blockchains are now scalable&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;https://yos.io/assets/dencun.avif&quot; alt=&quot;L2 fees are at an all-time low after the Dencun upgrade.&quot; /&gt;&lt;/p&gt;

&lt;p&gt;On the infrastructure side, network fees are at an all-time low thanks to the Dencun upgrade and new L2s. Today, builders can deploy new consumer-friendly rollups in a few clicks with &lt;a href=&quot;https://www.conduit.xyz/&quot;&gt;Conduit&lt;/a&gt; and &lt;a href=&quot;https://www.caldera.xyz/&quot;&gt;Caldera&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;usability-in-web3-is-getting-better&quot;&gt;Usability in web3 is getting better&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;https://yos.io/assets/embedded.webp&quot; alt=&quot;Embedded wallets simplify crypto UX by removing the need to open another app or external wallet.&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Embedded wallets and social logins are ubiquitous, enabling seamless UX for new users. Builders can onboard users with &lt;a href=&quot;https://www.privy.io/&quot;&gt;Privy&lt;/a&gt; and &lt;a href=&quot;https://dynamic.xyz/&quot;&gt;Dynamic&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;These are all promising adoption signals. We are at the cusp of a new crypto consumer wave in web3, but…&lt;/p&gt;

&lt;h2 id=&quot;whats-next&quot;&gt;What’s next?&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Building a successful consumer product is hard&lt;/strong&gt;. According to &lt;a href=&quot;https://www.binance.com/en/research/analysis/web3-the-household-name-in-the-making&quot;&gt;Binance Research&lt;/a&gt;, web3 has yet to break into the mainstream:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Average retention rate in web3 stands at 5.4%. Web2 retention rates are significantly higher, with a good rate considered between 25-40%.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;A prime example of crypto’s retention struggles is seen in Starknet, where user retention fell sharply from 18.0% post-March to just 4.3%. This decline was likely driven by the conclusion of their airdrop campaign, illustrating the limited impact of speculative incentives on long-term engagement.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;https://framerusercontent.com/images/ZMkG1XU42YI5h8f9S076YR5vzQ.png&quot; alt=&quot;User retention remains a significant challenge for web3.&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The data indicates that beyond broadening crypto’s reach to mainstream audiences, we must expand crypto’s adoption frontier beyond mere speculation and profit-making purposes. This means creating compelling consumer crypto products that generate intrinsic demand and keep users engaged.&lt;/p&gt;

&lt;h2 id=&quot;we-need-better-tools&quot;&gt;We need better tools&lt;/h2&gt;

&lt;p&gt;In the 2010s Hubspot and Mixpanel transformed online marketing and product analytics respectively. Analytics tools like theirs made it easier for internet builders to understand and use data about online users. Alongside them came a wave of web2 consumer apps we still use today.&lt;/p&gt;

&lt;p&gt;Building a successful consumer product is hard. It gets harder when you don’t know who your users are and how they use your product. Analytics and data tools are fundamental for the success of consumer apps. Soon they will play a critical role in consumer crypto.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://pbs.twimg.com/media/GBoL2WRWUAAcV1o?format=jpg&quot; alt=&quot;Crossing the chasm&quot; /&gt;&lt;/p&gt;

&lt;p&gt;For the next while, I’ve decided to focus on solving challenges at the intersection of blockchain, data, and product analytics.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Are you building in web3? &lt;a href=&quot;mailto:yos@formo.so&quot;&gt;Say hi&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;</content><author><name>Yos Riady</name><email>hello@yos.io</email></author><category term="thoughts" /><summary type="html">gm! It’s been a long while. 👋 Onchain summer is here. A new wave of consumer crypto apps is coming. 🕶️</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://yos.io/assets/recently.png" /><media:content medium="image" url="https://yos.io/assets/recently.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">How to Replace the Bytecode of Deployed Solidity Contracts</title><link href="https://yos.io/2022/08/07/replace-deployed-solidity-bytecode-for-testing/" rel="alternate" type="text/html" title="How to Replace the Bytecode of Deployed Solidity Contracts" /><published>2022-08-07T00:00:00+00:00</published><updated>2022-08-07T00:00:00+00:00</updated><id>https://yos.io/2022/08/07/replace-deployed-solidity-bytecode-for-testing</id><content type="html" xml:base="https://yos.io/2022/08/07/replace-deployed-solidity-bytecode-for-testing/">&lt;p&gt;&lt;img src=&quot;https://yos.io/assets/replace-bytecode-solidity.jpeg&quot; alt=&quot;How to Replace Bytecode of Deployed Solidity Contracts&quot; /&gt;&lt;/p&gt;

&lt;p&gt;What if there is a hardcoded contract address in another contract you need to test? External dependencies in smart contracts are sometimes stored as immutable and constant variables:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-solidity&quot; data-lang=&quot;solidity&quot;&gt;&lt;span class=&quot;k&quot;&gt;contract&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vault&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// An external dependency hardcoded at a specific address
&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;IOracle&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;constant&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;oracle&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IOracle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x773616E4d11A78F511299002da57A0a94577F1f4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In unit tests, we may need to modify external dependecies to produce specific answers behaviours and test multiple scenarios.&lt;/p&gt;

&lt;p&gt;We can use forked mainnet and testnet networks to test against live external dependencies locally. However, hardcoded addresses prevent us from swapping them out with a local version deployed at another address. We need a way to mock an already deployed contract at a specific hardcoded address.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How can we replace the bytecode of an existing contract?&lt;/strong&gt;&lt;/p&gt;

&lt;!--more--&gt;

&lt;p&gt;Let’s say that we want to replace the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;oracle&lt;/code&gt; contract in our unit tests with a local mock.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-solidity&quot; data-lang=&quot;solidity&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// Our own mock IOracle contract, for testing purposes
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;contract&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MockOracle&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IOracle&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;First, we deploy our oracle contract locally with Hardhat:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;MockOracle&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ethers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getContractFactory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;MockOracle&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;mockOracle&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;MockOracle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;deploy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Next, we need to replace the bytecode in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOracle(0x773616E4d11A78F511299002da57A0a94577F1f4)&lt;/code&gt; with our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MockOracle&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;We use the Ethereum JSON-RPC API &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eth_getCode()&lt;/code&gt; to get bytecode of the newly deployed contract.&lt;/li&gt;
  &lt;li&gt;Then, we use Hardhat’s  &lt;a href=&quot;https://hardhat.org/hardhat-network-helpers/docs/reference#setcode(address,-code)&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eth_setCode()&lt;/code&gt;&lt;/a&gt; to substitute the contents of the hardcoded address:&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;code&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;hre&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;network&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;provider&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;eth_getCode&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;mockOracle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;hre&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;network&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;provider&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;hardhat_setCode&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;0x773616E4d11A78F511299002da57A0a94577F1f4&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In the above snippet, we get the bytecode of our deployed contract and set it to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MyOracle&lt;/code&gt; and set it to the hardcoded &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOracle&lt;/code&gt; address.&lt;/p&gt;

&lt;p&gt;That’s it! We now know how to change the bytecode of an existing contract for testing purposes. This feature lets you write more exhaustive tests and ship well-tested smart contracts.&lt;/p&gt;</content><author><name>Yos Riady</name><email>hello@yos.io</email></author><category term="ethereum" /><category term="solidity" /><category term="solhint" /><summary type="html">What if there is a hardcoded contract address in another contract you need to test? External dependencies in smart contracts are sometimes stored as immutable and constant variables: contract Vault { // An external dependency hardcoded at a specific address IOracle public constant oracle = IOracle(0x773616E4d11A78F511299002da57A0a94577F1f4); function foo() { ... } } In unit tests, we may need to modify external dependecies to produce specific answers behaviours and test multiple scenarios. We can use forked mainnet and testnet networks to test against live external dependencies locally. However, hardcoded addresses prevent us from swapping them out with a local version deployed at another address. We need a way to mock an already deployed contract at a specific hardcoded address. How can we replace the bytecode of an existing contract?</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://yos.io/assets/replace-bytecode-solidity.jpeg" /><media:content medium="image" url="https://yos.io/assets/replace-bytecode-solidity.jpeg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Bubbling Up Errors in Solidity</title><link href="https://yos.io/2022/07/16/bubbling-up-errors-in-solidity/" rel="alternate" type="text/html" title="Bubbling Up Errors in Solidity" /><published>2022-07-16T00:00:00+00:00</published><updated>2022-07-16T00:00:00+00:00</updated><id>https://yos.io/2022/07/16/bubbling-up-errors-in-solidity</id><content type="html" xml:base="https://yos.io/2022/07/16/bubbling-up-errors-in-solidity/">&lt;p&gt;&lt;img src=&quot;https://yos.io/assets/bubbling-up-errors.jpeg&quot; alt=&quot;Bubbling up errors in Solidity&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Let’s say that you have a contract A which makes a low-level &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;call&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;delegatecall&lt;/code&gt; to another contract B:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-solidity&quot; data-lang=&quot;solidity&quot;&gt;&lt;span class=&quot;k&quot;&gt;contract&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;address&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bytes&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;external&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bytes&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;memory&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;delegatecall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// used to call B.bar()
&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The target contract B reverts with a revert message or custom error:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-solidity&quot; data-lang=&quot;solidity&quot;&gt;&lt;span class=&quot;k&quot;&gt;contract&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;B&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AccessForbidden&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;address&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sender&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;external&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;revert&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AccessForbidden&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sender&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;strong&gt;How can you bubble the error up in contract A?&lt;/strong&gt;&lt;/p&gt;

&lt;!--more--&gt;

&lt;h3 id=&quot;low-level-calls-do-not-revert&quot;&gt;Low-level calls do not revert&lt;/h3&gt;

&lt;p&gt;First of all, it’s important to know that a low-level &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;call&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;delegatecall&lt;/code&gt; doesn’t revert while calling a function that reverts:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-solidity&quot; data-lang=&quot;solidity&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// These won't revert even if the target contract reverts!
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bytes&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;memory&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bytes&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;memory&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;delegatecall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In the above example, when contract A calls contract B with a low-level call, The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;success&lt;/code&gt; variable signals whether the call was successful (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt;) or unsuccessful (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;false&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Using this, we could revert in the calling contract like so:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-solidity&quot; data-lang=&quot;solidity&quot;&gt;&lt;span class=&quot;k&quot;&gt;contract&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;address&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bytes&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;external&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bytes&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;memory&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;delegatecall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;However, the above code swallows any errors returned from the target contract! We don’t know what went wrong because no errors are bubbled up even though contract B reverts.&lt;/p&gt;

&lt;h3 id=&quot;bubbling-up-errors&quot;&gt;Bubbling up errors&lt;/h3&gt;

&lt;p&gt;Let’s examine the following solution:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-solidity&quot; data-lang=&quot;solidity&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bytes&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;memory&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;delegatecall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// If call reverts
&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// If there is return data, the call reverted without a reason or a custom error.
&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;revert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;assembly&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// We use Yul's revert() to bubble up errors from the target contract.
&lt;/span&gt;    &lt;span class=&quot;nb&quot;&gt;revert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ul&gt;
  &lt;li&gt;An inline assembly block is marked by assembly &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{ ... }&lt;/code&gt;, where the code inside the curly braces is code in the &lt;a href=&quot;https://docs.soliditylang.org/en/v0.8.13/yul.html#yul&quot;&gt;Yul&lt;/a&gt; language.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;result&lt;/code&gt; is a dynamic-size byte array. If the external contract call fails, the error object is returned in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;result&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;The Yul &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;revert&lt;/code&gt;  function takes in two inputs: 1) the pointer of where the error byte array starts, and 2) how long the byte array is.&lt;/li&gt;
  &lt;li&gt;For dynamic-size byte arrays, the first 32 bit of the pointer stores its size.
    &lt;ul&gt;
      &lt;li&gt;To fill in 1), we do &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add(32, result)&lt;/code&gt; to calculate the pointer where the byte array starts.&lt;/li&gt;
      &lt;li&gt;To fill in 2), we do &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mload(result)&lt;/code&gt; to retrieve this value.&lt;/li&gt;
      &lt;li&gt;Combining the above, we get &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;revert(add(32, result), mload(result))&lt;/code&gt;, which reverts the error raised in contract B.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;When there is no revert data returned by the target contract, we terminate early with an empty revert.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, when you call contract B from contract A you get the following revert message:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;&quot;AccessForbidden(0x123...)&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In unit tests, you can write the following (with Hardhat):&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;reverts&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;myContract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;TEST_ADDRESS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;TEST_BYTES&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;be&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;revertedWith&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;AccessForbidden()&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Nice! By bubbling up errors we ensure that contracts do not fail silently and fail with additional context when they are available.&lt;/p&gt;</content><author><name>Yos Riady</name><email>hello@yos.io</email></author><category term="ethereum" /><category term="solidity" /><summary type="html">Let’s say that you have a contract A which makes a low-level call or delegatecall to another contract B: contract A { function foo(address target, bytes data) external { (bool success, bytes memory result) = target.delegatecall(data) // used to call B.bar() } } The target contract B reverts with a revert message or custom error: contract B { error AccessForbidden(address sender); function bar() external { revert AccessForbidden(msg.sender); } } How can you bubble the error up in contract A?</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://yos.io/assets/bubbling-up-errors.jpeg" /><media:content medium="image" url="https://yos.io/assets/bubbling-up-errors.jpeg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Auditing Smart Contracts with Slither and Echidna</title><link href="https://yos.io/2022/02/20/audit-smart-contracts-with-slither-and-echidna/" rel="alternate" type="text/html" title="Auditing Smart Contracts with Slither and Echidna" /><published>2022-02-20T00:00:00+00:00</published><updated>2022-02-20T00:00:00+00:00</updated><id>https://yos.io/2022/02/20/audit-smart-contracts-with-slither-and-echidna</id><content type="html" xml:base="https://yos.io/2022/02/20/audit-smart-contracts-with-slither-and-echidna/">&lt;p&gt;&lt;img src=&quot;https://yos.io/assets/audit-smart-contracts.jpeg&quot; alt=&quot;Auditing Smart Contracts with Slither and Echidna&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The goal of smart contract audits is to assess code (alongside technical specifications and documentation) and alert project team of potential security issues that need to be addressed to &lt;strong&gt;improve security posture, decrease attack surface, and mitigate risk.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;An audit helps to detect and resolve security issues before launch, summarized as a set of findings with underlying vulnerabilities, severity, difficulty, sample exploit scenarios, and recommended mitigations.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://yos.io/assets/audit0.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Given &lt;a href=&quot;https://rekt.news/leaderboard/&quot;&gt;the high cost of smart contract bugs&lt;/a&gt;, it’s no surprise that an audit is a key step in the smart contract development lifecycle. However, engaging an auditor can be costly and difficult due to high demand.&lt;/p&gt;

&lt;p&gt;In this article, we’ll learn how you can use the open source tools &lt;strong&gt;Slither&lt;/strong&gt; and &lt;strong&gt;Echidna&lt;/strong&gt; to audit Solidity contracts, in order to identify any potential security vulnerabilities.&lt;/p&gt;

&lt;!--more--&gt;

&lt;blockquote&gt;
  &lt;p&gt;Thank you for reading.&lt;/p&gt;

  &lt;p&gt;Note that automated tools cannot replace manual code analysis and review from experienced smart contract security experts. However, they do help you move in the right direction by highlighting important best practices and common security vulnerabilities. &lt;strong&gt;An audit remains a critical step that a protocol should undergo before going live.&lt;/strong&gt;&lt;/p&gt;

  &lt;p&gt;Utilizing these tools in your development workflow helps you write more secure contracts so fewer security issues remain before the audit phase.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;background&quot;&gt;Background&lt;/h3&gt;

&lt;p&gt;I’m Yos, a Solidity engineer. I recently participated in the &lt;a href=&quot;https://secureum.xyz/&quot;&gt;Secureum&lt;/a&gt; smart contract security audit bootcamp (and ranked in the Top 25 out of 1000 participants.) The 3 month+ program ends with a practical component where the top participants would audit a real protocol, review the code, and raise any security vulnerabilities over the course of a month.&lt;/p&gt;

&lt;p&gt;Auditors generate a summarized report for the project team that highlights their findings ranked by severity from high to low, as well as exploit details and recommended mitigations. I applied a combination of manual code analysis based on Solidity best practices and security vulnerabilities alongside automated tools to audit Solidity smart contracts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The open source tools we’re about to cover in this article (Slither and Echidna) are frequently used by top smart contract auditors to supplement manual code analysis.&lt;/strong&gt; They help automate the process of reviewing code quality and correctness in an increasingly sophisticated smart contract ecosystem.&lt;/p&gt;

&lt;p&gt;In the rest of this article, we’ll first learn about common security pitfalls and how an audit helps, before finally jumping into the tools: Slither and Echidna.&lt;/p&gt;

&lt;h2 id=&quot;common-security-pitfalls&quot;&gt;Common Security Pitfalls&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://rekt.news/&quot;&gt;Smart contract bugs occur more frequently than it should&lt;/a&gt;, with hefty consequences for everyone involved, for both users and project teams.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://yos.io/assets/audit1.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Common real-world security vulnerabilities include:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Inadequate access controls (giving malicious actors access to sensitive operations)&lt;/li&gt;
  &lt;li&gt;Invalid input sanitation (failing to prevent exploits)&lt;/li&gt;
  &lt;li&gt;Incorrect inheritance (leading to other issues)&lt;/li&gt;
  &lt;li&gt;Arithmetic errors (underflow and overflow errors)&lt;/li&gt;
  &lt;li&gt;Business logic errors (failing to match technical specifications)&lt;/li&gt;
  &lt;li&gt;Non-conformance to standards (e.g. ERC20 return values)&lt;/li&gt;
  &lt;li&gt;External interactions with other contracts (e.g. flashloans, ERC777 callbacks, transfer fee ERC20 tokens, etc.)&lt;/li&gt;
  &lt;li&gt;State machine traps leading to locked contracts (e.g. invalid balances reverting require statements)&lt;/li&gt;
  &lt;li&gt;And many &lt;a href=&quot;https://swcregistry.io/&quot;&gt;others&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even the smallest of smart contract bugs can render the largest of DeFi products useless or open to exploits. This is exacerbated by the fact that most smart contracts are difficult or impossible to upgrade.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How can we mitigate the risk of smart contract bugs and exploits?&lt;/strong&gt; Can we identify and fix these issues before we launch?&lt;/p&gt;

&lt;h2 id=&quot;smart-contract-audits&quot;&gt;Smart Contract Audits&lt;/h2&gt;

&lt;p&gt;A smart contract audit is an external security assessment of a project codebase, typically requested and paid-for by the project team. For most projects, the scope is typically the on-chain smart contract code and occassionally any critical off-chain components that interact with the contracts.&lt;/p&gt;

&lt;p&gt;The goal of an audit is to assess and alert the project team, typically before launch, of potential security-related issues that need to be addressed to improve security posture, decrease attack surface, and mitigate risk.&lt;/p&gt;

&lt;p&gt;An audit helps to detect and resolve security issues (such as the ones highlighted above.) The auditor will share their findings of underlying vulnerabilities, severity, difficulty, sample exploit scenarios, and recommended mitigations. The project team will fix these issues and review them with the auditor before moving forward with the launch.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Here are &lt;a href=&quot;https://consensys.net/diligence/audits/&quot;&gt;some&lt;/a&gt; &lt;a href=&quot;https://github.com/trailofbits/publications/tree/master/reviews&quot;&gt;examples&lt;/a&gt; of audit reports.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;smart-contract-security-tools&quot;&gt;Smart Contract Security Tools&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://yos.io/assets/audit2.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Alongside manual code review, &lt;strong&gt;smart contract auditing tools&lt;/strong&gt; automate many of the tasks that can be codified into rules with different levels of coverage, correctness and precision. They enable the auditor to cover more ground and focus on high-level design review.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;They are fast, cheap, scalable and deterministic compared to manual analysis.&lt;/li&gt;
  &lt;li&gt;They are a snapshot of distilled smart contract security knowledge.&lt;/li&gt;
  &lt;li&gt;Well-suited to detect common security pitfalls and best-practices at the Solidity and EVM level.&lt;/li&gt;
  &lt;li&gt;With manual assistance, they can be programmed to check for application-level, business-logic constraints.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Note that automated tools are a supplement, not a replacement for security expertise and manual code analysis by experienced smart contract developers.&lt;/em&gt; Interpreting the outputs of these tools demand some level of familiarity with Solidity.&lt;/p&gt;

&lt;p&gt;In the next section, we’ll learn about the following smart contract security auditing tools:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Slither, a static analysis tool for Solidity code.&lt;/li&gt;
  &lt;li&gt;Echidna, a fuzz testing tool.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You’ll learn about what they are, what they’re used for, and how you can start using them to audit Solidity smart contracts.&lt;/p&gt;

&lt;h2 id=&quot;slither&quot;&gt;Slither&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://yos.io/assets/audit3.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/crytic/slither&quot;&gt;Slither&lt;/a&gt; is a static analysis tool for Solidity code. It takes in one or more contracts and generates a list of security vulnerabilities and other best-practice recommendations.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Static_program_analysis&quot;&gt;Static analysis&lt;/a&gt; is a technique of analyzing program properties without actually executing the program. This is in contrast to software testing where programs are actually executed with different inputs. Static analysis typically is a combination of control flow and data flow analyses.&lt;/p&gt;

&lt;p&gt;Examples of other static analysis tools are &lt;a href=&quot;https://eslint.org/&quot;&gt;ESLint&lt;/a&gt; for Javascript and &lt;a href=&quot;https://github.com/protofire/solhint&quot;&gt;Solhint&lt;/a&gt; for Solidity.&lt;/p&gt;

&lt;p&gt;Slither performs control-flow and data-flow analyses on smart contracts in the context of their set of detectors which encode common security pitfalls and best-practices. It comes with 70+ built-in detectors covering issues such as uninitialized variables, inheritance, access control, and structural issues. You can also add your own detector functions to look for specific patterns.&lt;/p&gt;

&lt;p&gt;Here’s an excerpt of Slither’s built-in detectors:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://yos.io/assets/audit4.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;When you run slither on a contract like so:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;slither contracts/strategies/AaveStrategy.sol&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Slither will enumerate over each detector and generate a report:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;BaseStrategy._swap&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;uint256[],address[],address&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;.i &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;contracts/BaseStrategy.sol#312&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; is a &lt;span class=&quot;nb&quot;&gt;local &lt;/span&gt;variable never initialized
UniswapV2Library.getAmountsOut&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;address,uint256,address[]&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;.i &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;contracts/libraries/UniswapV2Library.sol#73&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; is a &lt;span class=&quot;nb&quot;&gt;local &lt;/span&gt;variable never initialized
Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#uninitialized-local-variables

AaveStrategy._harvest&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;uint256&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;contracts/strategies/AaveStrategy.sol#77-81&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; ignores &lt;span class=&quot;k&quot;&gt;return &lt;/span&gt;value by aaveLendingPool.withdraw&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;address&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;strategyToken&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;,uint256&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;amountAdded&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;,address&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;this&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;contracts/strategies/AaveStrategy.sol#80&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
AaveStrategy._withdraw&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;uint256&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;contracts/strategies/AaveStrategy.sol#83-85&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; ignores &lt;span class=&quot;k&quot;&gt;return &lt;/span&gt;value by aaveLendingPool.withdraw&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;address&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;strategyToken&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;,amount,address&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;this&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;contracts/strategies/AaveStrategy.sol#84&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
AaveStrategy._exit&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;contracts/strategies/AaveStrategy.sol#87-97&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; ignores &lt;span class=&quot;k&quot;&gt;return &lt;/span&gt;value by aaveLendingPool.withdraw&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;address&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;strategyToken&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;,tokenBalance,address&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;this&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;contracts/strategies/AaveStrategy.sol#92&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
AaveStrategy._exit&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;contracts/strategies/AaveStrategy.sol#87-97&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; ignores &lt;span class=&quot;k&quot;&gt;return &lt;/span&gt;value by aaveLendingPool.withdraw&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;address&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;strategyToken&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;,available,address&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;this&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;contracts/strategies/AaveStrategy.sol#95&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
AaveStrategy._harvestRewards&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;contracts/strategies/AaveStrategy.sol#99-104&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; ignores &lt;span class=&quot;k&quot;&gt;return &lt;/span&gt;value by incentiveController.claimRewards&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;rewardTokens,reward,address&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;this&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;contracts/strategies/AaveStrategy.sol#103&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#unused-return&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In each section are the line number of the problematic code as well as reference links to details about the issue:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://yos.io/assets/audit5.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;You can use this information to learn about Solidity best practices and mitigate common security vulnerabilities. However, bear in mind that Slither will generate false positives or non-issues. Determining which issues are relevant requires some familiarity with Solidity and smart contract security.&lt;/p&gt;

&lt;p&gt;In addition to general reporting, Slither also comes with a set of printers which helps you inspect your contract’s inheritance tree and variable dependencies.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://yos.io/assets/audit6.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;You can run a printer like so:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;slither MyContract.sol &lt;span class=&quot;nt&quot;&gt;--print&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;printer name]&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;For example, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vars-and-auth&lt;/code&gt; printer gives you a useful summary of modifiers and variable dependencies for your contracts:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;Contract Ownable
Contract vars: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'_owner'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
Inheritance:: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'Context'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;

+----------------------------+------------+---------------+----------------+------------+---------------------------------------+----------------+
|          Function          | Visibility |   Modifiers   |      Read      |   Write    |             Internal Calls            | External Calls |
+----------------------------+------------+---------------+----------------+------------+---------------------------------------+----------------+
|        _msgSender&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;        |  internal  |       &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;      | &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'msg.sender'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; |     &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;     |                   &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;                  |       &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;       |
|         _msgData&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;         |  internal  |       &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;      |  &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'msg.data'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;  |     &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;     |                   &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;                  |       &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;       |
|       constructor&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;        |  internal  |       &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;      |       &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;       |     &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;     |      &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'_msgSender'&lt;/span&gt;, &lt;span class=&quot;s1&quot;&gt;'_setOwner'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;      |       &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;       |
|          owner&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;           |   public   |       &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;      |   &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'_owner'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;   |     &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;     |                   &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;                  |       &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;       |
|    renounceOwnership&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;     |   public   | &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'onlyOwner'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; |       &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;       |     &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;     |       &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'onlyOwner'&lt;/span&gt;, &lt;span class=&quot;s1&quot;&gt;'_setOwner'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;      |       &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;       |
| transferOwnership&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;address&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; |   public   | &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'onlyOwner'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; |       &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;       |     &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;     | &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'onlyOwner'&lt;/span&gt;, &lt;span class=&quot;s1&quot;&gt;'require(bool,string)'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; |       &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;       |
|                            |            |               |                |            |             &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'_setOwner'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;             |                |
|     _setOwner&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;address&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;     |  private   |       &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;      |   &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'_owner'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;   | &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'_owner'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; |                   &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;                  |       &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;       |
+----------------------------+------------+---------------+----------------+------------+---------------------------------------+----------------+&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The above is useful for auditors to quickly review if access control modifiers are correctly implemented.&lt;/p&gt;

&lt;p&gt;Running the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;inheritance-graph&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cfg&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;call-graph&lt;/code&gt; printers generates visualizations of your contract’s inheritance tree, control flow graph and more. For example, an inheritance tree:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://yos.io/assets/audit14.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In summary, Slither is a low-cost static analysis tool that you can simply run on your contracts. It helps detect common vulnerabilities and enforce known best practices. Slither Printers are helpful to review a contract’s structure in detail.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://yos.io/assets/audit7.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Slither analyzes contracts within seconds. However, static analysis often leads to false positives and &lt;strong&gt;is not suitable for complex checks against high-level proxies and business logic.&lt;/strong&gt; For that, we have Echidna.&lt;/p&gt;

&lt;h2 id=&quot;echidna&quot;&gt;Echidna&lt;/h2&gt;

&lt;p&gt;If we model smart contracts as state machines, we want to make sure that &lt;strong&gt;no invalid state can be reached&lt;/strong&gt;. This usually means that there’s inadequate input sanitation or a business logic error somewhere in our code.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/crytic/echidna&quot;&gt;Echidna&lt;/a&gt; can help us detect invalid state machines. &lt;strong&gt;Echidna is a fuzz testing tool for Solidity code.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Fuzzing&quot;&gt;Fuzz testing&lt;/a&gt; is an automated software testing technique that involves providing invalid, unexpected, or random data as inputs to a computer program. The program is then monitored for exceptions such as crashes, failing built-in code assertions, or potential memory leaks.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://yos.io/assets/audit8.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Echidna work as follows:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://yos.io/assets/audit9.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;You start by writing &lt;strong&gt;invariants, or high-level properties about your system.&lt;/strong&gt; For example, an invariant of a stablecoin or DeFi lending protocol may be ‘undercollateralied vaults should always be open for liquidation.’ This is expressed as boolean Solidity expressions like so:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;https://yos.io/assets/audit12.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Next, Echidna will then call your contracts with a pseudo-random generation of transactions, where it will try to find a sequence of transactions to violate your invariants.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Finally, if Echidna manages to break an invariant, it will give you the list of contract calls (state transitions) that it used to get there.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;https://yos.io/assets/audit13.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In summary, Echidna is a higher cost, but also higher impact tool compared to Slither.&lt;/p&gt;

&lt;p&gt;Echidna requires more time investment than Slither (it takes longer to run, and needs high-level invariants written by humans) but will only produce true positives. &lt;strong&gt;The true positives Echidna discovers are usually significant and extreme corner cases missed even by the best manual analyses.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In addition, The act of writing invariants helps ensures key system invariants to be documented and tracked somewhere. As the codebase grows, Echidna tests makes sure that there are no regressions in the contracts’ state machine over time.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://yos.io/assets/audit10.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;echidna-exercise&quot;&gt;Echidna Exercise&lt;/h2&gt;

&lt;p&gt;Learn by doing and try running Echidna on &lt;a href=&quot;https://gist.github.com/yosriady/d57fb492957dd450a15c177e3855e532&quot;&gt;these sample contracts I’ve written&lt;/a&gt;. Each contract has a security vulnerability that needs to be fixed. See if you can identify the underlying issue with Echidna and fix it. Then, rerun Echidna to fuzz test and verify that your fix is correct.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-solidity&quot; data-lang=&quot;solidity&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// Sample insecure contract
&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;pragma&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;solidity&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;contract&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Token&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;mapping&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;address&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;balances&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;transfer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;address&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uint&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;balances&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sender&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;balances&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;contract&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EchidnaTest&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Token&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;address&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;echidna_caller&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00a329C0648769a73afAC7F9381e08fb43DBEA70&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;balances&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;echidna_caller&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// add the property
&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;echidna_test_balance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;view&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;returns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;balances&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;echidna_caller&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;blockquote&gt;
  &lt;p&gt;I recommend checking out Crytic’s &lt;a href=&quot;https://github.com/crytic/building-secure-contracts&quot;&gt;guidelines&lt;/a&gt; to fully utilize these open source tools.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://yos.io/assets/audit11.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Over the course of this article, we learned to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Recognize the impact of smart contract bugs,&lt;/li&gt;
  &lt;li&gt;Review the latest attack vectors and best practices,&lt;/li&gt;
  &lt;li&gt;Use Slither to catch common issues,&lt;/li&gt;
  &lt;li&gt;Use Echidna to test high-level properties,&lt;/li&gt;
  &lt;li&gt;And finally, ship contracts with confidence.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Start with Slither’s built-in detectors to ensure that no simple bugs are present now or will be introduced later. Use Slither to check properties related to inheritance, variable dependencies, and structural issues. As the codebase grows, use Echidna to test more complex properties of the state machine.&lt;/p&gt;

&lt;p&gt;Now you too can write more secure contracts by using Slither and Echidna to audit your Solidity code!&lt;/p&gt;</content><author><name>Yos Riady</name><email>hello@yos.io</email></author><category term="ethereum" /><category term="solidity" /><category term="slither" /><category term="echidna" /><summary type="html">The goal of smart contract audits is to assess code (alongside technical specifications and documentation) and alert project team of potential security issues that need to be addressed to improve security posture, decrease attack surface, and mitigate risk. An audit helps to detect and resolve security issues before launch, summarized as a set of findings with underlying vulnerabilities, severity, difficulty, sample exploit scenarios, and recommended mitigations. Given the high cost of smart contract bugs, it’s no surprise that an audit is a key step in the smart contract development lifecycle. However, engaging an auditor can be costly and difficult due to high demand. In this article, we’ll learn how you can use the open source tools Slither and Echidna to audit Solidity contracts, in order to identify any potential security vulnerabilities.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://yos.io/assets/audit-smart-contracts.jpeg" /><media:content medium="image" url="https://yos.io/assets/audit-smart-contracts.jpeg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Easy, Instant Mocks for Solidity Contracts</title><link href="https://yos.io/2021/09/18/instant-mocks-solidity-contracts/" rel="alternate" type="text/html" title="Easy, Instant Mocks for Solidity Contracts" /><published>2021-09-18T00:00:00+00:00</published><updated>2021-09-18T00:00:00+00:00</updated><id>https://yos.io/2021/09/18/instant-mocks-solidity-contracts</id><content type="html" xml:base="https://yos.io/2021/09/18/instant-mocks-solidity-contracts/">&lt;p&gt;&lt;img src=&quot;https://yos.io/assets/solidity-mocks.jpeg&quot; alt=&quot;Easy, Instant Mocks for Solidity Contracts&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In a previous post, we learned about &lt;a href=&quot;https://yos.io/2021/09/11/real-world-contract-development-forking-mainnet/&quot;&gt;forking mainnet&lt;/a&gt; as an alternative to mock contracts in Solidity. The major drawback with mock contracts is that you need to spend time to rewrite existing smart contracts as mocks. To get exhaustive mock coverage, you’ll end up rewriting whole protocols for the sake of testing.&lt;/p&gt;

&lt;p&gt;What if there’s a magical way to &lt;strong&gt;mock contract functionality without writing mock contracts&lt;/strong&gt;? Read on to learn more.&lt;/p&gt;

&lt;!--more--&gt;

&lt;blockquote&gt;
  &lt;p&gt;Are you new to smart contracts? Check out the open source &lt;a href=&quot;https://github.com/yosriady/contracts-starter&quot;&gt;Hardhat starter kit&lt;/a&gt;! It comes with several useful tools preconfigured such as Typescript, type generation, linting, formatting, and test coverage. Just hit clone and run!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;instant-mocks-with-waffle--smock&quot;&gt;Instant Mocks with Waffle / Smock&lt;/h2&gt;

&lt;p&gt;You can instantly create mocks with the &lt;a href=&quot;https://ethereum-waffle.readthedocs.io/en/latest/index.html&quot;&gt;Waffle&lt;/a&gt; (or &lt;a href=&quot;https://smock.readthedocs.io/en/latest/&quot;&gt;Smock&lt;/a&gt;) testing libraries. Just provide the ABI of the smart contract you want to mock:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// Waffle example&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;deployMockContract&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;@ethereum-waffle/mock-contract&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;contractABI&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;../artifacts/MyContract.json&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Set up mock contract&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;myContract&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;deployMockContract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;wallet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;contractAbi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;You can set the return values for any of your mock’s functions with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mock.&amp;lt;nameOfMethod&amp;gt;&lt;/code&gt; helpers:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// You can mock specific functions, down to specific inputs&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;myContract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;nameOfMethod&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;returns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;myContract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;nameOfMethod&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;withArgs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;returns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;You can also set up reverts using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reverts()&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;revertsWithReason()&lt;/code&gt; helpers:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;myContract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;nameOfMethod&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reverts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;myContract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;nameOfMethod&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;revertsWithReason&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reason&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;myContract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;nameOfMethod&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;withArgs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reverts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;myContract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;nameOfMethod&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;withArgs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;revertsWithReason&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reason&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Behind every mock is a real smart contract (with actual Solidity code!) This means you can modify the behavior of individual functions, and leave some functions unmocked. Any values from mocked calls will pass through to be used in the actual contract code.&lt;/p&gt;

&lt;h2 id=&quot;full-example&quot;&gt;Full Example&lt;/h2&gt;

&lt;p&gt;Let’s try to mock the following contract:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-solidity&quot; data-lang=&quot;solidity&quot;&gt;&lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IERC20&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;balanceOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;address&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;account&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;external&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;view&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;returns&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint256&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;contract&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MyContract&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;IERC20&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;uint&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;constant&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;THRESHOLD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1000000&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;18&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;constructor&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IERC20&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;token&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;check&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;view&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;returns&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;uint&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;balance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;balanceOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sender&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;balance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;THRESHOLD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In our unit tests, we will to mock the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;token.balanceOf()&lt;/code&gt; function to return specific values. Mock contracts will be used to supply exactly the values we need to test different scenarios of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MyContract.check()&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;Here’s our unit test using mocks:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;nx&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Mocking example&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;beforeEach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;signers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Signers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;signers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;SignerWithAddress&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;hre&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ethers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getSigners&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;signers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;owner&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;signers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;signers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;receiver&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;signers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;MyContractArtifact&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Artifact&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;hre&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;artifacts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;readArtifact&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;MyContract&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;contract&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;MyContract&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;deployContract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;signers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;owner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;MyContractArtifact&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]);&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ERC20Artifact&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Artifact&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;hre&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;artifacts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;readArtifact&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;MyContract&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;token&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;deployMockContract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;signers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;owner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ERC20Artifact&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;abi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;returns false if the wallet has less then 1000000 coins&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;balanceOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;returns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;utils&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;parseEther&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;999999&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;contract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;check&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;be&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;equal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;returns true if the wallet has at least 1000000 coins&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;balanceOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;returns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;utils&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;parseEther&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;1000001&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;contract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;check&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;equal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;reverts if the ERC20 reverts&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;balanceOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reverts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;contract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;check&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;be&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;revertedWith&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Mock revert&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;returns 1000001 coins for my address and 0 otherwise&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;balanceOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;returns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;balanceOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;withArgs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;signers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;owner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;returns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;utils&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;parseEther&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;1000001&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;contract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;check&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;equal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;contract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;signers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;receiver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;check&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;equal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;That’s it!&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;

&lt;p&gt;Mocks are most effectively used when you need some behavior of a real smart contract but still want the ability to modify things on the fly.&lt;/p&gt;

&lt;p&gt;Use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ethereum-waffle&lt;/code&gt; (or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smock&lt;/code&gt;) testing libraries to instantly mock smart contracts, all without writing mock contracts yourself.&lt;/p&gt;</content><author><name>Yos Riady</name><email>hello@yos.io</email></author><category term="ethereum" /><category term="solidity" /><summary type="html">In a previous post, we learned about forking mainnet as an alternative to mock contracts in Solidity. The major drawback with mock contracts is that you need to spend time to rewrite existing smart contracts as mocks. To get exhaustive mock coverage, you’ll end up rewriting whole protocols for the sake of testing. What if there’s a magical way to mock contract functionality without writing mock contracts? Read on to learn more.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://yos.io/assets/solidity-mocks.jpeg" /><media:content medium="image" url="https://yos.io/assets/solidity-mocks.jpeg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Real World Contract Development with Forked Mainnet</title><link href="https://yos.io/2021/09/11/real-world-contract-development-forking-mainnet/" rel="alternate" type="text/html" title="Real World Contract Development with Forked Mainnet" /><published>2021-09-11T00:00:00+00:00</published><updated>2021-09-11T00:00:00+00:00</updated><id>https://yos.io/2021/09/11/real-world-contract-development-forking-mainnet</id><content type="html" xml:base="https://yos.io/2021/09/11/real-world-contract-development-forking-mainnet/">&lt;p&gt;&lt;img src=&quot;https://yos.io/assets/mainnet-fork.png&quot; alt=&quot;Real World Contract Development with Forked Mainnet&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Ethereum and other permissionless blockchains are &lt;em&gt;innovation machines&lt;/em&gt;. Developers are free to build with completely public building blocks, stitching them together to create sophisticated systems out in the open.&lt;/p&gt;

&lt;p&gt;When building a protocol of your own (DeFi, NFTs, etc), you’ll quickly realize that you need to interface with existing contracts. In a single transaction, your contracts may call several others. These contracts may include DeFi lending protocols, AMM pools, and marketplace contracts that are live on mainnet.&lt;/p&gt;

&lt;p&gt;Interfacing with other protocols is a key part of smart contract development. But how do you develop against these building blocks?&lt;/p&gt;

&lt;p&gt;Let’s hunt for an answer.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;mock-contracts&quot;&gt;Mock Contracts&lt;/h2&gt;

&lt;p&gt;A common approach to interfacing with third-party contracts at development time is with a Mock contract. Short of deploying the entire third-party protocol yourself, this seems like a low-hanging fruit. Here’s an example Mock contract you might write in place of the real thing:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-solidity&quot; data-lang=&quot;solidity&quot;&gt;&lt;span class=&quot;k&quot;&gt;contract&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MockContract&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mockValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// Mocked function
&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;greet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;view&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;returns&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;memory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mockValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// Function to change mock value for test cases
&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;setMockGreet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newMockValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;mockValue&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newMockValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;However, Mock contracts comes with some drawbacks:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;You need to spend time to rewrite existing third-party contracts as mocks. To get exhaustive mock coverage, you’ll end up rewriting whole protocols for the sake of testing.&lt;/li&gt;
  &lt;li&gt;There’s a parity risk where your mock contract’s API or behaviour may not match what’s on production. Mocks are ultimately simplified models of the real thing. As DeFi protocols continue grow in complexity, it’s simply not possible to simulate every single side effect using mocks.&lt;/li&gt;
  &lt;li&gt;As both contracts and your mocks grow in complexity, additional development effort is required to enable each mocked function to be configurable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Mock contracts are a common approach to smart contract development, but are limited in many ways. The time you spent on your mocks is time better spent on your own contracts. So how can we do better? Can we use real-world building blocks during the development phase?&lt;/p&gt;

&lt;p&gt;Let’s consider an alternative to mock contracts: &lt;strong&gt;forking mainnet.&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;forking-mainnet&quot;&gt;Forking Mainnet&lt;/h2&gt;

&lt;p&gt;Instead of writing Mock contracts, you can &lt;strong&gt;fork mainnet&lt;/strong&gt;. As its name suggests, this means running a copy of the production network locally. Forking mainnet gives you full access to a snapshot of the Mainnet network with all its building blocks, all ready for use.&lt;/p&gt;

&lt;p&gt;Forking mainnet is easy and straightforward. With Hardhat, you can connect to a mainnet fork by updating your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hardhat.config.ts&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;HardhatUserConfig&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;defaultNetwork&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;hardhat&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;networks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;hardhat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;accounts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;chainId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;31337&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;forking&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;MAINNET_RPC_URL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;mainnet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;MAINNET_RPC_URL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;accounts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;chainId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Enabling mainnet forking is as simple as adding the following lines:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;forking&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;https://eth-mainnet.alchemyapi.io/v2/&amp;lt;key&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;blockNumber&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;11095000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Here are the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;forking&lt;/code&gt; parameters:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;url&lt;/code&gt;&lt;/strong&gt;: Your RPC url should point to a node with archival data for this to work. &lt;a href=&quot;https://alchemyapi.io/&quot;&gt;Alchemy&lt;/a&gt; is a good free option. Note that you are not limited to Ethereum mainnet (you can work with a fork of Kovan or other networks.)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;blockNumber&lt;/code&gt;&lt;/strong&gt;: Pinning a block number enables caching. Every time data is fetched from mainnet, Hardhat  caches it on disk to speed up future access. You can get massive speed improvements with block pinning. &lt;em&gt;If you intend to set up automated CI tests, pinning is a must.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;Are you new to smart contracts? Check out the open source &lt;a href=&quot;https://github.com/yosriady/contracts-starter&quot;&gt;Hardhat starter kit&lt;/a&gt;! It comes with several useful tools preconfigured such as Typescript, type generation, linting, formatting, and test coverage. Just hit clone and run!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now that you have a local instance of mainnet protocols, &lt;strong&gt;setting them in a specific configuration&lt;/strong&gt; for your tests need is your likely next step. Let’s look at how to do that.&lt;/p&gt;

&lt;h2 id=&quot;impersonating-as-other-accounts&quot;&gt;Impersonating as other accounts&lt;/h2&gt;

&lt;p&gt;While connected to a forked mainnet, you can call contract functions as another account. This ‘impersonation’ feature is especially useful to prepare specific contract states for your tests. For example, you may want to act as a MakerDAO vault owner or a Uniswap liquidity provider, and operate on contracts on their behalf.&lt;/p&gt;

&lt;p&gt;Here’s an impersonation example:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;  &lt;span class=&quot;nx&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;example test case&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;impersonatedAddress&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;0x...&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Impersonate as another address&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;hre&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;network&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;provider&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;hardhat_impersonateAccount&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;impersonatedAddress&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;impersonatedSigner&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ethers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getSigner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;impersonatedAddress&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Make contract call as an impersonated address&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;MyContract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;impersonatedSigner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;doSomething&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(...);&lt;/span&gt;

    &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In the above test case:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;First, we make a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hardhat_impersonateAccount&lt;/code&gt; call with an Ethereum address to impersonate another address&lt;/li&gt;
  &lt;li&gt;This lets us make a contract call as if we were the impersonated account with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;connect(impersonatedSigner)&lt;/code&gt; on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MyContract&lt;/code&gt; contract. Impersonation lets you bypass ownership &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;msg.sender&lt;/code&gt; checks.&lt;/li&gt;
  &lt;li&gt;Contract calls made here will apply any state changes locally.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Compared to mocking contracts, &lt;strong&gt;forking mainnet comes with several advantages&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;You’re working with contracts whose APIs and behaviour are an exact match of what’s on production. There’s no parity risk.&lt;/li&gt;
  &lt;li&gt;As protocols continue to grow in complexity and composition, writing mocks for them becomes less and less feasible. Forking mainnet continues to be useful as it lets you capture all downstream side effects locally.&lt;/li&gt;
  &lt;li&gt;Forking mainnet consumes much less development time compared to writing mock contracts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s it!&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;

&lt;p&gt;Interfacing with other protocols is a key part of smart contract development. You now know how to interface with mainnet contracts at development time, in a more efficient &amp;amp; robust way without using mock contracts.&lt;/p&gt;</content><author><name>Yos Riady</name><email>hello@yos.io</email></author><category term="ethereum" /><category term="solidity" /><summary type="html">Ethereum and other permissionless blockchains are innovation machines. Developers are free to build with completely public building blocks, stitching them together to create sophisticated systems out in the open. When building a protocol of your own (DeFi, NFTs, etc), you’ll quickly realize that you need to interface with existing contracts. In a single transaction, your contracts may call several others. These contracts may include DeFi lending protocols, AMM pools, and marketplace contracts that are live on mainnet. Interfacing with other protocols is a key part of smart contract development. But how do you develop against these building blocks? Let’s hunt for an answer.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://yos.io/assets/mainnet-fork.png" /><media:content medium="image" url="https://yos.io/assets/mainnet-fork.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">How to Write Gas Efficient Contracts in Solidity</title><link href="https://yos.io/2021/05/17/gas-efficient-solidity/" rel="alternate" type="text/html" title="How to Write Gas Efficient Contracts in Solidity" /><published>2021-05-17T00:00:00+00:00</published><updated>2021-05-17T00:00:00+00:00</updated><id>https://yos.io/2021/05/17/gas-efficient-solidity</id><content type="html" xml:base="https://yos.io/2021/05/17/gas-efficient-solidity/">&lt;p&gt;&lt;img src=&quot;https://yos.io/assets/solidity-storage.png&quot; alt=&quot;How to Write Gas Efficient Contracts in Solidity&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Computations on Ethereum cost gas. If you’re not careful, you may end up writing contracts that cost more than they should. High gas costs kill usability!&lt;/p&gt;

&lt;p&gt;A common cause for high gas costs is an inefficient storage layout in Solidity contracts. In this post, let’s look at some tips you can use to help you write more gas-efficient contracts.&lt;/p&gt;

&lt;p&gt;Read on to learn more!&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;storage-layout-in-solidity&quot;&gt;Storage Layout in Solidity&lt;/h2&gt;

&lt;p&gt;When state variables of Solidity contracts are stored in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;storage&lt;/code&gt;, they are stored in a compact way such that multiple values sometimes use the same storage slot. Except for dynamically-sized arrays and mappings, data is stored contiguously as &lt;strong&gt;32-byte words&lt;/strong&gt;, item after item starting with the first state variable, which is stored in slot 0.&lt;/p&gt;

&lt;p&gt;The size of each variable is determined by its type. Here is a summary of Solidity value types and their size in bytes:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;type&lt;/th&gt;
      &lt;th&gt;bytesize&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;bool&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;bytes1&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;bytes8&lt;/td&gt;
      &lt;td&gt;8&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;bytes32&lt;/td&gt;
      &lt;td&gt;32&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;address&lt;/td&gt;
      &lt;td&gt;20&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;contract&lt;/td&gt;
      &lt;td&gt;20&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;uint8&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;uint16&lt;/td&gt;
      &lt;td&gt;2&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;uint32&lt;/td&gt;
      &lt;td&gt;4&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;uint128&lt;/td&gt;
      &lt;td&gt;16&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;uint256&lt;/td&gt;
      &lt;td&gt;32&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;int256&lt;/td&gt;
      &lt;td&gt;32&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Here’s an example of how a contract’s storage might be laid out:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://yos.io/assets/storage-layout.jpeg&quot; alt=&quot;Storage Layout&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In Example #2, multiple variables of value types may share a storage slot, within which each variable only takes up as much space as it need to.&lt;/p&gt;

&lt;p&gt;Any items with a size under 32 bytes are packed into a single storage slot if possible, according to the following rules:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Value types use only as many bytes as are necessary to store them.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;If a value type does not fit the remaining part of a storage slot, it is stored in the next storage slot.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Structs and array data always start a new slot, but their items are packed tightly according to these rules.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Items following struct or array data always start a new storage slot.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In short, optimizing storage layout in Solidity is like trying to pack items into the least number of boxes. The less boxes we need, the better.&lt;/p&gt;

&lt;h2 id=&quot;inspecting-storage-layout&quot;&gt;Inspecting Storage Layout&lt;/h2&gt;

&lt;p&gt;Before we proceed, we need a way to inspect what our contracts’ storage layout looks like.&lt;/p&gt;

&lt;p&gt;The storage layout of a contract can be viewed in the &lt;a href=&quot;https://docs.soliditylang.org/en/develop/using-the-compiler.html#output-description&quot;&gt;Standard JSON interface&lt;/a&gt; files which comes from the Solidity compiler. The output file is a JSON object containing two keys, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;storage&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;types&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;storageLayout&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;storage&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;types&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;blockquote&gt;
  &lt;p&gt;If you’re using Hardhat, you can find these files in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;artifacts/build-info/&lt;/code&gt; directory that’s generated when you run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hardhat compile&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let’s inspect these two fields more closely. We’ll inspect the storage layout of the following Solidity contract:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-solidity&quot; data-lang=&quot;solidity&quot;&gt;&lt;span class=&quot;k&quot;&gt;contract&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MyContract&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;address&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;owner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;storage&lt;/code&gt; field for the above contract is an array where each element has the following form:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span class=&quot;nl&quot;&gt;&quot;storage&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;astId&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;contract&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;contracts/MyContract.sol:MyContract&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;owner&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;offset&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;slot&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;t_address&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Each &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;storage&lt;/code&gt; element contain the following fields:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;astId&lt;/code&gt; is the id of the AST node of the state variable’s declaration&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;contract&lt;/code&gt; is the name of the contract including its path as prefix&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;label&lt;/code&gt; is the name of the state variable&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;offset&lt;/code&gt; is the offset in bytes within the storage slot according to the encoding&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;slot&lt;/code&gt; is the storage slot where the state variable resides or starts. This number may be very large and therefore its JSON value is represented as a string.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;type&lt;/code&gt; is an identifier used as key to the variable’s type information (described in the following)&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In addition to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;storage&lt;/code&gt;, the JSON file contains &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;types&lt;/code&gt;. In the following example, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;t_uint256&lt;/code&gt; represents an element in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;types&lt;/code&gt;, which has the form:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span class=&quot;nl&quot;&gt;&quot;types&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;t_address&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;encoding&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;inplace&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;address&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;numberOfBytes&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;20&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;You can inspect the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;storage&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;types&lt;/code&gt; fields to understand how much space each type consumes and how they are packed. Here’s a larger example:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span class=&quot;nl&quot;&gt;&quot;types&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;t_address&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;encoding&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;inplace&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;address&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;numberOfBytes&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;20&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;t_bool&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;encoding&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;inplace&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;bool&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;numberOfBytes&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;t_uint96&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;encoding&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;inplace&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;uint96&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;numberOfBytes&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;12&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;t_struct(MyInfo)476_storage&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;encoding&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;inplace&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;struct MyContract.MyInfo&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;members&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;astId&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;471&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;contract&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;contracts/MyContract.sol:MyContract&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;account&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;offset&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;slot&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;t_address&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;astId&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;473&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;contract&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;contracts/MyContract.sol:MyContract&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;balance&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;offset&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;slot&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;t_uint96&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;astId&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;475&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;contract&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;contracts/MyContract.sol:MyContract&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;alive&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;offset&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;slot&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;t_bool&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;numberOfBytes&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;64&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In the above file, we can see that:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;An &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;address&lt;/code&gt; takes up 20 bytes&lt;/li&gt;
  &lt;li&gt;A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;boolean&lt;/code&gt; takes up 1 byte&lt;/li&gt;
  &lt;li&gt;A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uint96&lt;/code&gt; takes up 12 bytes&lt;/li&gt;
  &lt;li&gt;A struct &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MyInfo&lt;/code&gt; occupies 64 bytes, and has 3 variables packed inside it:
    &lt;ul&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;address account&lt;/code&gt; takes up 20 bytes, in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;slot&lt;/code&gt; 0&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uint96 balance&lt;/code&gt; takes up 12 bytes, starting from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;offset&lt;/code&gt; 20 and still in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;slot&lt;/code&gt; 0&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bool alive&lt;/code&gt; takes up 1 byte in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;slot&lt;/code&gt; 1, because slot 0 is already full at 32 bytes&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;You can generate and use this report to inspect how your contracts’ storage is laid out. Try it out with some dummy contracts!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Armed with this knowledge, let’s learn some tips to optimize our Solidity contracts!&lt;/p&gt;

&lt;h2 id=&quot;tip-1-variable-packing&quot;&gt;Tip #1: Variable packing&lt;/h2&gt;

&lt;p&gt;Reading and writing from each storage slot cost gas. Packing variables lets us reduce the number of slots our contract needs.&lt;/p&gt;

&lt;p&gt;To allow the EVM to optimize your storage layout, make sure to order your storage variables and struct members such that they can be packed tightly. For example, instead of declaring your storage variables in the order of:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;// First approach

uint128, // 16 -&amp;gt; slot 0 16/32
uint256, // 32 -&amp;gt; slot 1 32/32 (doesn't fit slot 0)
uint128 // 16 -&amp;gt; slot 2 16/32&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;you can do:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;// Second approach

uint128, // 16 -&amp;gt; slot 0 16/32
uint128, // 16 -&amp;gt; slot 0 32/32 (fits slot 0)
uint256 // 32 -&amp;gt; slot 1 16/32&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The first approach results in no variable packing. It takes up three storage slots.&lt;/p&gt;

&lt;p&gt;In comparison, the second approach benefits from variable packing and takes only two slots.&lt;/p&gt;

&lt;p&gt;Here’s another variable packing example:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://yos.io/assets/storage-layout-before.jpeg&quot; alt=&quot;Storage Layout Before&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://yos.io/assets/storage-layout-after.jpeg&quot; alt=&quot;Storage Layout After&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In short, group Solidity variables into chunks of 32-byte words to optimize gas usage.&lt;/p&gt;

&lt;h2 id=&quot;tip-2-uint256-can-be-cheaper-than-uint8&quot;&gt;Tip #2: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uint256&lt;/code&gt; can be cheaper than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uint8&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;When using types that are smaller than 32 bytes such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uint8&lt;/code&gt;, your contract’s gas usage may in some cases be higher than if you use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uint256&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is because the EVM operates on 32 bytes at a time. The EVM will still occupy 256 bits, fill 8 bits with the uint variable and fill the extra bites with zeros. Therefore, if the element is smaller than that, the EVM has to do more operations to convert the element between 32 bytes and the desired size.&lt;/p&gt;

&lt;p&gt;It might be beneficial to use smaller-size types if you can get the compiler to pack multiple types into one storage slot (see the previous section on Variable packing), and thus, combine multiple reads or writes into a single operation.&lt;/p&gt;

&lt;p&gt;However, if you are not reading or writing all the values at the same time, this can have the opposite effect. When defining a lone variable, it can be more optimal to use a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uint256&lt;/code&gt; rather than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uint8&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;tip-3-use-bytesn-instead-of-bytes&quot;&gt;Tip #3: Use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytesN&lt;/code&gt; instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytes[]&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;The value types &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytes1&lt;/code&gt; … &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytes32&lt;/code&gt; hold a sequence of bytes from one to up to 32. You should use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytes&lt;/code&gt; over &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytes1[]&lt;/code&gt; because it is &lt;a href=&quot;http://solidity.readthedocs.io/en/latest/types.html#fixed-size-byte-arrays&quot;&gt;cheaper&lt;/a&gt;, since &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytes1[]&lt;/code&gt; adds 31 padding bytes between the elements. Due to padding rules, this wastes 31 bytes of space for each element.&lt;/p&gt;

&lt;p&gt;If you can limit the length to a certain number of bytes, always use one of the value types &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytesN&lt;/code&gt; because they are more gas efficient.&lt;/p&gt;

&lt;h2 id=&quot;tip-4-use-fixed-size-bytes32-instead-of-string--bytes&quot;&gt;Tip #4: Use fixed-size &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytes32&lt;/code&gt; instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;string&lt;/code&gt; / &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytes&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;Fitting your data in fixed-size 32 byte words is much cheaper than using arbitrary-length types. Remember that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytes32&lt;/code&gt; uses less gas because it fits in a single EVM word. Basically, Any fixed size variable in solidity is cheaper than dynamically sized ones.&lt;/p&gt;

&lt;h2 id=&quot;tip-5-write-to-storage-last&quot;&gt;Tip #5: Write to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;storage&lt;/code&gt; last&lt;/h2&gt;

&lt;p&gt;Only update &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;storage&lt;/code&gt; variables with the final results of your computation, after all intermediate calculations instead of at each step. This is because operations on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;storage&lt;/code&gt; is more expensive than operations on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;memory&lt;/code&gt; / &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;calldata&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let’s look an example contract:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-solidity&quot; data-lang=&quot;solidity&quot;&gt;&lt;span class=&quot;k&quot;&gt;pragma&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;solidity&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;contract&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Test&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;uint&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;internal&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Writes to storage at every intermediate step
&lt;/span&gt;      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;kt&quot;&gt;uint&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Writes only the final result to storage
&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In the sample code above, function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;B()&lt;/code&gt; is more gas-efficient than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A()&lt;/code&gt; because it does less storage writes. Use local variables to store your intermediate results, and write to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;storage&lt;/code&gt; last.&lt;/p&gt;

&lt;p&gt;Here is a cost comparison:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSTORE&lt;/code&gt; (saving a 32-byte word to storage): 22100 gas when storage value is set to non-zero from zero, OR 5000 gas when the storage value’s zeroness remains unchanged or is set to zero. &lt;a href=&quot;https://hackmd.io/@fvictorio/gas-costs-after-berlin#SSTORE-after-Berlin&quot;&gt;This assumes first-time access.&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SLOAD&lt;/code&gt; (loading a word from storage): 2100 gas on first-time access, 100 gas if already accessed&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MSTORE&lt;/code&gt; (saving a word to memory): 3 gas&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MLOAD&lt;/code&gt; (loading a word from memory): 3 gas&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you can see, the difference is potentially massive. Minimize writes to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;storage&lt;/code&gt; and do them last. Note that are numbers are post-Berlin upgrade numbers (EIP 2929.)&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;You might also notice that ‘cold’ reads on the EVM are more expensive than ‘warm’ reads. This is yet another reason for miniziming the number of storage slots and variable packing (Tip #1.)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;tip-6-free-up-unused-storage&quot;&gt;Tip #6: Free up unused storage&lt;/h2&gt;

&lt;p&gt;You get a gas refund when you ‘empty out’ variables. Deleting has the same effect as reassigning the value type with the default value, such as the zero address for addresses and 0 for integers.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-solidity&quot; data-lang=&quot;solidity&quot;&gt;&lt;span class=&quot;kt&quot;&gt;uint&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;internal&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;delete&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;//&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Clears&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uint&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Deleting a variable refunds 15,000 gas up to a maximum of half the gas cost of the transaction.&lt;/p&gt;

&lt;h2 id=&quot;tip-7-use-constant-and-immutable-keywords&quot;&gt;Tip #7: Use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;constant&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;immutable&lt;/code&gt; keywords&lt;/h2&gt;

&lt;p&gt;Add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;constant&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;immutable&lt;/code&gt; type annotations to variables:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-solidity&quot; data-lang=&quot;solidity&quot;&gt;&lt;span class=&quot;k&quot;&gt;contract&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;C&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;bytes32&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;constant&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MY_HASH&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;keccak256&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;abc&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;address&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;immutable&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;owner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;owner&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sender&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Reading constant and immutable variables is no longer considered a storage read (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSTORE&lt;/code&gt;) because it uses &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EXTCODE*&lt;/code&gt; opcodes instead which is much cheaper.&lt;/p&gt;

&lt;h2 id=&quot;tip-8-cache-storage-values-in-memory&quot;&gt;Tip #8: Cache storage values in memory&lt;/h2&gt;

&lt;p&gt;Anytime you are reading from storage more than once, it is cheaper to cache variables in memory. An SLOAD cost 100 GAS while MLOAD and MSTORE only cost 3 GAS.&lt;/p&gt;

&lt;p&gt;This is especially true in for loops when using the length of a storage array as the condition being checked after each loop. Caching the array length in memory can yield significant gas savings when the array length is high.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-solidity&quot; data-lang=&quot;solidity&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// Before
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;approvals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// approvals is a storage variable
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// After
&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;memory&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;numApprovals&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;approvals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;numApprovals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;tip-9-cache-external-values-in-memory&quot;&gt;Tip #9: Cache external values in memory&lt;/h2&gt;

&lt;p&gt;When making repeated external calls when the values between calls do not change, cache the values:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-solidity&quot; data-lang=&quot;solidity&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// Before
&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;core&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;controller&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hasRole&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;core&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;controller&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MANAGER_ROLE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sender&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// After
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IController&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;memory&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;controller&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;core&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;controller&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;controller&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hasRole&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;controller&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MANAGER_ROLE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sender&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;tip-10--0-is-more-expensive-than--0-for-unsigned-integers&quot;&gt;Tip #10: &amp;gt; 0 is more expensive than != 0 for unsigned integers&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;!= 0&lt;/code&gt; costs 6 less GAS compared to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;gt; 0&lt;/code&gt; for unsigned integers in require statements with the optimizer enabled. &lt;a href=&quot;https://twitter.com/gzeon/status/1485428085885640706&quot;&gt;Learn more.&lt;/a&gt;&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-solidity&quot; data-lang=&quot;solidity&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// Before
&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// After
&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;tip-11-splitting-require-statements-that-use--saves-gas&quot;&gt;Tip #11: Splitting require() statements that use &amp;amp;&amp;amp; saves gas&lt;/h2&gt;

&lt;p&gt;Instead of using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;amp;&amp;amp;&lt;/code&gt; operator in a single require statement to check multiple conditions,using multiple require statements with 1 condition per require statement will save 3 GAS per &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;amp;&amp;amp;&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-solidity&quot; data-lang=&quot;solidity&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// Before
&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MIN_64x64&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MAX_64x64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// After
&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MIN_64x64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MAX_64x64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;tip-12-i-costs-less-gas-compared-to-i-or-i--1&quot;&gt;Tip #12: ++i costs less gas compared to i++ or i += 1&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;++i&lt;/code&gt; costs less gas compared to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i++&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i += 1&lt;/code&gt; for unsigned integers. This is because the pre-increment operation is cheaper (about 5 GAS per iteration).&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i++&lt;/code&gt; increments &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i&lt;/code&gt; and returns the initial value of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i&lt;/code&gt;. This means:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-solidity&quot; data-lang=&quot;solidity&quot;&gt;&lt;span class=&quot;kt&quot;&gt;uint&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;//&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;but&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In the first example, the compiler has to create a temporary variable (when used) for returning 1 instead of 2.&lt;/p&gt;

&lt;p&gt;In contrast, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;++i&lt;/code&gt; returns the actual incremented value:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-solidity&quot; data-lang=&quot;solidity&quot;&gt;&lt;span class=&quot;kt&quot;&gt;uint&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;//&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;too&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;so&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;no&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;need&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;temporary&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;variable&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This tip is applicable for loops as well.&lt;/p&gt;

&lt;h2 id=&quot;tip-13-shorten-require-messages-to-less-than-32-characters&quot;&gt;Tip #13: Shorten require messages to less than 32 characters&lt;/h2&gt;

&lt;p&gt;Strings that are more than 32 characters will require more than 1 storage slot, costing more gas. Consider reducing the message length to less than 32 characters or use error codes:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-solidity&quot; data-lang=&quot;solidity&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// Before
&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;This require statement message exceeds thirty two characters.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// After
&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;A201&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;tip-14-use-custom-errors-instead-of-revert-strings-to-save-gas&quot;&gt;Tip #14: Use Custom Errors instead of Revert Strings to save Gas&lt;/h2&gt;

&lt;p&gt;Consider replacing revert strings with custom errors. &lt;a href=&quot;https://blog.soliditylang.org/2021/04/21/custom-errors/&quot;&gt;Custom errors&lt;/a&gt; from Solidity 0.8.4 are cheaper than revert strings (cheaper deployment cost and runtime cost when the revert condition is met.)&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-solidity&quot; data-lang=&quot;solidity&quot;&gt;&lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;withdraw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sender&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;owner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;revert&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Unauthorized&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;owner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;transfer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;balance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;blockquote&gt;
  &lt;p&gt;Starting from Solidity v0.8.4, there is a convenient and gas-efficient way to explain to users why an operation failed through the use of custom errors. Until now, you could already use strings to give more information about failures (e.g., revert(“Insufficient funds.”);), but they are rather expensive, especially when it comes to deploy cost, and it is difficult to use dynamic information in them.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;tip-15-usage-of-uint8-may-increase-gas-cost&quot;&gt;Tip #15: Usage of uint8 may increase gas cost&lt;/h2&gt;

&lt;p&gt;When using elements that are smaller than 32 bytes, your contract’s gas usage may be higher. This is because the EVM operates on 32 bytes at a time. Therefore, if the element is smaller than that, the EVM must use more operations in order to reduce the size of the element from 32 bytes to the desired size. The EVM needs to properly enforce the limits of this smaller type.&lt;/p&gt;

&lt;p&gt;It is only beneficial to use reduced-size arguments if you are dealing with storage values because the compiler will pack multiple elements into one storage slot, and thus, combine multiple reads or writes into a single operation. When dealing with function arguments or memory values, there is no inherent benefit because the compiler does not pack these values.&lt;/p&gt;

&lt;p&gt;Using smaller-size uints such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uint8&lt;/code&gt; is only more efficient when you can pack variables into the same storage slot, such as in structs. In other cases and in loops, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uint256&lt;/code&gt; is more gas efficient than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uint8&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;tip-16-non-strict-inequalities-are-cheaper-than-strict-ones&quot;&gt;Tip #16: Non-strict inequalities are cheaper than strict ones&lt;/h2&gt;

&lt;p&gt;In the EVM, there is no opcode for non-strict inequalities (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;gt;=&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;=&lt;/code&gt;) and two operations are performed (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;gt;&lt;/code&gt; + &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;=&lt;/code&gt;.) Consider replacing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;gt;=&lt;/code&gt; with the strict counterpart &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;gt;&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-solidity&quot; data-lang=&quot;solidity&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// Before
&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// After
&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;tip-17-use-external-instead-of-public-where-possible&quot;&gt;Tip #17: Use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;external&lt;/code&gt; instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;public&lt;/code&gt; where possible&lt;/h2&gt;

&lt;p&gt;Functions with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;public&lt;/code&gt; visibility modifier are costlier than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;external&lt;/code&gt;. Default to using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;external&lt;/code&gt; modifier until you need to expose it to other functions within your contract.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-solidity&quot; data-lang=&quot;solidity&quot;&gt;&lt;span class=&quot;k&quot;&gt;contract&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Test&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Hello World&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Execution cost: 24527
&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;view&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;returns&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;memory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
         &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;//Execution cost: 24505
&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;external&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;view&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;returns&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;memory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
         &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;tip-18-internal-functions-are-cheaper-than-public&quot;&gt;Tip #18: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;internal&lt;/code&gt; functions are cheaper than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;public&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;If a function is only callable by other functions internally, specify it as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;internal&lt;/code&gt;. Internal functions are cheaper to call than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;public&lt;/code&gt; functions.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-solidity&quot; data-lang=&quot;solidity&quot;&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{...}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;internal&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{...}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;tip-19-enable-the-solidity-gas-optimizer&quot;&gt;Tip #19: Enable the Solidity Gas Optimizer&lt;/h2&gt;

&lt;p&gt;Set the Solidity optimizer &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;runs&lt;/code&gt; value to a low number to optimize for contract deployment costs. Alternatively, set the optimizer to a high number to optimize for run-time gas costs when functions are called on a contract.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;nx&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;solidity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;0.8.16&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;settings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;optimizer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;enabled&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;runs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;tip-20-skip-initializing-default-values&quot;&gt;Tip #20: Skip initializing default values&lt;/h2&gt;

&lt;p&gt;When Solidity variables are not set, they refer to a set of default values:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;address&lt;/code&gt; = &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;address(0)&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uint256&lt;/code&gt; = &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bool&lt;/code&gt; = &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;false&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Gas is spent when you unecessarily initialize variables to its default value:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-solidity&quot; data-lang=&quot;solidity&quot;&gt;&lt;span class=&quot;kt&quot;&gt;uint256&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// bad
&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint256&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;//&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;better&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;tip-21-short-circuit-expensive-operations&quot;&gt;Tip #21: Short circuit expensive operations&lt;/h2&gt;

&lt;p&gt;Short-circuiting works by ordering the lower-cost operation first so that the higher-cost operation is skipped if the first operation evaluates to true. For example:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-solidity&quot; data-lang=&quot;solidity&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// f(x) is low cost
// g(y) is expensive
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Ordering should go as follows
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;

&lt;p&gt;In this post, we learned:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;How storage is laid out in Solidity contracts&lt;/li&gt;
  &lt;li&gt;How to inspect the storage layout of your contracts&lt;/li&gt;
  &lt;li&gt;Patterns and techniques to optimize the gas usage of your contracts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Keep in mind that storage optimization techniques can run counter to code readability. When in doubt, be sure to aim for a balance between efficiency and readability.&lt;/p&gt;</content><author><name>Yos Riady</name><email>hello@yos.io</email></author><category term="ethereum" /><category term="solidity" /><summary type="html">Computations on Ethereum cost gas. If you’re not careful, you may end up writing contracts that cost more than they should. High gas costs kill usability! A common cause for high gas costs is an inefficient storage layout in Solidity contracts. In this post, let’s look at some tips you can use to help you write more gas-efficient contracts. Read on to learn more!</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://yos.io/assets/solidity-storage.png" /><media:content medium="image" url="https://yos.io/assets/solidity-storage.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Recently</title><link href="https://yos.io/2020/07/31/recently/" rel="alternate" type="text/html" title="Recently" /><published>2020-07-31T00:00:00+00:00</published><updated>2020-07-31T00:00:00+00:00</updated><id>https://yos.io/2020/07/31/recently</id><content type="html" xml:base="https://yos.io/2020/07/31/recently/">&lt;p&gt;&lt;img src=&quot;https://yos.io/assets/recently.png&quot; alt=&quot;Recently&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Recently&lt;/em&gt; is a periodic retrospective.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;table-of-contents&quot;&gt;Table of Contents&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;#reading&quot;&gt;Reading&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#listening&quot;&gt;Listening&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;reading&quot;&gt;Reading&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.collaborativefund.com/blog/useful-hacks/&quot;&gt;Useful hacks&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.collaborativefund.com/blog/100-little-ideas/&quot;&gt;100 little ideas&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.nfx.com/post/hidden-patterns-great-startup-ideas/&quot;&gt;Hidden patterns in great startup ideas&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.nfx.com/post/9-habits-world-class-startups/&quot;&gt;9 habits of world class startups&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.nfx.com/post/10-places-to-find-product-market-fit/&quot;&gt;10 places to find product market fit&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://overreacted.io/preparing-for-tech-talk-part-1-motivation/&quot;&gt;Preparing for tech talks&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://blog.circle.com/2020/03/10/programmable-dollars-for-your-internet-business/&quot;&gt;Programmable dollars for your internet business&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://medium.com/ethereum-cat-herders/how-can-we-onboard-newcomers-to-ethereum-better-6794a3314337&quot;&gt;How can we onboard newcomers to Ethereum better&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://blog.gnosis.pm/breaking-down-ethereum-wallets-options-2162b41477d7&quot;&gt;Breaking down ethereum wallet options&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://matthewstrom.com/writing/optimize-for-learning/&quot;&gt;Optimize for learning&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://blog.pragmaticengineer.com/scaling-engineering-teams-via-writing-things-down-rfcs/&quot;&gt;Scaling engineering teams via writing things down&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://blog.pragmaticengineer.com/the-product-minded-engineer/&quot;&gt;The Product-Minded Software Engineer&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://blog.pragmaticengineer.com/on-writing-well/&quot;&gt;Undervalued Software Engineering Skills: Writing Well&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://cdixon.org/2010/01/03/the-next-big-thing-will-start-out-looking-like-a-toy&quot;&gt;The next big thing will start out looking like a toy&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://lindajxie.com/2019/09/25/interoperability-and-composability-within-ethereum/&quot;&gt;Interoperability and composability within Ethereum&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://medium.com/bollinger-investment-group/constant-function-market-makers-defis-zero-to-one-innovation-968f77022159&quot;&gt;Constant Function Market Makers: DeFi’s “Zero to One” Innovation&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.etherean.org/blockchain/community/governance/2020/03/04/autonocrats-anthropocrats.html&quot;&gt;Autonocrats and Anthropocrats&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://medium.com/@mariolaul/on-autonomous-software-21b9608049d0&quot;&gt;On autonomous software&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://medium.com/@daniel.heller/ten-principles-for-growth-69015e08c35b&quot;&gt;Ten principles for growth&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.kitchensoap.com/2012/10/25/on-being-a-senior-engineer/&quot;&gt;On being a senior engineer&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://blog.newrelic.com/culture/successful-software-developers-habits/&quot;&gt;Successful software developers habits&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://blog.chain.link/challenges-in-defi-how-to-bring-more-capital-and-less-risk-to-automated-market-maker-dexs/&quot;&gt;How to Bring More Capital and Less Risk to Automated Market Maker DEXs&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.swyx.io/writing/marketing-yourself/&quot;&gt;Marketing yourself&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://avc.com/2020/01/what-to-work-on/&quot;&gt;What to work on&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://codewithoutrules.com/2017/12/07/asking-for-help/&quot;&gt;Asking for help&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://variant.fund/the-ownership-economy-crypto-and-consumer-software/&quot;&gt;The ownership economy&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://store.steampowered.com/points/howitworks&quot;&gt;Steam introduces community points&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://medium.com/dragonfly-research/what-explains-the-rise-of-amms-7d008af1c399&quot;&gt;What explains the rise of AMMs?&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://bankless.substack.com/p/the-token-maximalist-thesis&quot;&gt;The Token Maximalist Thesis&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://medium.com/dragonfly-research/request-for-crypto-startups-ea6a520cac48&quot;&gt;Request for crypto startups&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;highlights&quot;&gt;Highlights&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Curse of Knowledge:&lt;/strong&gt; The inability to communicate your ideas because you wron gly assume others have the necessary background to understand what you’re talking about.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Base-Rate Neglect:&lt;/strong&gt; Assuming the success rate of everyone who’s done what you’re about to try doesn’t apply to you, caused by overestimating the extent to which you do things differently than everyone else.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hard-Easy Effect:&lt;/strong&gt; Hard tasks promote overconfidence because the rewards are high and fun to dream about; easy tasks promote underconfidence because they’re boring and easy to put off.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hedonic Treadmill:&lt;/strong&gt; Expectations rise with results, so nothing feels as good as you’d imagine for as long as you’d expect.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Positive Illusions:&lt;/strong&gt; Excessively rosy views about the decisions you’ve made to maintain self-esteem in a world where everyone makes bad decisions all the time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ostrich Effect:&lt;/strong&gt; Avoiding negative information that might challenge views that you desperately want to be right.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fluency Heuristic:&lt;/strong&gt; Ideas that can be explained simply are more likely to be believed than those that are complex, even if the simple-sounding ideas are nonsense. It occurs because ideas that are easy to grasp are hard to distinguish from ideas you’re familiar with.&lt;/p&gt;

&lt;p&gt;The only true authority stems from knowledge, not from position. Knowledge engenders authority, and authority engenders respect – so if you want respect in an egoless environment, cultivate knowledge.&lt;/p&gt;

&lt;p&gt;Don’t be “the coder in the corner.” Don’t be the person in the dark office emerging only for soda. The coder in the corner is out of sight, out of touch, and out of control. This person has no voice in an open, collaborative environment. Get involved in conversations, and be a participant in your office community.&lt;/p&gt;

&lt;p&gt;Fight for what you believe, but gracefully accept defeat. Understand that sometimes your ideas will be overruled. Even if you are right, don’t take revenge or say “I told you so.” Never make your dearly departed idea a martyr or rallying cry.&lt;/p&gt;

&lt;p&gt;Follow the principles of extreme ownership.&lt;/p&gt;

&lt;p&gt;You need to face the consequences of your mistakes and learn from your mistakes. If you don’t make mistakes, you won’t learn anything, and you won’t grow up&lt;/p&gt;

&lt;p&gt;Novelty is a risk. Too much of it, and you’re almost certain to fail. But too little of it and you’re just a redundant copy of someone else — which is also a recipe for failure.&lt;/p&gt;

&lt;p&gt;Be curious. Read widely. Try new things. What people call intelligence just boils down to curiosity.&lt;/p&gt;

&lt;p&gt;We should all work on projects that interest us, where we have insights that others don’t have, and that motivate and inspire us and others.&lt;/p&gt;

&lt;p&gt;You must &lt;a href=&quot;https://avc.com/2020/01/what-to-work-on/&quot;&gt;work on&lt;/a&gt; something that inspires you and others, you must work on something with a significant impact, and you must do it in a way that makes getting where you want to go as easy as possible and keeps you there as long as possible.&lt;/p&gt;

&lt;p&gt;If you can teach yourself how to solve problems, you have a bright career ahead of yourself. No matter where you live, you will find problems galore in need of solving. Those who would benefit from solutions of their problems will pay you handsomely to solve them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Take initiative:&lt;/strong&gt; The most common misconception in software is that there are grown-ups out there who are on top of things. Own your team’s and company’s mission. Don’t wait to be told; think about what needs doing and do it or advocate for it. Managers depend on the creativity and intelligence of their engineers, not figuring it all out themselves.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Unblock yourself:&lt;/strong&gt; Learn to never, ever accept being blocked; find a way by persuasion, escalation, or technical creativity. Again, your job isn’t just to write the code and wait for everything else to fall into place; your job is to figure out how to create value with your efforts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Own your project management:&lt;/strong&gt; Understand the dependency graph for your project, ensure key pieces have owners, write good summaries of plans and status, and proactively inform stakeholders of plans and progress. Practice running meetings! All this enables you to take on much bigger projects and is great preparation for leadership.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Own your education:&lt;/strong&gt; Pursue mastery of your craft. Your career should be a journey of constant growth, but no one else will ensure that you grow. Find a way to make learning part of your daily life (even 5 minutes/day); get on mailing lists, find papers and books that are worth reading, and read the manual cover to cover for technologies you work with. Consistency is key; build habits that will keep you growing throughout your career.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Communicate proactively:&lt;/strong&gt; Regular, well-organized communication builds confidence and goodwill in collaborators; knowledge-sharing creates an atmosphere of learning and camaraderie. Shar  e knowledge and set a regular cadence of informing stakeholders on project goals, progress, and obstacles. Give talks and speak up judiciously in meetings.&lt;/p&gt;

&lt;p&gt;The key observation is that while your technical programming ability may plateau, the impact of your technical contributions doesn’t have to. Your ability to decide where to spend your efforts to maximize your impact — what code to write, what software to build, and which business problems to tackle — is unbounded. It’s this ability that distinguishes the most valuable and effective engineers from everyone else.&lt;/p&gt;

&lt;p&gt;What makes for a world-class software engineer is the ability to consistently deliver business value. Effectively communicate with the non-technical stakeholders and be the bridge between technology and business goals. Make sure they’re aware of pros and cons of every development related decision.&lt;/p&gt;

&lt;p&gt;You identify and solve problems that are core to the business, or you enable those around you to more effectively solve those core business problems. It’s in this alignment of your technical efforts with business value that your career grows.&lt;/p&gt;

&lt;h2 id=&quot;listening&quot;&gt;Listening&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=W3nx5PuVa0Y&quot;&gt;ACCA OST&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=SzSBaYubCqE&quot;&gt;Promare OST&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=1-FQwsdXtsg&quot;&gt;No Straight Roads&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=Gcfm1PGX_gg&quot;&gt;Hylics 2 OST&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><author><name>Yos Riady</name><email>hello@yos.io</email></author><category term="thoughts" /><summary type="html">Recently is a periodic retrospective.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://yos.io/assets/recently.png" /><media:content medium="image" url="https://yos.io/assets/recently.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>