<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Leonardo Teixeira Menezes</title>
    <description>The latest articles on Forem by Leonardo Teixeira Menezes (@ltmenezes).</description>
    <link>https://forem.com/ltmenezes</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F675844%2F93109e1f-2679-4cdc-a629-7a79206d7918.jpg</url>
      <title>Forem: Leonardo Teixeira Menezes</title>
      <link>https://forem.com/ltmenezes</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/ltmenezes"/>
    <language>en</language>
    <item>
      <title>The Rise of Flash Startups</title>
      <dc:creator>Leonardo Teixeira Menezes</dc:creator>
      <pubDate>Tue, 19 Mar 2024 15:59:19 +0000</pubDate>
      <link>https://forem.com/ltmenezes/the-rise-of-flash-startups-3j3k</link>
      <guid>https://forem.com/ltmenezes/the-rise-of-flash-startups-3j3k</guid>
      <description>&lt;p&gt;In the past businesses took pride in how long they lasted, from your local bakery to big corporations they all boasted about it, the idea behind it was simple, if a business was run well enough it should stand the test of time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm2rh228t4ihou7m7wjsc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm2rh228t4ihou7m7wjsc.png" alt="Image of a local bakery that has been running for over a hundred years." width="550" height="413"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We were living in simpler times in a slow-moving world, where technical innovations were rare to come by and demand was not changing as fast as it is today. Steady, slow-changing demand from consumers breeds companies that spend decades, if not centuries mastering their craft, optimizing and perfecting each stage of its processes and details in its products. Back then, the expectation was that after a life’s worth of work, you could pass your company on to your kids and family, creating a long-lasting traditional business. However, this time is coming close to an end.&lt;/p&gt;

&lt;p&gt;We are now living in a world where businesses and consumers are moving at a never-before-seen speed, this is due to two main factors: &lt;strong&gt;digital economy and AI.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The digital economy is fast-moving by its nature, it’s built on top of ever-changing software and products. Trends come and go in a matter of weeks. A product that might attract millions in a month might be irrelevant in the very next month.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7vowqeg0ftmuib4dh63r.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7vowqeg0ftmuib4dh63r.jpg" alt="Image of two articles side by side, one headline talks about the growth of Clubhouse, and the other one about its decline." width="800" height="149"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An example of this was a Clubhouse, these two articles are less than 4 months apart and that was back in 2021. Clubhouse for those unfamiliar with it was one of the biggest social media apps in the world for a couple of months, attracting millions of users, celebrities, and politicians to have public conversations. It was so dominant back then that other apps tried copying it as fast as possible, one of the most popular copycats was Twitter, which launched ‘Twitter Spaces’ that had very similar features. Now, all of this area is practically gone, there’s simply no more demand for public audio chats anymore apart from very niche use cases.&lt;/p&gt;

&lt;p&gt;The second biggest factor is AI. With the current boom of AI products, there was never an easier time to build new products. From the marketing material to the source code, you can use AI to speed up the process. There are AI apps to build marketing videos from words, to create a logo in seconds, and to build and design prototypes. This makes it easier than ever to start a small company and there was never a better time to market these products on the internet.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F167zobwj02yculbjfryi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F167zobwj02yculbjfryi.png" alt="Image from a custom GPT that generates ad videos." width="774" height="1005"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Given all of this, can we really say that companies like Clubhouse failed? This notion of success comes from an outdated perspective of what a successful company is. We can’t expect tech companies going ahead to adhere to old metrics of success, such as ‘standing the test of time’. &lt;strong&gt;The future of the vast majority of tech products will be to exist for a short period of time, to supply a specific temporary demand, make a profit, and vanish when they are no longer needed.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I call this type of company a &lt;strong&gt;Flash Startup.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The term comes from Flashmobs for which the dictionary definition is: &lt;strong&gt;“a group of people who arrange, by email or mobile phone, to come together in a place at the same time, do something funny or silly, and then leave”.&lt;/strong&gt; This is close to a perfect explanation for what the future of startups is becoming. The default expectation should not be to build a long-lasting company anymore. Flash Startups should be okay with sunsetting when they are no longer needed. The success comes from effectively handling a temporary demand and disbanding before wasting all its profits chasing a non-existent mirage of a long-lasting prospect.&lt;/p&gt;

&lt;p&gt;A good example of how a Flash Startup should operate is PhotoAI.com. Back in 2022, there was a huge demand for AI-generated photos of oneself, a kind of a photoshoot for yourself but instead of going to a studio, you would get it generated by AI. PhotoAI.com was created by &lt;a class="mentioned-user" href="https://dev.to/levelsio"&gt;@levelsio&lt;/a&gt; and it was one of the biggest apps on this trend, it made him a small fortune in the process. Less than a year later, the demand for it had already fizzled out:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6rlfyak8hk9ub0f6pyzo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6rlfyak8hk9ub0f6pyzo.png" alt="Graph showing the surge in demand for AI photoshoots and it's steep decline." width="800" height="602"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;PhotoAI will probably not exist in the future and that is okay, it was still a successful business. After all, Flash Startups are not meant to last forever. They are meant to solve a specific temporary demand and make a profit while doing so, which they did.&lt;/p&gt;

&lt;p&gt;To build the future we need to get rid of outdated expectations of what a company should be and how they should operate. Next time that you are working on a project or investing in a company &lt;strong&gt;reflect on what’s your own definition of success for it&lt;/strong&gt;, you might very well find out that you are building the next Flash Startup.&lt;/p&gt;




&lt;p&gt;If you liked reading this article consider following me on Dev.to, &lt;a href="https://twitter.com/ltmenezes"&gt;on Twitter&lt;/a&gt;, or &lt;a href="https://ltmenezes.dev/"&gt;subscribe to my personal website&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>webdev</category>
      <category>startup</category>
    </item>
    <item>
      <title>ActivityPub, Fediverse and the Future of social networks</title>
      <dc:creator>Leonardo Teixeira Menezes</dc:creator>
      <pubDate>Thu, 20 Jul 2023 20:20:12 +0000</pubDate>
      <link>https://forem.com/ltmenezes/activitypub-fediverse-and-the-future-of-social-networks-4dbd</link>
      <guid>https://forem.com/ltmenezes/activitypub-fediverse-and-the-future-of-social-networks-4dbd</guid>
      <description>&lt;p&gt;With the recent growth of Mastodon and Threads, you might have heard about ActivityPub, a relatively new networking protocol that has gathered momentum and is on its way to change how social networks work on the web. This article will give you an introduction to ActivityPub, how it’s used on the Fediverse, and some insights into how it might grow on the internet going ahead.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Crash Course into ActivityPub
&lt;/h2&gt;

&lt;p&gt;The ActivityPub protocol is a decentralized social networking protocol, it defines how applications can represent and communicate classic social network interactions such as ‘Posting a Photo’ or ‘Following a person’, creating a standard with which decentralized social network servers and clients can communicate. ActivityPub is a real-time pub/sub protocol, based on HTTP and JSON.&lt;/p&gt;

&lt;p&gt;Let’s start by breaking down an ActivityPub request with one example request, this is a request from UserA to follow UserB on a social network:&lt;/p&gt;

&lt;p&gt;HTTP POST Request&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "@context" : "https://www.w3.org/ns/activitystreams",
  "id":"https://my-example.com/my-first-follow",
  "type" : "Follow",
  "actor" : "https://mastodon.social/users/UserA",
  "object" : "https://mastodon.social/users/UserB"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first glance, you might notice how intuitive it is, we are making a request of type ‘Follow’ performed by the actor ‘UserA’ to the object ‘UserB. There are three sets of types in ActivityPub:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Activities: They describe actions that can happen on the social network.&lt;/li&gt;
&lt;li&gt;Actors: Describe entities that can perform activities.&lt;/li&gt;
&lt;li&gt;Objects: Describes an object of any kind.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With these three sets, we can describe classic social network interactions, such as posting an image, following someone, or checking in on an event. The value that ActivityPub creates is by defining a standard to communicate these interactions across federated social networks, creating the possibility, for example, for a user on a social network to follow and interact with someone on a different network.&lt;/p&gt;

&lt;p&gt;In order to enable federated social network interactions ActivityPub created the definition of an actor Inbox and Outbox, these are a collection of every action published by the actors that are ready to be requested by other social networks (Outbox) and a collection in which an actor receives actions performed by other actors (Inbox).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy9xnagkmrnfzsbt4y8mh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy9xnagkmrnfzsbt4y8mh.png" alt="Image illustrating other social network instances requesting an actor Inbox and Outbox" width="720" height="363"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In practical terms, your “Inbox” will be an endpoint in which other actors can do POST requests to inform you of new activities, and your “Outbox” will be requested using GET requests by actors to update themselves on the latest activities you created.&lt;/p&gt;

&lt;p&gt;Your Inbox and Outbox exist on your ‘Home Server’, we are going to explore the concept of a ‘Home server’ later but for now think of it as the server that is hosting your social network account, this server is going to be responsible for the underlying infrastructure of your social network, for receiving new activities posted on your Inbox and for making your Outbox available for other networks to fetch.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Fediverse
&lt;/h2&gt;

&lt;p&gt;‘Fediverse’ is a combination of the words “Federated” and “Universe”, it’s also a term that was invented to describe a group of federated social networks that interact with each other using protocols such as the ActivityPub. It started out with a single social network in 2008 and now has more than thousands of live instances with millions of active users. Since the release of ActivityPub in 2018 most of these servers already added support for it and it’s now the most prominent protocol for this server-to-server communication. &lt;/p&gt;

&lt;p&gt;In order to join the Fediverse as a user you need to either create your own server to host your account or to choose an existing instance to be your ‘Home server’. Your home server will be responsible for all your account infrastructure on the Fediverse, it will host your Inbox and Outbox and will be the source of truth for your account information.&lt;/p&gt;

&lt;p&gt;Adding support for ActivityPub and joining the Fediverse means that a social network can leverage the existing user base of the Fediverse to create content for its own users and to increase the reach of users on its network.&lt;/p&gt;

&lt;p&gt;One of the biggest drivers behind the growth of the Fediverse is the &lt;a href="https://github.com/mastodon/mastodon"&gt;open-source project Mastodon&lt;/a&gt;. Mastodon is an open-source social network server based on ActivityPub that you can use to host your own social network, it’s also the backend for some of the biggest Fediverse projects that are currently live, such as the Mastodon Social (1M+ users) and Truth Social (2M+ users).&lt;/p&gt;

&lt;h2&gt;
  
  
  Why would users care about the Fediverse?
&lt;/h2&gt;

&lt;p&gt;There are two main benefits of being part of the Fediverse, Freedom and Content.&lt;/p&gt;

&lt;p&gt;Being part of the Fediverse means that you have the freedom to choose a network tailored to your specific needs as your home server, users are free to pick instances based on their content moderation policy, technical reliability, and others, while still being able to interact with their friends that are using a different network or even hosting their own instance.&lt;/p&gt;

&lt;p&gt;Using a Fediverse social network also means that you are going to have more content than a traditionally upcoming social network. The Fediverse already has millions of users and several social networks have already announced that they are going to add support for it, such as Tumblr and Threads, this means that even if you are part of a small federated instance you can still consume content being posted on other social networks.&lt;/p&gt;

&lt;p&gt;As Bill Gates once said, “Content is king” on the Internet, and since the beginning of social networks users have flocked to where content is being published, but this might change with the Fediverse. With content being available to the whole Fediverse as opposed to a single social network instance this means that each user can make their decision about their home server without taking content into consideration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Challenges Ahead
&lt;/h2&gt;

&lt;p&gt;Both ActivityPub and the Fediverse have several challenges ahead if they are to continue with their current growth rate.&lt;/p&gt;

&lt;p&gt;The first and most pressing one is scalability, ActivityPub is a very recent protocol, it was published in 2018 and so far it has been an uphill battle to scale it with constant outages and degraded user experience. This could be a common case of scaling issues for an early-stage social network with a high growth rate however there are some design decisions behind this protocol that might make it especially hard to scale. Jeff Darcy, an engineer at Meta, wrote a post about this topic, I recommend the read for more context about some of these issues as well as some insights on scaling social networks: &lt;a href="https://gist.github.com/jdarcy/60107fe4e653819138396257df302eef"&gt;https://gist.github.com/jdarcy/60107fe4e653819138396257df302eef&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another important issue is privacy and safety, being a distributed and decentralized network the Fediverse doesn’t have guarantees on how instances are going to handle users right to privacy. Let’s walk through an example, a user posts a picture on their feed, the post is then distributed to all the instances connected to the Fediverse however the user realizes they made a mistake and chooses to delete the picture, in this scenario, a request to delete the picture will be sent to all instances but there are no guarantees that they are going to actually fulfill this request. This issue is not only about instances acting in bad faith, there might be legitimate instances with different policies regarding content deletion requests. In short, there are no guarantees on how instances and users in different instances will interact with the content you post.&lt;/p&gt;

&lt;p&gt;Lastly, it’s not clear what the incentives will be for existing social networks to join the Fediverse. Networks in the Fediverse distribute all the content being posted on them, meaning that users will be able to access content that was previously only accessible on their own app/website on a completely different surface, over which the network has no control over. This creates several monetization issues, for example, websites won’t be able to display ads when you consume content shared by them on a different social network.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep an eye out
&lt;/h2&gt;

&lt;p&gt;Regardless if you want to create an account in a Fediverse instance or if you use a social network that will add support for it, I recommend keeping an eye out for this space. It’s not frequent that we have an experience of a distributed and federated group of social networks at this scale and, given the current growth trend, it might just be the beginning of a new standard for how social networks operate on the web.&lt;/p&gt;

&lt;p&gt;Liked reading this post? Follow me on &lt;a href="https://twitter.com/leotmenezes"&gt;@ltmenezes&lt;/a&gt; on Twitter to keep yourself up-to-date with my latest articles.&lt;/p&gt;

</description>
      <category>socialmedia</category>
      <category>networking</category>
      <category>activitypub</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Automated Dapps Scrapping with Metamask and C#</title>
      <dc:creator>Leonardo Teixeira Menezes</dc:creator>
      <pubDate>Fri, 01 Oct 2021 09:28:13 +0000</pubDate>
      <link>https://forem.com/ltmenezes/automated-dapps-scrapping-with-metamask-and-c-39m4</link>
      <guid>https://forem.com/ltmenezes/automated-dapps-scrapping-with-metamask-and-c-39m4</guid>
      <description>&lt;p&gt;Hey everyone!&lt;br&gt;
This article is a follow up on my last article about Daaps Scrapping, if you have not read it yet I suggest heading to:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag__link"&gt;
  &lt;a href="/ltmenezes" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F675844%2F93109e1f-2679-4cdc-a629-7a79206d7918.jpg" alt="ltmenezes"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/ltmenezes/automated-dapps-scrapping-with-selenium-and-metamask-2ae9" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Automated Dapps Scrapping with Selenium and Metamask&lt;/h2&gt;
      &lt;h3&gt;Leonardo Teixeira Menezes ・ Jul 28 '21&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#blockchain&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#python&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#testing&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;Thank you all for the great feedback you provided in the last article, it's great to see people building their automations and sharing their own challenges.&lt;/p&gt;

&lt;p&gt;One of my followers requested an example of how Metamask automation would look like in C#, so a built an automation for the same 'Import Wallet' flow:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ChromeOptions&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromeOptions&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddExtension&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EXTENSION_PATH&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;IWebDriver&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromeDriver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CHROME_PATH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Navigate to Metamask extension page&lt;/span&gt;
        &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Navigate&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;GoToUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"chrome-extension://&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;EXTENSION_ID&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/popup.html"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Enter Metamask import wallet flow&lt;/span&gt;
        &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FindElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;XPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"//button[text()=\"Get Started\"]"&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;Click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FindElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;XPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"//button[text()=\"Import wallet\"]"&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;Click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FindElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;XPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"//button[text()=\"No Thanks\"]"&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;Click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Send recovery phrase, password to import the wallet&lt;/span&gt;
        &lt;span class="n"&gt;IList&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IWebElement&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;inputFields&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FindElements&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;XPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"//input"&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;inputFields&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;SendKeys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SECRET_RECOVERY_PHRASE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;inputFields&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;SendKeys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NEW_SECRET&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;inputFields&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;SendKeys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NEW_SECRET&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FindElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CssSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;".first-time-flow__terms"&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;Click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FindElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;XPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"//button[text()=\"Import\"]"&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;Click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FindElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;XPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"//button[text()=\"All Done\"]"&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;Click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Close Metamask 'What's new' popup&lt;/span&gt;
        &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FindElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CssSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;".popover-header__button"&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;Click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadLine&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The concepts used here are the same as the previous article, we load Metamask extension to our ChromeDriver, navigate to its extension page and then automate the import flow as we would with any webpage. &lt;/p&gt;

&lt;p&gt;It's good to note that the XPaths and CSS selectors used here might differ based on your Metamask extension version, so if you have issues in any of these steps jump over to your local ChromeDriver window and debug which selector broke the automation.&lt;/p&gt;

&lt;p&gt;Let me know in the comments for which Dapp you are building your automation for and which challenges you're facing, I will make sure to address them in the next article!&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>blockchain</category>
      <category>testing</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Automated Dapps Scrapping with Selenium and Metamask</title>
      <dc:creator>Leonardo Teixeira Menezes</dc:creator>
      <pubDate>Wed, 28 Jul 2021 20:41:15 +0000</pubDate>
      <link>https://forem.com/ltmenezes/automated-dapps-scrapping-with-selenium-and-metamask-2ae9</link>
      <guid>https://forem.com/ltmenezes/automated-dapps-scrapping-with-selenium-and-metamask-2ae9</guid>
      <description>&lt;p&gt;One of the newest trends in web development is the rise of decentralized applications, also known as Dapps. These applications are built leveraging decentralized networks in order to provide trustless interactions between users, using predefined interactions built as smart contracts (if you want to know more about dapps &lt;a href="https://ethereum.org/en/dapps/"&gt;head over here&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;To access Dapps users need to use a crypto wallet to connect with, this creates a new challenge for developers who want to scrap and/or test Dapps using tools like &lt;a href="https://github.com/SeleniumHQ/selenium"&gt;Selenium&lt;/a&gt;. In this post we will cover the basics on how to solve this using Python and Chromium, however, the principles described here can be applied using any programming language and web browser automation tool.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/lNfnNzyssTmR2xOwZd/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/lNfnNzyssTmR2xOwZd/giphy.gif" width="480" height="278"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Most current Dapps depend on a crypto wallet being present in the user browser as an extension, injecting in the web page information about the user wallet and the network it's connected with. One of the most popular browser crypto wallet is &lt;a href="https://metamask.io/"&gt;Metamask&lt;/a&gt;. In order to successfully scrape a Dapp we need to interact not only with the target website but also with the Metamask extension simultaneously, to approve the app connection with our wallet and other possible transactions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compressing the extension
&lt;/h2&gt;

&lt;p&gt;In order to load the extension on our automated browser we will first need to compress the Metamask extension to a .crx file, here are the steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install Metamask on your regular chrome&lt;/li&gt;
&lt;li&gt;Navigate to &lt;code&gt;chrome://extensions/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Click 'Pack extension' and enter the local path to the Metamask extension
This will generate a &lt;code&gt;.crx&lt;/code&gt; file that you can use to load as an extension on Chromium. Save the name of the folder where the extension is installed, this will be the 'Extension ID' that we will use later.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Loading the extension
&lt;/h2&gt;

&lt;p&gt;To load Chromium with Metamask installed run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;selenium&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;webdriver&lt;/span&gt;

&lt;span class="n"&gt;EXTENSION_PATH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ENTER THE PATH TO YOUR CRX FILE&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;opt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;webdriver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ChromeOptions&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_extension&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EXTENSION_PATH&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;driver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;webdriver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Chrome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chrome_options&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Interacting with Metamask
&lt;/h2&gt;

&lt;p&gt;In order to interact with the dapp and Metamask simultaneously, we will need to have multiple tabs in our Chromium, one for the target Dapp and another one for Metamask itself.&lt;/p&gt;

&lt;p&gt;When Chromium starts it will have a welcome screen for the Metamask extension, which will prompt you to setup your wallet, this is an example code to import an existing wallet (You may need to update some steps depending on your Metamask version):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_element_by_xpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;//button[text()=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Get Started&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;]&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_element_by_xpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;//button[text()=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Import wallet&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;]&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_element_by_xpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;//button[text()=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;No Thanks&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;]&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# After this you will need to enter you wallet details
&lt;/span&gt;
&lt;span class="n"&gt;inputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_elements_by_xpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;//input&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;send_keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SECRET_RECOVERY_PHRASE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;send_keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NEW_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;send_keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NEW_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_element_by_css_selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;.first-time-flow__terms&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_element_by_xpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;//button[text()=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Import&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;]&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_element_by_xpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;//button[text()=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;All Done&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;]&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After this Metamask will be successfully set up in Chromium, ready to connect to a Dapp.&lt;br&gt;
When you need to interact with Metamask again you will need to use it in a different tab, like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;EXTENSION_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ENTER HERE THE EXTENSION ID THAT YOU SAVED EARLIER&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;

&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute_script&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;window.open(&lt;/span&gt;&lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="s"&gt;);&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;switch_to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;window&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;window_handles&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;chrome-extension://{}/popup.html&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EXTENSION_ID&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this Metamask will be opened in this new tab, ready to be interacted with.&lt;/p&gt;




&lt;p&gt;That's it, now you're ready to start automating interactions with Dapps.&lt;br&gt;
Follow me for more articles like this and if you have any questions feel free to leave them in the comments below.&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>python</category>
      <category>webdev</category>
      <category>testing</category>
    </item>
  </channel>
</rss>
