<?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>DEV Community: Cibrax</title>
    <description>The latest articles on DEV Community by Cibrax (@cibrax).</description>
    <link>https://dev.to/cibrax</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%2F671757%2F5df87e0b-bb49-49f5-8fad-6e8bf4701cd3.jpg</url>
      <title>DEV Community: Cibrax</title>
      <link>https://dev.to/cibrax</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cibrax"/>
    <language>en</language>
    <item>
      <title>Cookie-Based authentication for Next.js 13 apps</title>
      <dc:creator>Cibrax</dc:creator>
      <pubDate>Wed, 11 Oct 2023 17:01:44 +0000</pubDate>
      <link>https://dev.to/cibrax/cookie-based-authentication-for-nextjs-13-apps-4bad</link>
      <guid>https://dev.to/cibrax/cookie-based-authentication-for-nextjs-13-apps-4bad</guid>
      <description>&lt;p&gt;This post is for you if you want a simpler alternative to NextAuth to implement authentication in your Next.js application using Iron-Session and the App Router.&lt;/p&gt;

&lt;h1&gt;
  
  
  What's iron-session ?
&lt;/h1&gt;

&lt;p&gt;It's a popular open-source project for Node.js for encrypting/decrypting data that can be persisted in cookies. You can find more about the project in &lt;a href="https://github.com/vvo/iron-session"&gt;Github&lt;/a&gt;.&lt;br&gt;
My implementation uses a middleware that relies on iron-session to create an encrypted session cookie for the authenticated user. I wrote two functions: getSession for decrypting the data associated with the authenticated user in the existing session cookie and setSession for creating the session cookie.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;unsealData&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;iron-session/edge&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;sealData&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;iron-session/edge&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;cookies&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/headers&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sessionPassword&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SESSION_PASSWORD&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;sessionPassword&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SESSION_PASSWORD is not set&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;login&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getSession&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;encryptedSession&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cookies&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auth_session&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)?.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;encryptedSession&lt;/span&gt;
        &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;unsealData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;encryptedSession&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;sessionPassword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
        &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;setSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;encryptedSession&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;sealData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;sessionPassword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nx"&gt;cookies&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auth_session&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;encryptedSession&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;sameSite&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;strict&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;httpOnly&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="c1"&gt;// secure: true, # Uncomment this line when using HTTPS&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;It's important to note that the authentication cookie has been set with the following attributes,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;sameSite: strict, so only requests coming from our application receive the authentication cookie. This prevents cross-forgery attacks.&lt;/li&gt;
&lt;li&gt;httpOnly: true, so the cookie could not be updated on the client side.&lt;/li&gt;
&lt;li&gt;secure: true, so the cookie is only sent over https. &lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Next.js middleware
&lt;/h1&gt;

&lt;p&gt;The new App Router only supports a single middleware function per application. That function must be called "middleware" and also exported in a file "middleware" at the same level as the "app" directory. If you need to address different concerns as middleware, all those should be combined in this function. Probably not a good idea, but that's a topic for another discussion.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextRequest&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getSession&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/services/authentication/cookie-session&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;getSession&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// See "Matching Paths" below to learn more&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;matcher&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/((?!api|_next/static|_next/image|favicon.ico|login).*)&lt;/span&gt;&lt;span class="dl"&gt;'&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;Matcher is a regular expression that Next.js uses to determine if the middleware should run or not. The code for this implementation just checks if there is an active session or sends the user to the login page otherwise.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Login form
&lt;/h1&gt;

&lt;p&gt;The login form combines a component that runs the client side with a server action that authenticates the user and issues the session cookie.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@mui/material/Button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Typography&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@mui/material/Typography&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Container&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@mui/material/Container&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Paper&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@mui/material/Paper&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;TextField&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@mui/material/TextField&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;experimental_useFormState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;experimental_useFormStatus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-dom&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;login&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/app/login/action&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;SubmitButton&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;pending&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;experimental_useFormStatus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Button&lt;/span&gt;
            &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="nx"&gt;fullWidth&lt;/span&gt;
            &lt;span class="nx"&gt;variant&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;contained&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;primary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;10px 0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
            &lt;span class="nx"&gt;aria&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;pending&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nx"&gt;Login&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;experimental_useFormState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Container&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;main&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;maxWidth&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;xs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Paper&lt;/span&gt; &lt;span class="nx"&gt;elevation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;20px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;marginTop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;20px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Typography&lt;/span&gt; &lt;span class="nx"&gt;variant&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;h5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;align&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;center&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Login&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Typography&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TextField&lt;/span&gt;
                        &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;username&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
                        &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;username&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
                        &lt;span class="nx"&gt;variant&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;outlined&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                        &lt;span class="nx"&gt;margin&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;normal&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                        &lt;span class="nx"&gt;required&lt;/span&gt;
                        &lt;span class="nx"&gt;fullWidth&lt;/span&gt;
                        &lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Username&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                        &lt;span class="nx"&gt;autoFocus&lt;/span&gt;
                        &lt;span class="nx"&gt;aria&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;describedby&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                    &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
                    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TextField&lt;/span&gt;
                        &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
                        &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
                        &lt;span class="nx"&gt;variant&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;outlined&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                        &lt;span class="nx"&gt;margin&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;normal&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                        &lt;span class="nx"&gt;required&lt;/span&gt;
                        &lt;span class="nx"&gt;fullWidth&lt;/span&gt;
                        &lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                        &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                        &lt;span class="nx"&gt;autoComplete&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;current-password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                    &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
                    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SubmitButton&lt;/span&gt;&lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/form&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Typography&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;red&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="nx"&gt;gutterBottom&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Typography&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                &lt;span class="p"&gt;)}&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Paper&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Container&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&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 component below representing the view of the login form runs as a client component to use experimental_useFormState. That function allows capturing results back from the server action. &lt;/p&gt;

&lt;p&gt;The server action is straightforward; it only authenticates the user and sets the cookie. For the sake of simplicity, the code only checks for "admin" as username and password.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;setSession&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/services/authentication/cookie-session&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/navigation&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;login&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;previousState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FormData&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;username&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;setSession&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;login&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/home&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;previousState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;previousState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid username or password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;}&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;There is something tricky about the experimental_useFormState function, which requires a client component to be used but a server component acting as a parent to invoke the server action. That part took me a while to figure out. You need a new server component to wrap the form.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Form&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./form&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Login&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Form&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Form&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&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;h1&gt;
  
  
  Complete example
&lt;/h1&gt;

&lt;p&gt;You can find the complete implementation in this &lt;a href="https://github.com/pcibraro/nextjs-auth"&gt;Github repo&lt;/a&gt;&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>authentication</category>
    </item>
    <item>
      <title>Contratos Hibridos, Oraculos y Chainlink</title>
      <dc:creator>Cibrax</dc:creator>
      <pubDate>Wed, 29 Dec 2021 13:07:12 +0000</pubDate>
      <link>https://dev.to/cibrax/contratos-hibridos-oraculos-y-chainlink-1k6n</link>
      <guid>https://dev.to/cibrax/contratos-hibridos-oraculos-y-chainlink-1k6n</guid>
      <description>&lt;p&gt;Una de las caracteristicas principales de los Smart Contracts o contratos inteligentes en Blockchain programables como Ethereum es que se ejecutan de manera aislada. Eso signfica que la maquina virtual de Ethereum o EVM ejecuta los contratos en un sandbox en donde solo tienen acceso a los datos locales o datos provistos por otros contratos en la misma red.&lt;br&gt;
La idea de Oraculos aparecen como solucion a esa problematica. Pareciera ser que el termino esta relacionado de alguna manera a la pelicula The Matrix. El oraculo era el personaje que sabia todo sobre la matriz y asesoraba a Neo, el persona principal sobre lo que ocurria en el mundo exterior. &lt;br&gt;
Aplicando el mismo principio, podriamos decir que un oraculo es un smart contrat que sabe como conectarse con aplicaciones o servicios correndo fuera del Blockchain.&lt;/p&gt;

&lt;p&gt;En muchos casos, proveen cotizaciones en tiempo real de distintos tokens a los smart contracts que forman parte de los protocolos Defi, y son criticos para el funcionamiento de los mismos.&lt;/p&gt;

&lt;p&gt;Un contrato hibrido es un termino que introdujeron los del proyecto Chainlink. Es una combinacion de un contrato que corre en el Blockchain pero tiene acceso a servicios fuera del Blockchain que son provistos por nodos de la red de Chainlink (O mejormente llamados DoNs). En otras palabras, un contrato hibrido seria equivalente a un Oraculo.&lt;/p&gt;

&lt;p&gt;Sergey Nazarov,  uno de los fundadores de Chainlink hizo incapie en la importancia de los Oraculos para muchos de los protocolos que corren en un Blockchain, y la lanzo esta frase popular, "Un Blockchain sin Oraculos, es como una computadora sin internet".&lt;/p&gt;
&lt;h2&gt;
  
  
  Los modelos push y pull
&lt;/h2&gt;

&lt;p&gt;Los modelos push y pull hacen referencia al modo en que un Oraculo provee informacion a otros contratos.&lt;/p&gt;

&lt;p&gt;En el modelo push, aplicaciones o servicios corriendo fuera del Blockchain estan constantemente actualizando informacion en los contratos que actuan como Oraculos. Otros contratos pueden luego consultar esta informacion a demanda.&lt;/p&gt;

&lt;p&gt;Por otro lado, el modelo pull es lo opuesto. Un contrato que necesita acceder a informacion no disponible en el Blockchain llama a un Oraculo a traves de una transaccion.  Una aplicacion que esta corriendo por fuera del Blockchain y monitoreando las transacciones hacia ese Oraculo intercepta la transaccion, ejecuta codigo o llama a un servicio externo y devuelve el resultado como otra transaccion al contrato que originalmente llamo al Oraculo. &lt;/p&gt;
&lt;h2&gt;
  
  
  Chainlink
&lt;/h2&gt;

&lt;p&gt;Chainlink es un proyecto que busca proveer toda la infrastructura que se necesite para poder correr una red de Oraculos que se integran con cualquier Blockchain programable existente (Ethereum y otros). &lt;br&gt;
No es un Blockchain, pero  brindan el software para que cualquiera pueda correr un nodo que internamente provee Oraculos que actuan como intemediarios entre Smart Contracts corriendo en un Blockchain y aplicaciones fuera del mismo.&lt;/p&gt;

&lt;p&gt;El modelo de negocios de Chainlink es proveer mecanismos para vender datos a las aplicaciones corriendo en el Blockchain. Si un protocolo Defi necesita una cotizacion o algun dato que un servicio externa pueda proveer, los mismos se publican a traves de Oraculos que corren en uno o mas nodos de Chainlink. Esos nodos reciben fracciones del token nativo $Link cada vez que pueden satisfacer alguno de esos pedidos. El token $Link es una implementacion del estandard ERC-677. &lt;br&gt;
La conexion con sistemas externos se realizar a traves un componente llamado "Adapter" o adaptador. Cualquier programador puede crear o implementar un "Adapter" &lt;/p&gt;

&lt;p&gt;Cualquiera puede correr un nodo de Link, pero la gracia esta en poder tener acceso a algunos de los adapters que mas se utilizan. &lt;br&gt;
Mucho de ese hosting se lo delegan a socios estrategicos o tambien llamados operadores de nodos. Al fin y al cabo, Chainlink representa en su totalidad al conjunto de todas las redes de nodos que corren su software.&lt;/p&gt;

&lt;p&gt;Uno de los aspectos criticos de cualquier procolo de Defi es que no puede confiar en una sola fuente de datos para tomar decisiones. Si esa fuente de datos no esta disponible o brinda informacion erronea, de pronto se vuelve un verdadero problema y puede generar perdidas enormes.&lt;br&gt;
Chainlink ataca ese problema juntando y procesando datos de muchas fuentes y haciendolo disponible a traves de distintos nodos. Si uno de esos nodos deja de responder, los otros lo pueden remplazar. Lo mismo con la calidad de la informacion, si uno de los nodos empieza a brindar datos invalidos, los otros pueden realizar correcciones. Cabe aclarar que esto solo aplica para el price feed de cotizaciones, el cual lo manejan ellos y es uno de los caballos de batalla de este proyecto.  Si alguien quiere algo similar, lo tiene que implementar desde cero, y Chainlink no lo provee.&lt;/p&gt;
&lt;h2&gt;
  
  
  La arquitectura de Chainlink
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xypiqLgY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cjwhab5lpuam9tpk62ea.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xypiqLgY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cjwhab5lpuam9tpk62ea.png" alt="Image description" width="601" height="571"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Como definicion a alto nivel, una red de Chainlink esta compuesta por nodos. Un nodo es un proceso que esta corriendo todo el tiempo y permite la configuracion de tareas de integracion o que se conectan al Blockchain. Cuando arrancas un nodo, tenes que configurar una clave privada, la cual se usa para firmar cualquier transaccion que el nodo enviee al Blockchain. Si no tenes ningun clave, el nodo automaticamente genera una cuando arranca.&lt;br&gt;
Esa clave tambien tiene que tener fondos en ETH, por que de lo contrario, el nodo no va a poder pagar por el gas para enviar las transacciones. Esa clave privada tambien brinda la contraparte publica o direccion para identificar al nodo.&lt;/p&gt;

&lt;p&gt;Las tareas de integracion que corre un nodo con Oraculos en el Blockchain se configuran en algo que se llaman Jobs. Un job esta representado por un documento json que tiene dos partes, una tarea de arranque (initiator) y otras tareas de integracion. La tarea de arranque es la que vigila que se cumpla cierta condicion para dar comienzo a la ejecucion del resto de las tareas del job. Esas condiciones por lo general son transacciones o eventos que ocurren en el Blockchanin. Chainlink ya ofrece algunas implementaciones que podes reutilizar cuando configuras un job en un nodo. Tambien podes crear tu propia tarea de arranque si asi lo precisas.&lt;/p&gt;

&lt;p&gt;Estas tareas de arranque son las que determinan el modelo push o pull del Oraculo. Las tareas que vigilan el transaction log del Blockchain por transacciones o eventos, soportan el modelo pull. Por el contrario, tambien tenes tareas que se ejecutan en intervalos de tiempo predeterminados y continuan con otras tareas que actualizan el estado de un smart contract. Estas ultimas son para soportar el modelo push.&lt;/p&gt;

&lt;p&gt;Una vez que la tarea de arranque se ejecuto,  esta devuelve datos que se pasan al resto de las tareas que se ejecutan a continuacion. La ultima tarea en ejecutarse  puede llamar a un sistema externo o bien enviar los datos resultantes al Blockchain. &lt;/p&gt;

&lt;p&gt;Esto es un ejemplo de un job,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Integracion Web&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;initiators&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;web&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tasks&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;myadapter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&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;La tarea de arranque "web", es una de las tareas predefinidas por Chainlink y permite arrancar el job desde una interface web que provee el nodo. Una vez que este job arranca, ejecuta otra tarea que se llama "myadapter" y que probablemente envie datos a un sistema externo.&lt;/p&gt;

&lt;p&gt;Como podes ver, los job implementan el patron de Tuberias o Pipeline, en donde tenes datos de ingreso que se van pasando entre las distintas tareas para luego convertirlos en un resultado final.&lt;/p&gt;

&lt;p&gt;Un nodo nos da dos interfaces para configurar jobs y adapters (se explica a continuacion), por linea de comando con un tool, o por una interface web. Ambos necesitan de un usuario y contrasena que se registran cuando el nodo se configura por primera vez.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adaptadores o Adapters
&lt;/h2&gt;

&lt;p&gt;Un adaptador o external adapter es un componente para integrar Chainlink con sistemas externos.&lt;/p&gt;

&lt;p&gt;Un adaptador no es otra cosa que una API que sigue ciertas convenciones para los parametros de entrada y lo de salida. El desarrollador escribe esta API y la puede publicar como un adaptador en un nodo de Chainlink. Se registra especificando la URL en donde esta hosteada. Una vez que se registro en el nodo, se la puede referenciar desde un job.&lt;/p&gt;

&lt;p&gt;La API de un adaptador solo puede recibir HTTP POSTs con el siguiente JSON,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:{},&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;meta&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;job id&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;responseURL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;url&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;data: Son los datos de ingreso que la API necesita para pasarle al sistema externo&lt;/li&gt;
&lt;li&gt;meta: Opcional. Son argumentos de configuracion.&lt;/li&gt;
&lt;li&gt;responseURL: Opcional. Si la API tiene que devolver una respuesta con un callback a esta URL (para llamadas asyncronicas)&lt;/li&gt;
&lt;li&gt;id: Opcional. El identificador del job.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;La respuesta de un adaptador debe ser la siguiente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pending&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;data: Un objeto que representa la respuesta de la llamada externa.&lt;/li&gt;
&lt;li&gt;error: Opcional. Detalles de error si la llamada fallo.&lt;/li&gt;
&lt;li&gt;pending: Opcional. Para llamadas asincronicas, nos indica si la 
llamada esta pendiente de esperar una respuesta.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Un adaptador no devuelve codigos de estado HTTP para especificar si la llamada fallo o no. Y si el sistema externo necesita credenciales de autenticacion, se le deben pasar al adaptador como parte de los datos de entrada, o se deben configurar en el nodo.&lt;/p&gt;

&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Al momento de escribir este post, el nodo no pasa ningun token de autenticacion al adapter cuando lo llama. Si el adapter corre como una API en un servidor externo al nodo, y queres restringir quien puede hacer una llamada al mismo, vas a tener que restringer las llamadas por IP en el subnet en donde corren los nodos.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Correr un nodo de Chainlink
&lt;/h2&gt;

&lt;p&gt;Cualquiera puede correr un nodo de Chainlink bajandose el codigo fuente o a traves de una imagen de Docker.&lt;/p&gt;

&lt;p&gt;Este post solo va a discutir como hacerlo con Docker. El contenedor de Docker va a necesitar de los siguientes requisitos.&lt;/p&gt;

&lt;p&gt;1- Una base de datos Postgres. (Tambien se puede correr como otro contenedor de Docker)&lt;br&gt;
2- Acceso a un nodo de Ethereum, ya sea un nodo propio o un nodo publico en Infura.&lt;/p&gt;

&lt;p&gt;Para este ejemplo voy a mostrar como correr la base de datos Posgres tambien como un contenedor de Docker.&lt;/p&gt;

&lt;p&gt;El primer paso es crear una red en Docker para que nodo y la base de datos pueden comunicarse entre si.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker network create chainlink-net
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El segundo paso es correr el contenedor de Postgres&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run -d -p 5432:5432 --name chainlink-db --net=chainlink-net -e POSTGRES_PASSWORD=password postgres
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El tercer paso es crear un archivo con la configuracion del nodo de Chainlink (Este nodo va a utilizar Rinkeby). El archivo se debe llamar .env&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LOG_LEVEL=debug
ETH_CHAIN_ID=4
MIN_OUTGOING_CONFIRMATIONS=2
LINK_CONTRACT_ADDRESS=0x01BE23585060835E02B77ef475b0Cc51aA1e0709
CHAINLINK_TLS_PORT=0
SECURE_COOKIES=false
GAS_UPDATER_ENABLED=true
ALLOW_ORIGINS=*
ETH_URL=&amp;lt;YOUR INFURA Rinkeby ETH URL&amp;gt;
DATABASE_URL=postgresql://postgres:password@chainlink-db:5432/postgres?sslmode=disable
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finalmente, se necesita ejecutar este comando arrancar el nodo de Chainlink&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run -v ~/.chainlink-rinkeby:/chainlink -p 6688:6688 -it --net=chainlink-net --env-file=.env smartcontract/chainlink:0.10.8 local n
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Una vez que el nodo esta corriendo, tambien ofrece acceso a un portal de administracion. Si lo corren en forma local, esta disponible en el puerto 6688 por defecto. Pueden navegar a &lt;a href="https://localhost:6688"&gt;https://localhost:6688&lt;/a&gt; para comenzar a configurar jobs y adapters.&lt;/p&gt;

&lt;p&gt;Si queres asociarle fondos en ETH a la clave privada del nodo, podes usar el tool por linea de comando para exportarla y luego importarla en un wallet externo. Necesitas correr estos comandos,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker exec -it &amp;lt;container&amp;gt; bash
chainlink admin login
chainlink keys eth list
chainlink keys eth export &amp;lt;node-address&amp;gt; -p .password --output key.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Node-Address es la direccion publica del nodo, esta se muestra una vez que arrancas al mismo o en la interface web. Una vez que corren este comando, van a obtener la clave privada en un archivo json. Pueden importar el mismo directamente en un wallet como Metamask.&lt;/p&gt;

</description>
      <category>chainlink</category>
      <category>ethereum</category>
      <category>oracles</category>
      <category>blockchain</category>
    </item>
    <item>
      <title>Sign-In with Solana</title>
      <dc:creator>Cibrax</dc:creator>
      <pubDate>Mon, 20 Dec 2021 15:27:44 +0000</pubDate>
      <link>https://dev.to/cibrax/sign-in-with-solana-3m95</link>
      <guid>https://dev.to/cibrax/sign-in-with-solana-3m95</guid>
      <description>&lt;p&gt;Solana has become lately one of the hottest programmable Blockchains after Ethereum. Since the adoption of Solana is growing, and also the number of people using one of their wallets, it might be convenient to start looking into how to support one-click authentication for web sites.&lt;/p&gt;

&lt;p&gt;This post will show how to enable that scenario with Phantom.&lt;/p&gt;

&lt;h2&gt;
  
  
  One-Click authentication with signatures
&lt;/h2&gt;

&lt;p&gt;Either Ethereum or Solana supports the idea of signing text messages with the user's private key available on a wallet. Since only the user owns that private key, and it is the only one who can generate an equivalent signature, this is proof enough to use it as an authentication mechanism. A This scenario uses a combination of Signature + Public Key/Address. As an analogy to a traditional authentication method like username and password, the Public Key/Address would be equivalent to the username, and the signature to a password.&lt;/p&gt;

&lt;h2&gt;
  
  
  Signing a text message with Phantom
&lt;/h2&gt;

&lt;p&gt;The following code shows how to use Phantom to sign a message. The user will be prompted to authorize this operation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Sign this message for authenticating with your wallet. Nonce: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;nonce&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;encodedMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;TextEncoder&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signedMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;solana&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
   &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;signMessage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;encodedMessage&lt;/span&gt;&lt;span class="p"&gt;,&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;A nonce was generated server-side and injected in the text message to avoid reply attacks, in which the user signature is intercepted and reused for authentication later on.&lt;/p&gt;

&lt;p&gt;This sample uses NextAuth for integrating authentication in a Next.js application. The signature and public key are passed to the SignIn function provided by NextAuth.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;signIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;credentials&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;signedMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;signature&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;signedMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;signature&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;callbackUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/`&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Verifying the signature on the server side.
&lt;/h2&gt;

&lt;p&gt;The server receives the signature and public key and  verifies whether the former is valid. The user is authenticated once this validation passes successfully.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nonce&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cookies&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;auth-nonce&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Sign this message for authenticating with your wallet. Nonce: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;nonce&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;messageBytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;TextEncoder&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;publicKeyBytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;bs58&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signatureBytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;bs58&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;signature&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nacl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;detached&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;messageBytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;signatureBytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;publicKeyBytes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`authentication failed`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user can not be authenticated&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;publicKey&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code retrieves the generated nonce from a session cookie, recreates the text message, and validates the user's signature with the public key passed by the client side.&lt;br&gt;
Once the signature is validated, the public key is set as the username for the user.&lt;/p&gt;

&lt;p&gt;The complete sample is available to download from my Github repository &lt;a href="https://github.com/pcibraro/solana-login"&gt;solana-login&lt;/a&gt;&lt;/p&gt;

</description>
      <category>solana</category>
      <category>javascript</category>
      <category>blockchain</category>
      <category>authentication</category>
    </item>
    <item>
      <title>Como implementar NFTs con Solidity</title>
      <dc:creator>Cibrax</dc:creator>
      <pubDate>Thu, 28 Oct 2021 14:28:05 +0000</pubDate>
      <link>https://dev.to/cibrax/como-implementar-nfts-con-solidity-3knd</link>
      <guid>https://dev.to/cibrax/como-implementar-nfts-con-solidity-3knd</guid>
      <description>&lt;p&gt;NFT o Token No Fugible (Non-Fungile-Token) es un concepto relativamente nuevo y capaz dificil de entender para muchos.&lt;/p&gt;

&lt;p&gt;Un token en el contexto de Blockchain representa una prueba de pertenencia en el mundo digital. Significa que se puede utilizar como evidencia para demostrar que uno es dueño de algo. Hay una diferencia muy sutil entre ser dueño y probar que uno es dueño. Vos podes ser dueño de un automovil, pero para probar que realmente te pertenece, quizas necesites una factura o titulo que lo demuestre. Un token sirve para demostrar esto ultimo. Ademas, podes demostrar que el token te pertenece utilizando el sistema de critografia con clave publica y privada. El token esta asociado a una direccion que solo se puede calcular con la clave privada que uno posee.&lt;/p&gt;

&lt;p&gt;Los tokens se crearon para representar valor en la moneda nativa de un Blockchain o su equivalente en moneda fiat como ser los dolares americanos. Si tenes un token, lo podes cambiar por otro sin hacer ninguna diferencia o perder valor.&lt;/p&gt;

&lt;p&gt;En cambio, los NFTs fueron creados para representar cosas unicas cuyo valor no esta atado a una moneda. Como cada NFT es unico, tambien tiene un valor intrinsico diferente. No se puede cambiar simplemente por otro NFT como ocurriria con un token tradicional. Se pueden utilizar para representar posesion sobre bienes digitales como ser imagenes, subscripciones, tickets o recompensas en un juego, etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  NFTs en Ethrereum
&lt;/h2&gt;

&lt;p&gt;Los NFTs se implementan en Ethereum a traves de Smart Contracts. Estos ultimos no son los NFT en si, pero proveen el mecanismo para generarlos. Los contratos en este escenario controlan como se generan y asignan los NFTs en el Blockchain. La imagen siguiente muestra como los NFTs se agrupan y viven bajo el contrato que los genero.&lt;/p&gt;

&lt;p&gt;&lt;a href="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%2Farticles%2Fdymqj6l73segiswvyqvu.jpg" class="article-body-image-wrapper"&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%2Farticles%2Fdymqj6l73segiswvyqvu.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;En ese sentido, uno no puede simplemente acceder o localizarlos directamente por una direccion en el Blockchain. Son solamente una representation logica dentro del ambito de un contrato. El acceso a los mismos esta exclusivamente controlada por dicho contrato. &lt;/p&gt;

&lt;p&gt;Como no representan un elemento nativo de un Blockchain, un desarrollador podria implementar el contrato para manejarlos en la forma que mas le convenga. Para evitar que esto pase, la comunidad de Ethereum definio una interface con metodos que cualquier implementador deberia seguir para considerar que el contrato permite controlar NFTs. Esta interface se convirtio en un estandard con el nombre de ERC-721.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pragma solidity ^0.4.20;

/// @title ERC-721 Non-Fungible Token Standard
/// @dev See https://eips.ethereum.org/EIPS/eip-721
///  Note: the ERC-165 identifier for this interface is 0x80ac58cd.
interface ERC721 /* is ERC165 */ {
    /// @dev This emits when ownership of any NFT changes by any mechanism.
    ///  This event emits when NFTs are created (`from` == 0) and destroyed
    ///  (`to` == 0). Exception: during contract creation, any number of NFTs
    ///  may be created and assigned without emitting Transfer. At the time of
    ///  any transfer, the approved address for that NFT (if any) is reset to none.
    event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);

    /// @dev This emits when the approved address for an NFT is changed or
    ///  reaffirmed. The zero address indicates there is no approved address.
    ///  When a Transfer event emits, this also indicates that the approved
    ///  address for that NFT (if any) is reset to none.
    event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);

    /// @dev This emits when an operator is enabled or disabled for an owner.
    ///  The operator can manage all NFTs of the owner.
    event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);

    /// @notice Count all NFTs assigned to an owner
    /// @dev NFTs assigned to the zero address are considered invalid, and this
    ///  function throws for queries about the zero address.
    /// @param _owner An address for whom to query the balance
    /// @return The number of NFTs owned by `_owner`, possibly zero
    function balanceOf(address _owner) external view returns (uint256);

    /// @notice Find the owner of an NFT
    /// @dev NFTs assigned to zero address are considered invalid, and queries
    ///  about them do throw.
    /// @param _tokenId The identifier for an NFT
    /// @return The address of the owner of the NFT
    function ownerOf(uint256 _tokenId) external view returns (address);

    /// @notice Transfers the ownership of an NFT from one address to another address
    /// @dev Throws unless `msg.sender` is the current owner, an authorized
    ///  operator, or the approved address for this NFT. Throws if `_from` is
    ///  not the current owner. Throws if `_to` is the zero address. Throws if
    ///  `_tokenId` is not a valid NFT. When transfer is complete, this function
    ///  checks if `_to` is a smart contract (code size &amp;gt; 0). If so, it calls
    ///  `onERC721Received` on `_to` and throws if the return value is not
    ///  `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
    /// @param _from The current owner of the NFT
    /// @param _to The new owner
    /// @param _tokenId The NFT to transfer
    /// @param data Additional data with no specified format, sent in call to `_to`
    function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable;

    /// @notice Transfers the ownership of an NFT from one address to another address
    /// @dev This works identically to the other function with an extra data parameter,
    ///  except this function just sets data to "".
    /// @param _from The current owner of the NFT
    /// @param _to The new owner
    /// @param _tokenId The NFT to transfer
    function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;

    /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
    ///  TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE
    ///  THEY MAY BE PERMANENTLY LOST
    /// @dev Throws unless `msg.sender` is the current owner, an authorized
    ///  operator, or the approved address for this NFT. Throws if `_from` is
    ///  not the current owner. Throws if `_to` is the zero address. Throws if
    ///  `_tokenId` is not a valid NFT.
    /// @param _from The current owner of the NFT
    /// @param _to The new owner
    /// @param _tokenId The NFT to transfer
    function transferFrom(address _from, address _to, uint256 _tokenId) external payable;

    /// @notice Change or reaffirm the approved address for an NFT
    /// @dev The zero address indicates there is no approved address.
    ///  Throws unless `msg.sender` is the current NFT owner, or an authorized
    ///  operator of the current owner.
    /// @param _approved The new approved NFT controller
    /// @param _tokenId The NFT to approve
    function approve(address _approved, uint256 _tokenId) external payable;

    /// @notice Enable or disable approval for a third party ("operator") to manage
    ///  all of `msg.sender`'s assets
    /// @dev Emits the ApprovalForAll event. The contract MUST allow
    ///  multiple operators per owner.
    /// @param _operator Address to add to the set of authorized operators
    /// @param _approved True if the operator is approved, false to revoke approval
    function setApprovalForAll(address _operator, bool _approved) external;

    /// @notice Get the approved address for a single NFT
    /// @dev Throws if `_tokenId` is not a valid NFT.
    /// @param _tokenId The NFT to find the approved address for
    /// @return The approved address for this NFT, or the zero address if there is none
    function getApproved(uint256 _tokenId) external view returns (address);

    /// @notice Query if an address is an authorized operator for another address
    /// @param _owner The address that owns the NFTs
    /// @param _operator The address that acts on behalf of the owner
    /// @return True if `_operator` is an approved operator for `_owner`, false otherwise
    function isApprovedForAll(address _owner, address _operator) external view returns (bool);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;El concepto de interface tampoco existe en la maquina virtual de Ethereum (EVM). Solidity los soporta, pero una vez que el contrato se compila y transforma en byte code, no hay forma de determinar que implementa dicha interface salvo mirando los metodos que provee.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;/blockquote&gt;

&lt;p&gt;Como los contratos son la fuente de NFTs, tambien cobra sentido el echo de utilizarlos para agrupar colecciones como images or arte.&lt;/p&gt;

&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Un NFT no es otra cosa mas que un ID unico que esta asociado a la direccion de su dueño en el espacio de almacenamiento del Smart Contract que lo genero.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;/blockquote&gt;

&lt;p&gt;El espacio de almacenamiento en el Blockchain es caro. Mientras guardes datos basicos de tus NFTs, no pasa nada. Pero si quieres guardar cosas mas grandes como imagenes de varios KBs, ya estamos hablando de otra cosa. El Blockchain no esta optimizado para ese escenario y tambien el precio a pagar seria muy alto. Por esa razon, lo que se hace en estos casos es utilizar un archivo de metadatos. Es un archivo en formato JSON que describe a tu NFT mas en detalle, y guarda entre otras cosas, URLs a otras ubicaciones en donde estan las imagenes asociadas al NFT u otros documentos grandes. Este archivo de metadatos se podria guardar en cualquier lado, pero la mayoria prefiere hacerlo en forma decentralizada utilizando IPFS. El contrato termina manteniendo una referencia a la ubicacion de este archivo.&lt;/p&gt;

&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;El problema del huevo y la gallina. El Blockchain asegura integridad de datos para mi NFTs. Una vez que se almacena ahi, nadie puede cambiarlo. Sin embargo, no podemos asegurar lo mismo para este archivo de metadatos que vive afuera del Blockchain. Hay varias soluciones a este problema. Una es guardar estos metadatos como texto en el contrato, y todas las referencias del mismo fuera del Blockchain. Otra es guardar un checksum generado a partir de los datos en el mismo.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Implementando un contrato ERC-721 con OpenZeppelin
&lt;/h2&gt;

&lt;p&gt;OpenZeppelin ya provee un contrato que podemos utilizar de base para cualquier implementacion que se adhiera al estandard ERC-721.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.2;

import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract TikenToken is ERC721, Ownable {
    using Counters for Counters.Counter; 

    Counters.Counter private _tokenIds;

    event TokenEmitted(string indexed symbol, address _sender, uint256 _id);

    constructor() ERC721("My NFT", "MYNFT") {
    }

    function createToken(string memory _tokenURI, address to) public onlyOwner returns (uint) {
        _tokenIds.increment();
        uint256 newItemId = _tokenIds.current();

        _mint(to, newItemId);

        emit TokenEmitted(symbol(), to, newItemId);

        return newItemId;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El codigo de arriba muestra una implementacion muy basica. Genera un nuevo identificador para un token NFT y llama al metodo interno &lt;code&gt;_mint&lt;/code&gt; para asociar este nuevo token con la direccion que se paso como argumento. Este contrato guarda internamente la relacion entre ambos en una estructura de datos del tipo &lt;code&gt;mapping&lt;/code&gt;.&lt;br&gt;
Esta implementacion no ofrece metadatos para los NFTs. Si queres guardar una URL que apunte al archivo de metadatos, tambien tenes que implementar la interface &lt;code&gt;ERC721URIStorage&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function tokenURI(uint256 tokenId)
        public
        view
        override(ERC721, ERC721URIStorage)
        returns (string memory)
    {
        return super.tokenURI(tokenId);
    }

    function createToken(string memory _tokenURI) public onlyOwner returns (uint) {
        _tokenIds.increment();
        uint256 newItemId = _tokenIds.current();

        _mint(msg.sender, newItemId);
        _setTokenURI(newItemId, _tokenURI);

        emit TokenEmitted(symbol(), msg.sender, newItemId);

        return newItemId;
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Con estos cambios, hay un metodo nuevo &lt;code&gt;tokenURI&lt;/code&gt; que devuelve la URL asociada al token y modificamos el metodo &lt;code&gt;createToken&lt;/code&gt; para guardar esa URL en el contrato.&lt;/p&gt;

&lt;p&gt;Por ultimo, si tambien quieran soportar destruir o quemar los token NFTs generados por su contrato, lo pueden hacer implementando la interface &lt;code&gt;ERC721Burnable&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) {
        super._burn(tokenId);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Este metodo lo que hace es asignar el token a una direccion a la cual nadie puede acceder, y por lo tanto se considera que el token fue destruido o quemado.&lt;/p&gt;

</description>
      <category>nft</category>
      <category>ethereum</category>
      <category>blockchain</category>
      <category>solidity</category>
    </item>
    <item>
      <title>NFTs in Ethereum explained</title>
      <dc:creator>Cibrax</dc:creator>
      <pubDate>Mon, 25 Oct 2021 13:09:51 +0000</pubDate>
      <link>https://dev.to/cibrax/nfts-in-ethereum-explained-4hbp</link>
      <guid>https://dev.to/cibrax/nfts-in-ethereum-explained-4hbp</guid>
      <description>&lt;h1&gt;
  
  
  NFTs in Ethereum explained
&lt;/h1&gt;

&lt;p&gt;NFT or Non-Fungible-Token is a relatively new concept that is hard to grasp for many.&lt;br&gt;
A token in the scope of a Blockchain represents proof of ownership in a digital world, which means you can use it as evidence to prove you own something. There is a subtle difference between ownership and proof of ownership. You could own a car, but you might need an invoice or title to prove it is yours. A token represents the latter. You demonstrate a token is yours by using public and private key cryptography. The token is associated with an address that can only be computed with a private key you own.&lt;br&gt;
A token was initially used to represent value in the native currency of a Blockchain or an equivalent fiat currency such as US Dollars. All the issue tokens were worth the same value. If you have one token, you could change with another token without making any difference or losing value.&lt;/p&gt;

&lt;p&gt;NFTs were introduced to represent things with a unique value other than currency. As each NFT is unique, they have different intrinsic values as well. You can not simply change an NFT for another NFT anymore. They could represent ownership on digital assets such as images, subscriptions, game rewards, etc.&lt;/p&gt;
&lt;h2&gt;
  
  
  NFTs in Ethrereum
&lt;/h2&gt;

&lt;p&gt;NFTs are implemented in Ethrereum with Smart Contracts. It is worth mentioning that a Smart Contract is not an NFT but a source or factory for them.&lt;/p&gt;

&lt;p&gt;The contracts in this scenario control how the NFTs are issued and assigned in the Blockchain. The following image shows how NFTs are grouped and stored in the Blockchain under their parent contract.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PM0kECo5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fhcvz4liykio82r8ostr.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PM0kECo5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fhcvz4liykio82r8ostr.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In that sense, they can not directly be accessed or located by an address in the Blockchain. The access is always controlled by a contract. NFTs are not a built-in construct in the Blockchain either, so anyone could implement the Smart Contract to manage them in any way. To prevent the latter from happening, different community members in Ethereum defined a primary interface with a few methods that any Smart Contract should adhere to be considered an NFT factory. That interface became the facto standard known as ERC-721.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight solidity"&gt;&lt;code&gt;&lt;span class="k"&gt;pragma&lt;/span&gt; &lt;span class="n"&gt;solidity&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="mf"&gt;0.4&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;/// @title ERC-721 Non-Fungible Token Standard
/// @dev See https://eips.ethereum.org/EIPS/eip-721
///  Note: the ERC-165 identifier for this interface is 0x80ac58cd.
&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="n"&gt;ERC721&lt;/span&gt; &lt;span class="cm"&gt;/* is ERC165 */&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;/// @dev This emits when ownership of any NFT changes by any mechanism.
&lt;/span&gt;    &lt;span class="c1"&gt;///  This event emits when NFTs are created (`from` == 0) and destroyed
&lt;/span&gt;    &lt;span class="c1"&gt;///  (`to` == 0). Exception: during contract creation, any number of NFTs
&lt;/span&gt;    &lt;span class="c1"&gt;///  may be created and assigned without emitting Transfer. At the time of
&lt;/span&gt;    &lt;span class="c1"&gt;///  any transfer, the approved address for that NFT (if any) is reset to none.
&lt;/span&gt;    &lt;span class="k"&gt;event&lt;/span&gt; &lt;span class="n"&gt;Transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;address&lt;/span&gt; &lt;span class="k"&gt;indexed&lt;/span&gt; &lt;span class="n"&gt;_from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;address&lt;/span&gt; &lt;span class="k"&gt;indexed&lt;/span&gt; &lt;span class="n"&gt;_to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;uint256&lt;/span&gt; &lt;span class="k"&gt;indexed&lt;/span&gt; &lt;span class="n"&gt;_tokenId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;/// @dev This emits when the approved address for an NFT is changed or
&lt;/span&gt;    &lt;span class="c1"&gt;///  reaffirmed. The zero address indicates there is no approved address.
&lt;/span&gt;    &lt;span class="c1"&gt;///  When a Transfer event emits, this also indicates that the approved
&lt;/span&gt;    &lt;span class="c1"&gt;///  address for that NFT (if any) is reset to none.
&lt;/span&gt;    &lt;span class="k"&gt;event&lt;/span&gt; &lt;span class="n"&gt;Approval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;address&lt;/span&gt; &lt;span class="k"&gt;indexed&lt;/span&gt; &lt;span class="n"&gt;_owner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;address&lt;/span&gt; &lt;span class="k"&gt;indexed&lt;/span&gt; &lt;span class="n"&gt;_approved&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;uint256&lt;/span&gt; &lt;span class="k"&gt;indexed&lt;/span&gt; &lt;span class="n"&gt;_tokenId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;/// @dev This emits when an operator is enabled or disabled for an owner.
&lt;/span&gt;    &lt;span class="c1"&gt;///  The operator can manage all NFTs of the owner.
&lt;/span&gt;    &lt;span class="k"&gt;event&lt;/span&gt; &lt;span class="n"&gt;ApprovalForAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;address&lt;/span&gt; &lt;span class="k"&gt;indexed&lt;/span&gt; &lt;span class="n"&gt;_owner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;address&lt;/span&gt; &lt;span class="k"&gt;indexed&lt;/span&gt; &lt;span class="n"&gt;_operator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;_approved&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;/// @notice Count all NFTs assigned to an owner
&lt;/span&gt;    &lt;span class="c1"&gt;/// @dev NFTs assigned to the zero address are considered invalid, and this
&lt;/span&gt;    &lt;span class="c1"&gt;///  function throws for queries about the zero address.
&lt;/span&gt;    &lt;span class="c1"&gt;/// @param _owner An address for whom to query the balance
&lt;/span&gt;    &lt;span class="c1"&gt;/// @return The number of NFTs owned by `_owner`, possibly zero
&lt;/span&gt;    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;balanceOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;address&lt;/span&gt; &lt;span class="n"&gt;_owner&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;external&lt;/span&gt; &lt;span class="k"&gt;view&lt;/span&gt; &lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint256&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;/// @notice Find the owner of an NFT
&lt;/span&gt;    &lt;span class="c1"&gt;/// @dev NFTs assigned to zero address are considered invalid, and queries
&lt;/span&gt;    &lt;span class="c1"&gt;///  about them do throw.
&lt;/span&gt;    &lt;span class="c1"&gt;/// @param _tokenId The identifier for an NFT
&lt;/span&gt;    &lt;span class="c1"&gt;/// @return The address of the owner of the NFT
&lt;/span&gt;    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;ownerOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint256&lt;/span&gt; &lt;span class="n"&gt;_tokenId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;external&lt;/span&gt; &lt;span class="k"&gt;view&lt;/span&gt; &lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;address&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;/// @notice Transfers the ownership of an NFT from one address to another address
&lt;/span&gt;    &lt;span class="c1"&gt;/// @dev Throws unless `msg.sender` is the current owner, an authorized
&lt;/span&gt;    &lt;span class="c1"&gt;///  operator, or the approved address for this NFT. Throws if `_from` is
&lt;/span&gt;    &lt;span class="c1"&gt;///  not the current owner. Throws if `_to` is the zero address. Throws if
&lt;/span&gt;    &lt;span class="c1"&gt;///  `_tokenId` is not a valid NFT. When transfer is complete, this function
&lt;/span&gt;    &lt;span class="c1"&gt;///  checks if `_to` is a smart contract (code size &amp;gt; 0). If so, it calls
&lt;/span&gt;    &lt;span class="c1"&gt;///  `onERC721Received` on `_to` and throws if the return value is not
&lt;/span&gt;    &lt;span class="c1"&gt;///  `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
&lt;/span&gt;    &lt;span class="c1"&gt;/// @param _from The current owner of the NFT
&lt;/span&gt;    &lt;span class="c1"&gt;/// @param _to The new owner
&lt;/span&gt;    &lt;span class="c1"&gt;/// @param _tokenId The NFT to transfer
&lt;/span&gt;    &lt;span class="c1"&gt;/// @param data Additional data with no specified format, sent in call to `_to`
&lt;/span&gt;    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;safeTransferFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;address&lt;/span&gt; &lt;span class="n"&gt;_from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;address&lt;/span&gt; &lt;span class="n"&gt;_to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;uint256&lt;/span&gt; &lt;span class="n"&gt;_tokenId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;bytes&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;external&lt;/span&gt; &lt;span class="k"&gt;payable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;/// @notice Transfers the ownership of an NFT from one address to another address
&lt;/span&gt;    &lt;span class="c1"&gt;/// @dev This works identically to the other function with an extra data parameter,
&lt;/span&gt;    &lt;span class="c1"&gt;///  except this function just sets data to "".
&lt;/span&gt;    &lt;span class="c1"&gt;/// @param _from The current owner of the NFT
&lt;/span&gt;    &lt;span class="c1"&gt;/// @param _to The new owner
&lt;/span&gt;    &lt;span class="c1"&gt;/// @param _tokenId The NFT to transfer
&lt;/span&gt;    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;safeTransferFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;address&lt;/span&gt; &lt;span class="n"&gt;_from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;address&lt;/span&gt; &lt;span class="n"&gt;_to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;uint256&lt;/span&gt; &lt;span class="n"&gt;_tokenId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;external&lt;/span&gt; &lt;span class="k"&gt;payable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;/// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
&lt;/span&gt;    &lt;span class="c1"&gt;///  TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE
&lt;/span&gt;    &lt;span class="c1"&gt;///  THEY MAY BE PERMANENTLY LOST
&lt;/span&gt;    &lt;span class="c1"&gt;/// @dev Throws unless `msg.sender` is the current owner, an authorized
&lt;/span&gt;    &lt;span class="c1"&gt;///  operator, or the approved address for this NFT. Throws if `_from` is
&lt;/span&gt;    &lt;span class="c1"&gt;///  not the current owner. Throws if `_to` is the zero address. Throws if
&lt;/span&gt;    &lt;span class="c1"&gt;///  `_tokenId` is not a valid NFT.
&lt;/span&gt;    &lt;span class="c1"&gt;/// @param _from The current owner of the NFT
&lt;/span&gt;    &lt;span class="c1"&gt;/// @param _to The new owner
&lt;/span&gt;    &lt;span class="c1"&gt;/// @param _tokenId The NFT to transfer
&lt;/span&gt;    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;transferFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;address&lt;/span&gt; &lt;span class="n"&gt;_from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;address&lt;/span&gt; &lt;span class="n"&gt;_to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;uint256&lt;/span&gt; &lt;span class="n"&gt;_tokenId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;external&lt;/span&gt; &lt;span class="k"&gt;payable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;/// @notice Change or reaffirm the approved address for an NFT
&lt;/span&gt;    &lt;span class="c1"&gt;/// @dev The zero address indicates there is no approved address.
&lt;/span&gt;    &lt;span class="c1"&gt;///  Throws unless `msg.sender` is the current NFT owner, or an authorized
&lt;/span&gt;    &lt;span class="c1"&gt;///  operator of the current owner.
&lt;/span&gt;    &lt;span class="c1"&gt;/// @param _approved The new approved NFT controller
&lt;/span&gt;    &lt;span class="c1"&gt;/// @param _tokenId The NFT to approve
&lt;/span&gt;    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;approve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;address&lt;/span&gt; &lt;span class="n"&gt;_approved&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;uint256&lt;/span&gt; &lt;span class="n"&gt;_tokenId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;external&lt;/span&gt; &lt;span class="k"&gt;payable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;/// @notice Enable or disable approval for a third party ("operator") to manage
&lt;/span&gt;    &lt;span class="c1"&gt;///  all of `msg.sender`'s assets
&lt;/span&gt;    &lt;span class="c1"&gt;/// @dev Emits the ApprovalForAll event. The contract MUST allow
&lt;/span&gt;    &lt;span class="c1"&gt;///  multiple operators per owner.
&lt;/span&gt;    &lt;span class="c1"&gt;/// @param _operator Address to add to the set of authorized operators
&lt;/span&gt;    &lt;span class="c1"&gt;/// @param _approved True if the operator is approved, false to revoke approval
&lt;/span&gt;    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;setApprovalForAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;address&lt;/span&gt; &lt;span class="n"&gt;_operator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;_approved&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;external&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;/// @notice Get the approved address for a single NFT
&lt;/span&gt;    &lt;span class="c1"&gt;/// @dev Throws if `_tokenId` is not a valid NFT.
&lt;/span&gt;    &lt;span class="c1"&gt;/// @param _tokenId The NFT to find the approved address for
&lt;/span&gt;    &lt;span class="c1"&gt;/// @return The approved address for this NFT, or the zero address if there is none
&lt;/span&gt;    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getApproved&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint256&lt;/span&gt; &lt;span class="n"&gt;_tokenId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;external&lt;/span&gt; &lt;span class="k"&gt;view&lt;/span&gt; &lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;address&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;/// @notice Query if an address is an authorized operator for another address
&lt;/span&gt;    &lt;span class="c1"&gt;/// @param _owner The address that owns the NFTs
&lt;/span&gt;    &lt;span class="c1"&gt;/// @param _operator The address that acts on behalf of the owner
&lt;/span&gt;    &lt;span class="c1"&gt;/// @return True if `_operator` is an approved operator for `_owner`, false otherwise
&lt;/span&gt;    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;isApprovedForAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;address&lt;/span&gt; &lt;span class="n"&gt;_owner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;address&lt;/span&gt; &lt;span class="n"&gt;_operator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;external&lt;/span&gt; &lt;span class="k"&gt;view&lt;/span&gt; &lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;bool&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;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Interfaces don't exist as a primary construct in the Ethereum Virtual Machine (EVM). They are supported in Solidity, but they don't correlate to anything once they are deployed. You can assume a Smart Contract follows a convention for the methods it provides.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;/blockquote&gt;

&lt;p&gt;Since a Smart Contract becomes the source for NFTs, it also makes a lot of sense for grouping collections like image collectibles.&lt;/p&gt;

&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;NFTs are unique IDs mapped to an address (the owner) and stored in a Smart Contract.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;/blockquote&gt;

&lt;p&gt;Storage space in the Blockchain is expensive. As long as you store basic data about your NFTs in the storage, you should be good. How about images? That is a different story. Although it would make sense to store the whole blob of bytes for an image in the Blockchain, that would be extremely expensive and hard to manage in the long run. For that reason, the community found a different way to address that scenario. It is called NFT metadata. It is a JSON file that describes additional data about your NFT that you wouldn't store in the Blockchain. That metadata file contains, for example, an URL to the location of the image blob. This metadata file could be stored anywhere, but many prefer it in decentralized storage like IPFS. The Smart Contract ends up holding a reference to the location of this metadata in the Blockchain.&lt;/p&gt;

&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;The chicken and egg dilemma. My NFT in the Blockchain assures data integrity. Once it is saved in the Blockchain, it can be changed. However, the same thing can not be ensured for the metadata file is pointing to. There are solutions to this problem. Store the metadata as text in the same storage as the Smart Contract, or store a checksum created from the data in the metadata file. &lt;/p&gt;
&lt;/blockquote&gt;


&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Implementing an ERC-721 contract
&lt;/h2&gt;

&lt;p&gt;OpenZeppelin already provides a base contract that can be used as a starting point for any implementation that sticks to the ERC-721 standard.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight solidity"&gt;&lt;code&gt;&lt;span class="c1"&gt;// SPDX-License-Identifier: MIT
&lt;/span&gt;&lt;span class="k"&gt;pragma&lt;/span&gt; &lt;span class="n"&gt;solidity&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="mf"&gt;0.8&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="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"@openzeppelin/contracts/utils/Counters.sol"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"@openzeppelin/contracts/token/ERC721/ERC721.sol"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"@openzeppelin/contracts/access/Ownable.sol"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;contract&lt;/span&gt; &lt;span class="n"&gt;TikenToken&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;ERC721&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Ownable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="n"&gt;Counters&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;Counters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 

    &lt;span class="n"&gt;Counters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Counter&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;_tokenIds&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;event&lt;/span&gt; &lt;span class="n"&gt;TokenEmitted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="k"&gt;indexed&lt;/span&gt; &lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;address&lt;/span&gt; &lt;span class="n"&gt;_sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;uint256&lt;/span&gt; &lt;span class="n"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;ERC721&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"My NFT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"MYNFT"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;createToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="k"&gt;memory&lt;/span&gt; &lt;span class="n"&gt;_tokenURI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;address&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;onlyOwner&lt;/span&gt; &lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_tokenIds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="kt"&gt;uint256&lt;/span&gt; &lt;span class="n"&gt;newItemId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_tokenIds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="n"&gt;_mint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;newItemId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;emit&lt;/span&gt; &lt;span class="n"&gt;TokenEmitted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;newItemId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;newItemId&lt;/span&gt;&lt;span class="p"&gt;;&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 code above shows a straightforward implementation of an ERC721 contract. &lt;br&gt;
It generates a new identifier for the NFT and calls the internal &lt;code&gt;_mint&lt;/code&gt; method for associating the sender address with this new token (internally stored in a mapping).&lt;br&gt;
This implementation does not offer any metadata for the NFTs. If you also want to store the URL for the metadata associated with the generated NFT, you must implement the &lt;code&gt;ERC721URIStorage&lt;/code&gt; interface.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight solidity"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;tokenURI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint256&lt;/span&gt; &lt;span class="n"&gt;tokenId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt;
        &lt;span class="k"&gt;view&lt;/span&gt;
        &lt;span class="k"&gt;override&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ERC721&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ERC721URIStorage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="k"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tokenURI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokenId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;createToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="k"&gt;memory&lt;/span&gt; &lt;span class="n"&gt;_tokenURI&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;onlyOwner&lt;/span&gt; &lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_tokenIds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="kt"&gt;uint256&lt;/span&gt; &lt;span class="n"&gt;newItemId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_tokenIds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="n"&gt;_mint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;newItemId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;_setTokenURI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newItemId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_tokenURI&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;emit&lt;/span&gt; &lt;span class="n"&gt;TokenEmitted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;newItemId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;newItemId&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;These changes include a new method, &lt;code&gt;tokenURI&lt;/code&gt; that returns the metadata URL associated with the token and a new line &lt;code&gt;_setTokenURI&lt;/code&gt; in the &lt;code&gt;createToken&lt;/code&gt; method for persisting the URL in the contract storage.&lt;/p&gt;

&lt;p&gt;Finally, if you also want to support the ability to destroy or burn issued NTFs, you can also implement the interface &lt;code&gt;ERC721Burnable&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight solidity"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;_burn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint256&lt;/span&gt; &lt;span class="n"&gt;tokenId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;internal&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ERC721&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ERC721URIStorage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_burn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokenId&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 method assigns the token to an address that is no longer accessible.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Implementing a basic ETH Pool - Exactly challenge explained</title>
      <dc:creator>Cibrax</dc:creator>
      <pubDate>Thu, 26 Aug 2021 18:32:03 +0000</pubDate>
      <link>https://dev.to/cibrax/implementing-a-basic-eth-pool-exactly-challenge-explained-54c</link>
      <guid>https://dev.to/cibrax/implementing-a-basic-eth-pool-exactly-challenge-explained-54c</guid>
      <description>&lt;h1&gt;
  
  
  Implementing a basic ETH Pool - Exactly Finance's challenge explained
&lt;/h1&gt;

&lt;p&gt;I am still in the process of learning Solidity and Smart contract development, and there is no better way to learn than building new stuff on it. Yesterday, I came across a code challenge from Exactly to build a basic pool in Ethereum. I thought it was going to be a great exercise to put some ideas into practice, so I decide to ahead and do it. What I am going to show here is a summary of all the design decisions and how I ended up implementing that solution.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Challenge
&lt;/h1&gt;

&lt;p&gt;You can find the full description of the challenge here. In short, it requires implementing a pool where one or more participants can deposit funds. There is also a team that owns the pool and can contribute to it with rewards. Those rewards are distributed across all the participants in the pool according to their % of the stake. For example, if Participant A deposits 100 tokens and B 300 tokens, A owns 25% and B 75%. When A or B withdraws the funds from the pool, they should get their funds and also the corresponding % of the rewards sent to the pool until that point in time. Once a participant has left the pool, it won't be able to claim rewards in that pool anymore. Time is not mentioned anywhere in the description, so we won't consider it as a variable for the implementation.&lt;/p&gt;

&lt;h1&gt;
  
  
  The implementation
&lt;/h1&gt;

&lt;p&gt;The first thing is to define the Smart Contract structure. For this implementation, we will require at least three methods, &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deposit: for making deposits in the pool&lt;/li&gt;
&lt;li&gt;Withdraw: for withdraw funds from the pool&lt;/li&gt;
&lt;li&gt;Deposit Rewards: for teams members to distribute rewards through the members in the pool.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;contract ETHPool {
  receive() external payable {}
  function depositRewards() public payable {}
  function withdraw() public {}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We could implement deposits in two ways, a traditional method or a receive method (previously known as the fallback method). I decided to use the latter to receive funds directly with a regular transaction without a data payload. Some wallets or exchanges don't support data payload.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Receive method
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;uint256 public total;

address[] public users;

struct DepositValue {
  uint256 value;
  bool hasValue;
}

mapping(address =&amp;gt; DepositValue) public deposits;

receive() external payable {

   if(!deposits[msg.sender].hasValue) // only pushes new users
      users.push(msg.sender);

    deposits[msg.sender].value += msg.value;
    deposits[msg.sender].hasValue = true;

    total += msg.value;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The deposit implementation uses two data structures, a mapping for storing the funds associated with a user (deposits), and a list for tracking all the users in the pool (users). &lt;br&gt;
In the way the EVM works, there is no way to determine if an entry exists in a mapping, so we can not rely on the mapping to determine if the user is part of the list of users. I did not want to go through all the elements in the list either; that could be expensive for a long list. I decided to use a known workaround with a struct that contains a flag to determine if the entry was defined or not. &lt;br&gt;
Once a user makes a deposit, I store the funds in the mapping and add the user to the list if it was not added previously. &lt;br&gt;
Finally, I increase the total value in the pool. I decided to use a variable to store the contract's total and not use the balance. The latter is prone to &lt;a href="https://consensys.github.io/smart-contract-best-practices/known_attacks/#forcibly-sending-ether-to-a-contract"&gt;attacks&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The DepositRewards method
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function depositRewards() public payable  {
  require(total &amp;gt; 0); // No rewards to distribute if the pool is empty.

  for (uint i = 0; i &amp;lt; users.length; i++){
    address user = users[i];

    uint rewards = ((deposits[user].value * msg.value) / total);

    deposits[user].value += rewards;
   }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The challenge description does not mention time anywhere as a variable. It only describes the rewards are paid weekly. That implies that anyone with funds in the pool can receive rewards. It does not matter how long the funds were there. &lt;br&gt;
My implementation goes through all the users in the list and distributes the received rewards according to the % of the stake on the pool. &lt;br&gt;
I had to consider two things when implementing this method. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If the pool is empty, so the total equals 0, there is no need to distribute any rewards. We want to rollback the transaction if that happens. Otherwise, the funds for the rewards will be lost.&lt;/li&gt;
&lt;li&gt; The EVM does not support decimals or float numbers, so you have to be careful when doing divisions. The initial formula I used was this one (user deposits / total) * rewards. However, that produced a result equal to 0 most of the time, as the user deposits were less than the total.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  The Withdraw method
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function withdraw() public {
  uint256 deposit = deposits[msg.sender].value;

  require(deposit &amp;gt; 0, "You don't have anything left to withdraw");

  deposits[msg.sender].value = 0;

  (bool success, ) = msg.sender.call{value:deposit}("");

  require(success, "Transfer failed");
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;It checks the user's funds in the pool and transfers those. If the user does not have anything in the pool, the transaction is reverted. It also sets the deposits in the pool to zero before making the transfer to avoid reentrancy attacks. Once the transfer is made, it checks for the results and reverts the transaction if the call failed (our change in the deposits mapping is reverted as well).&lt;br&gt;&lt;br&gt;
There is no need to use a reentrancy guard, as setting the deposit to 0 is making the same effect.   &lt;/p&gt;
&lt;h2&gt;
  
  
  Managing the Team Members
&lt;/h2&gt;

&lt;p&gt;The challenge description is clear about who can deposit rewards in the pool. That's the team members. We need to add support in our contract for adding members. A simple way is to pass a list of addresses in the constructor, but that's not flexible. Once the contract is deployed, the list of members can not be changed anymore. I decided to use the OpenZeppelin Access Control contract, which provides support for roles.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import "@openzeppelin/contracts/access/AccessControl.sol";

contract ETHPool is AccessControl {
  constructor() {
    _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
    _setupRole(TEAM_MEMBER_ROLE, msg.sender);
  }
}

function addTeamMember(address account) public {
  grantRole(TEAM_MEMBER_ROLE, account);
}

function removeTeamMember(address account) public {
  revokeRole(TEAM_MEMBER_ROLE, account);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We assign the admin role and team member role to the Smart Contract's owner as a part of the constructor execution. The admin is the one that can assign users to the other roles.  I also added two methods to grant or revoke the team member role to/from a user.&lt;/p&gt;

&lt;p&gt;Finally, the depositRewards method was modified to check for that role.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function depositRewards() public payable onlyRole(TEAM_MEMBER_ROLE) {
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Adding events
&lt;/h2&gt;

&lt;p&gt;Events are nice to have features in Smart Contracts. They allow reporting information in the Blockchain transaction log that can not be inferred directly from a transaction. They can also be indexed and used by Dapps.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;event Deposit(address indexed _address, uint256 _value);
event Withdraw(address indexed _address, uint256 _value);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I added two events for reporting when a deposit or a withdraw was made. &lt;br&gt;
Those are called in the respective methods.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;receive() external payable {
   ....
   emit Deposit(msg.sender, msg.value);
}

function withdraw() public {
  ...
  emit Withdraw(msg.sender, deposit);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The complete implementation
&lt;/h2&gt;

&lt;p&gt;You can find the complete source code in my &lt;a href="https://github.com/pcibraro/challenge"&gt;Github repository&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ethreum</category>
      <category>smartcontracts</category>
    </item>
    <item>
      <title>Chainlink Keepers - An alarm clock for your Smart Contracts</title>
      <dc:creator>Cibrax</dc:creator>
      <pubDate>Fri, 06 Aug 2021 19:48:50 +0000</pubDate>
      <link>https://dev.to/cibrax/chainlink-keepers-an-alarm-clock-for-your-smart-contracts-m0e</link>
      <guid>https://dev.to/cibrax/chainlink-keepers-an-alarm-clock-for-your-smart-contracts-m0e</guid>
      <description>&lt;p&gt;Smart Contracts work in reactive mode. Once deployed in the Blockchain, they go to a hibernation state until some work needs to be done. When the work is completed, they go to bed again. They basically react to transactions by executing code.&lt;/p&gt;

&lt;p&gt;On the contrary, Smart Contracts in proactive mode, which don't really exist in reality but can be emulated, watch for different conditions to wake up themselves and do their job without intervention. For example, a contract that runs automatically when it detects a price fluctuation or when a given date or time is reached.&lt;/p&gt;

&lt;p&gt;These contracts require the intervention of an external agent or worker that is constantly pinging the contract to verify whether one of the conditions to run was met. Those conditions should be checked in one or more view methods to avoid paying gas to the network. That means they can be resolved locally without submitting transactions.&lt;/p&gt;

&lt;p&gt;Running an agent or worker now means you require additional off-chain infrastructure, which is centralized. &lt;/p&gt;

&lt;p&gt;What if you can also leverage some of the existing decentralized network of oracles (DONs) from Chainlink to run those agents. Enter in the scene the Chainlink Keepers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chainlink Keepers
&lt;/h2&gt;

&lt;p&gt;Keepers is a feature recently added in Chainlink for hosting jobs that allow running Smart Contracts proactively. It uses DONs to run the jobs in a decentralized manner. &lt;br&gt;
Jobs are called Upkeeps, and the Smart Contracts must implement an interface with the following methods.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function checkUpkeep(
    bytes calldata checkData
  )
    external
    returns (
        bool upkeepNeeded,
        bytes memory performData
);

function performUpkeep(
    bytes calldata performData
) external;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;checkUpKeep&lt;/code&gt; is the method called periodically by the jobs to check if some works need to be done. &lt;em&gt;It's the alarm clock for your contract&lt;/em&gt;. It receives a parameter checkData, which could be helpful to check for the conditions in the method implementation. That data is a fixed value that you configure as part of the job. It must be implemented as a view to avoiding paying gas on each call. &lt;br&gt;
It returns two values, upKeepNeeded, which specifies if an action must be performed, and data to be passed to execute that action.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;performUpKeep&lt;/code&gt; is the method where the Smart Contract does the work. It's called if upKeepNeeded returned a value equal to true.&lt;/p&gt;

&lt;p&gt;Chainlink also offers an application where you can configure the jobs. As part of the configuration of the job, you must provide the following data.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An email address&lt;/li&gt;
&lt;li&gt;Name of the job (unkeep)&lt;/li&gt;
&lt;li&gt;Address of the deployed contract&lt;/li&gt;
&lt;li&gt;Admin Address. This is the address of an owner that can withdraw funds associated to the contract.&lt;/li&gt;
&lt;li&gt;Gas Limit. This gas limit is for executing the performUnKeep method.&lt;/li&gt;
&lt;li&gt;Check Data, which is passed to the checkUpkeep method. This is an array of bytes (hex), which could result from using abi.encode.
&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;This feature is still in beta and the registration must be done manually in the &lt;a href="https://keepers.chain.link/"&gt;Keepers app&lt;/a&gt;. Not support for automation APIs for the moment&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Anatomy of a Keeper contract
&lt;/h2&gt;

&lt;p&gt;Let's say that you want to implement a Betting contract for a game with two participants. You would like to select a winner and distribute the gains after the game finishes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;

interface KeeperCompatibleInterface {
    function checkUpkeep(bytes calldata checkData) external returns (bool upkeepNeeded, bytes memory performData);
    function performUpkeep(bytes calldata performData) external;
}

contract Betting is KeeperCompatibleInterface{

   uint public matchTimestamp;

    constructor(uint _matchTimestamp) {
      matchTimestamp = _matchTimestamp;
    }

    function checkUpkeep(bytes calldata checkData)  external view override returns (bool upkeepNeeded, bytes memory performData) {
         upkeepNeeded = (block.timestamp &amp;gt; matchTimestamp);
    }

    function performUpkeep(bytes calldata performData) external override {
        //calls an oracle to retrieve the result of the match

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

&lt;/div&gt;



&lt;p&gt;The contract is set with a time lock through a timestamp received in the constructor. We can assume this represents the date and time after the game finishes, and we know who the winner is.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; uint public matchTimestamp;

    constructor(uint _matchTimestamp) {
      matchTimestamp = _matchTimestamp;
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;checkUpkeep&lt;/code&gt; method compares the current block timestamp with the timestamp assigned to the contract and returns a value indicating if the condition is satisfied or not.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function checkUpkeep(bytes calldata checkData)  external view override returns (bool upkeepNeeded, bytes memory performData) {
         upkeepNeeded = (block.timestamp &amp;gt; matchTimestamp);
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, the performUpkeep emulates a call to an Oracle in Chainlink that might hit an API to return the game's result.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function performUpkeep(bytes calldata performData) external override {
        //calls an oracle to retrieve the result of the match

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

&lt;/div&gt;



</description>
      <category>ethereum</category>
      <category>smartcontracts</category>
      <category>chainlink</category>
      <category>keepers</category>
    </item>
    <item>
      <title>The Web3 ecosystem for Ethereum</title>
      <dc:creator>Cibrax</dc:creator>
      <pubDate>Mon, 02 Aug 2021 14:51:27 +0000</pubDate>
      <link>https://dev.to/cibrax/the-web3-ecosystem-for-ethereum-186k</link>
      <guid>https://dev.to/cibrax/the-web3-ecosystem-for-ethereum-186k</guid>
      <description>&lt;p&gt;Web3 is an umbrella term for a new wave of applications that rely on decentralized technologies and the Blockchain. &lt;br&gt;
Since the inception of Ethereum, which brought the idea of executing code in the Blockchain, many new projects have emerged in this space to help developers implement decentralized applications.&lt;br&gt;
The image above shows some of the most notable projects that you can start using today.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rwxlMIwt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://photos.collectednotes.com/photos/4455/b5d775c8-81c2-4253-801b-cb7036d15ec2" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rwxlMIwt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://photos.collectednotes.com/photos/4455/b5d775c8-81c2-4253-801b-cb7036d15ec2" alt="alt"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's give a short overview of the purpose for each one.&lt;/p&gt;

&lt;h2&gt;
  
  
  IPFS
&lt;/h2&gt;

&lt;p&gt;"Interplanetary file system" (or IPFS) is a protocol and peer-to-peer network for storing and sharing files. As with any peer-to-peer network, there is no central server, and different nodes in the network replicate copies of the files. &lt;br&gt;
It would be equivalent to Bittorrent but with a different feature set, and it's what most developers in the Web3 space use today for hosting DApps, written as Single Page Applications, or store and share files. &lt;br&gt;
IPFS is also used to store assets related to the NFTs. &lt;br&gt;
Once you publish content in one of the IPFS nodes, it gets associated with an identifier that could use to locate it. &lt;/p&gt;

&lt;p&gt;Another critical aspect of IPFS if you are planning to host your DApp on it is content pinning. To ensure your files are retained in the network, you need to rely on a pinning service.  Infura, for example, offers a free plan for a limited space. &lt;/p&gt;

&lt;h2&gt;
  
  
  The Graph
&lt;/h2&gt;

&lt;p&gt;The Graph project implements a protocol for indexing and querying data available in the Eth Transaction Log and IPFS.&lt;br&gt;
It supports the idea of subgraphs, which allow developers to tailor the data to be indexed based on their needs. &lt;br&gt;
Those subgraphs are published through nodes in the network, and they can be queried from DApps. &lt;/p&gt;

&lt;p&gt;If your DApp has immediate needs to query data available in the transaction log (e.g., transactions or events), or data pushed in IPFS, you should start by looking into this project first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chainlink
&lt;/h2&gt;

&lt;p&gt;Chainlink is a project whose aim is to provide all the infrastructure and plumbing for running a network of Oracles (DONs) that integrate with existing Blockchain networks (Ethereum and others). It's not a Blockchain, but it offers the infrastructure to run heterogeneous networks with oracle nodes that act as intermediaries between Smart Contracts and applications running outside.&lt;br&gt;
The value proposition or business value in Chainlink is to offer a mechanism to sell data to apps running in the Blockchain. If you have an API that provides data that might be useful in the Blockchain, you can publish it through a Chainlink's adapter in one or more nodes and get paid for every request made to it. The unit of payments is a LINK token, which is a standard ERC-677 token.&lt;br&gt;
You can run one or more nodes or ask any existing node operators (service providers that run nodes in their infrastructure) to run the adapter for you.&lt;br&gt;
In that sense, Chainlink represents a collection of decentralized oracle networks (DONs) with nodes hosting different adapters or connections with external applications.&lt;br&gt;
One of the critical aspects of implementing autonomous apps that run in a Blockchain is that they can not rely on a single data source to make decisions. If the data source becomes unavailable or starts providing inaccurate information, it suddenly becomes a big mess.&lt;br&gt;
Chainlink tries to address that issue by aggregating data from multiple sources and making it available through various nodes (horizontal scaling). If one node becomes unresponsive, the other nodes can take that work. The same thing with the data sources is that if one starts providing invalid data, they can still correct it by using other sources.&lt;/p&gt;

&lt;p&gt;If you are building Smart Contracts that require interaction with the external world, this is the project to look into. &lt;/p&gt;

&lt;h2&gt;
  
  
  Ceramic and IDX
&lt;/h2&gt;

&lt;p&gt;Ceramic and IDX are two relatively new projects from the same company, which address different scenarios.&lt;/p&gt;

&lt;p&gt;Ceramic provides a mechanism for supporting data streams on top of IPFS. This project might be a good fit if you need to support scenarios like messaging in your DApp.&lt;/p&gt;

&lt;p&gt;On the other hand, IDX is about user identity and authentication. It tries to provide an identity layer that any DApp could use to uniquely identify users in a decentralized manner. If you want your DApp users to be authenticated with ETH private keys and have a decentralized profile for them, this is the project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Polkadot
&lt;/h2&gt;

&lt;p&gt;Polkadot is a project that provides interoperability between ETH and other  Blockchains. The idea behind Polkadot is that many of the different available Blockchain today have different purposes, there is any Blockchain that could do everything, and they need to interoperate somehow.  The connection between those Blockchain networks is made through bridges, which this project is going to provide.&lt;/p&gt;

&lt;p&gt;A bridge is an intermediary for moving assets or data from one Blockchain to another. As the Blockchains use different protocols, rules, and governance models, the bridge provides various interoperable mechanisms on both sides. &lt;/p&gt;

&lt;h2&gt;
  
  
  Polygon
&lt;/h2&gt;

&lt;p&gt;Polygon is a layer 2 project for Ethereum. It's well known that Ethereum suffers from scalability issues. It can only process 17 transactions per second, and the gas fees can be very high sometimes. &lt;br&gt;
Polygon runs on top of the Ethereum network and provides better transaction throughput and lower gas fees. It works as a secondary network with a bridge that allows moving assets (tokens) from one network and another. You could leverage Polygon to move load from the main Ethereum network into this L2 Blockchain and provide better response times and cheap gas fees to your users.&lt;/p&gt;

</description>
      <category>web3</category>
      <category>ethereum</category>
      <category>dapps</category>
    </item>
    <item>
      <title>Using Merkle Trees for Bulk transfers in Ethereum</title>
      <dc:creator>Cibrax</dc:creator>
      <pubDate>Tue, 27 Jul 2021 19:53:03 +0000</pubDate>
      <link>https://dev.to/cibrax/using-merkle-trees-for-bulk-transfers-in-ethereum-1h61</link>
      <guid>https://dev.to/cibrax/using-merkle-trees-for-bulk-transfers-in-ethereum-1h61</guid>
      <description>&lt;h1&gt;
  
  
  Using Merkle Trees for Bulk transfers in Ethereum
&lt;/h1&gt;

&lt;p&gt;Merkle Trees have become more popular than ever in the last decade for their heavy use in the crypto world.  Most Blockchain implementations rely on this data structure for validating transactions as part of the consensus protocols. &lt;/p&gt;

&lt;p&gt;What is a Merkle tree exactly? It's a data structure usually represented by a binary tree where each parent node contains a combination of hashes from their children.&lt;/p&gt;

&lt;p&gt;The top of the tree is called root hash or Merkle root, and it is obtained from the process of re-hashing the concatenation of the child nodes starting from the last layer up to the top.&lt;/p&gt;

&lt;p&gt;If the hash in one of the nodes is changed, the resulting tree and Merkle Root are also changed. This is an essential factor for one of the scenarios we will discuss in this article, bulk transfers. &lt;/p&gt;

&lt;h1&gt;
  
  
  The use of Merkle Trees for Bulk Transfers
&lt;/h1&gt;

&lt;p&gt;We all know that executing an operation like a transfer in a Smart Contract cost money (or Ether in technical terms), which is paid as gas to the validation nodes in the network. Now imagine that you have to make thousands of transfers; that's a lot of money giving the high prices of the gas in the ETH mainnet. &lt;/p&gt;

&lt;p&gt;This kind of scenario is fairly common for NFT airdrops, or in the betting industry. Merkle trees become handy for inverting roles in these particular scenarios. What if we make all the possible recipients claim their tokens instead of making a transfer to them. In that way, our solution would scale better as they will be responsible for paying the gas to claim the tokens. &lt;/p&gt;

&lt;p&gt;Let's now describe in detail how this solution works in practical terms. &lt;br&gt;
If we know all the addresses in advance, we can use a Merkle tree and compute a unique Merkle root. We can later distribute a proof representing one of the tree's nodes to each of these addresses.  &lt;/p&gt;

&lt;p&gt;They can use the proof to claim the tokens. The Merkle root in our possession can validate the proof and make sure it belongs to the same tree. If the validation succeeds, we can assume the presented proof was ok, and we can issue the tokens.&lt;/p&gt;

&lt;p&gt;This article will show you how to implement this with Solidity for a Betting scenario.&lt;/p&gt;
&lt;h1&gt;
  
  
  Anatomy of the Betting Smart Contract
&lt;/h1&gt;

&lt;p&gt;The implementation of our Smart Contract uses the OpenZeppelin Contract Library and MerkleProof utility. It's a contract for betting on a match with two teams, team one and team two.&lt;/p&gt;

&lt;p&gt;This is how the contract looks like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "hardhat/console.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import {MerkleProof} from "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";

contract Betting is Ownable {
  event GainsClaimed(address indexed _address, uint256 _value);

  using MerkleProof for bytes32[];

  uint256 public totalBetOne;
  uint256 public totalBetTwo;

  uint256 public minimumBet;

  address[] public playersBetOne;
  address[] public playersBetTwo;

  mapping(address =&amp;gt; uint256) public players;
  mapping(address =&amp;gt; uint256) public claimed;

  bytes32 merkleRoot;
  uint8 winner;

  constructor() Ownable() {
    // minimum bet is 1 gwei
    minimumBet = 1000000000;
  }

  function setMerkleRoot(bytes32 root, uint8 team) onlyOwner public 
  {
    merkleRoot = root;
    winner = team;
  }

  function checkPlayer(address player) public view returns(bool){
    return !(players[player] == 0);
  }

  function getTotalBetOne() public view returns(uint256){
    return totalBetOne;
   }

  function getTotalBetTwo() public view returns(uint256){
    return totalBetTwo;
  }

  function getPlayersBetOne() public view returns(address[] memory) {
    return playersBetOne;
  }

  function getPlayersBetTwo() public view returns(address[] memory) {
    return playersBetTwo;
  }

  function bet(uint8 team) public payable {
    require(team == 1 || team == 2, "Invalid team");

    require(!checkPlayer(msg.sender), "You bet on a game already");

    require(msg.value &amp;gt;= minimumBet, "Minimum bet is 1 gwei");

    require(merkleRoot == 0, "Bets are closed");

    if(team == 1) {
      playersBetOne.push(msg.sender);
      totalBetOne += msg.value;
    } else {
      playersBetTwo.push(msg.sender);
      totalBetTwo += msg.value;
    }

    players[msg.sender] = msg.value;
  }

  function claim(bytes32[] memory proof) public {
    require(merkleRoot != 0, "No winner yet for this bet");

    require(proof.verify(merkleRoot, keccak256(abi.encodePacked(msg.sender))), "You are not in the list");

    uint256 senderBet = players[msg.sender];

    uint256 totalWinners = totalBetOne;
    uint256 totalLosers = totalBetTwo;

    if(winner == 2) {
      totalWinners = totalBetTwo;
      totalLosers = totalBetOne;
    }

    uint256 total = senderBet + ((senderBet / totalWinners) * totalLosers);

    (bool success, ) = msg.sender.call{value:total}("");

    require(success, "Transfer failed.");

    emit GainsClaimed(msg.sender, total);
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's discuss different sections of it in detail.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import "@openzeppelin/contracts/access/Ownable.sol";
import {MerkleProof} from "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This imports the OpenZeppelin Ownable contract and the MerkleProof utility. You must previously install those dependencies by running NPM install "@openzeppelin/contracts" --save-dev. &lt;br&gt;
Our contract references the Ownable contract as we will use the onlyOwner condition in some methods.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;contract Betting is Ownable {
  event GainsClaimed(address indexed _address, uint256 _value);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The contract will emit an event GainsClaimed when someone with valid proof claims the gains.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function setMerkleRoot(bytes32 root, uint8 team) onlyOwner public 
  {
    merkleRoot = root;
    winner = team;
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the method that we will call when the match finishes. We will pass the Merkle root computed from a tree with all the addresses that bet on the winner. We also pass the winner team. Also, note that this method is marked with the onlyOwner condition, so only the contract owner can set the root.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function getPlayersBetOne() public view returns(address[] memory) {
    return playersBetOne;
  }

  function getPlayersBetTwo() public view returns(address[] memory) {
    return playersBetTwo;
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These two methods return a list of the addresses that bet on each team. We will use these lists to compute the Merkle Tree. As these are views, they don't cost anything; they are simply resolved in our local ETH node.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function bet(uint8 team) public payable {
    require(team == 1 || team == 2, "Invalid team");

    require(!checkPlayer(msg.sender), "You bet on a game already");

    require(msg.value &amp;gt;= minimumBet, "Minimum bet is 1 gwei");

    require(merkleRoot == 0, "Bets are closed");

    if(team == 1) {
      playersBetOne.push(msg.sender);
      totalBetOne += msg.value;
    } else {
      playersBetTwo.push(msg.sender);
      totalBetTwo += msg.value;
    }

    players[msg.sender] = msg.value;
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The method for betting on a team accepts the team as an argument and does two things,&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Push the address on the correct list (Team A or Team B)&lt;/li&gt;
&lt;li&gt;Increases the total amount for the bet associated with the contract
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function claim(bytes32[] memory proof) public {
    require(merkleRoot != 0, "No winner yet for this bet");

    require(proof.verify(merkleRoot, keccak256(abi.encodePacked(msg.sender))), "You are not in the list");

    uint256 senderBet = players[msg.sender];

    uint256 totalWinners = totalBetOne;
    uint256 totalLosers = totalBetTwo;

    if(winner == 2) {
      totalWinners = totalBetTwo;
      totalLosers = totalBetOne;
    }

    uint256 total = senderBet + ((senderBet / totalWinners) * totalLosers);

    (bool success, ) = msg.sender.call{value:total}("");

    require(success, "Transfer failed.");

    emit GainsClaimed(msg.sender, total);
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, the method for claiming the gains on the game. This method requires proof, which was previously computed from a Merkle tree containing all the addresses in the winner's list. If someone passes an invalid proof, or a proof calculated from some other tree, the method will validate that and reject the call.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;require(proof.verify(merkleRoot, keccak256(abi.encodePacked(msg.sender))), "You are not in the list");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This method uses the following formula to distribute the gains.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;uint256 total = senderBet + ((senderBet / totalWinners) * totalLosers);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Generating the Merkle Tree
&lt;/h1&gt;

&lt;p&gt;We will be using the merkletreejs and keccak256 from node.js with a Hardhat test suite to test our contract.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { expect } = require("chai");
const { MerkleTree } = require('merkletreejs');
const keccak256 = require('keccak256');

describe("Betting", function () {
  let owner, addr1, addr2, addr3, addr4, addr5;
  let Betting, betting;

  beforeEach(async function() {
      [owner, addr1, addr2, addr3, addr4, addr5] = await ethers.getSigners();

      Betting = await ethers.getContractFactory("Betting");
      betting = await Betting.deploy();

      await betting.deployed();
  });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code above deploys the contract and stores a few addresses provided by Hardhat in local variables so we can reference them later on in the tests.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;it("Should allow claiming gains", async function () {
    await betting.bet(1, { value : 1e9 });

    await betting.connect(addr1).bet(1, { value : 1e9 })

    await betting.connect(addr2).bet(2, { value : 1e9 })

    const list = await betting.getPlayersBetTwo();

    const merkleTree = new MerkleTree(list, keccak256, { hashLeaves: true, sortPairs: true });

    const root = merkleTree.getHexRoot();

    await betting.setMerkleRoot(root, 2);

    const proof = merkleTree.getHexProof(keccak256(addr2.address));

    await expect(betting.connect(addr2).claim(proof))
      .to.emit(betting, 'GainsClaimed')
      .withArgs(addr2.address, 3e9);;
  });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The test above calls the "bet" method from three different addresses, giving a total of 3 gwei as the total balance. We also compute a Merkle tree from the list of addresses for team two (that's a single address, the address 2). &lt;br&gt;
It also generates proof for address 2, and calls the "claim" method with that proof to claim the gains. Note that it's crucial to impersonate the calls with the correct address using the connect method, as many of the methods in our contract use the msg.sender variable.&lt;/p&gt;

&lt;p&gt;The complete code is available in my github repository &lt;a href="https://github.com/pcibraro/merkletree-smartcontracts"&gt;"merkletrees-smartcontracts"&lt;/a&gt;&lt;/p&gt;

</description>
      <category>smartcontracts</category>
      <category>ethereum</category>
      <category>solidity</category>
    </item>
    <item>
      <title>Authorization Code Flow with PKCE in Azure AD with React</title>
      <dc:creator>Cibrax</dc:creator>
      <pubDate>Thu, 22 Jul 2021 12:27:14 +0000</pubDate>
      <link>https://dev.to/cibrax/authorization-code-flow-with-pkce-in-azure-ad-with-react-2b40</link>
      <guid>https://dev.to/cibrax/authorization-code-flow-with-pkce-in-azure-ad-with-react-2b40</guid>
      <description>&lt;h2&gt;
  
  
  Authorization Code Flow with PKCE
&lt;/h2&gt;

&lt;p&gt;The implicit authorization code flow was initially released for native/dumb and javascript applications running in a context of a browser that did not have a dedicated backend to negotiate an access token from an authorization server (due to a limitation in browsers that prevented JavaScript from making cross-domain calls) . &lt;/p&gt;

&lt;p&gt;In this flow, access tokens were returned directly to the browser without requiring any client secret. These aspects made it naturally less secure, so additional practices were used to mitigate any potential vulnerability (e.g short lived tokens, pre-registered redirection URIs or a set of a unique nonce and state parameters in the URL)&lt;/p&gt;

&lt;p&gt;Nowadays, most browsers support Cross-Origin Resource Sharing (CORS) so that cross-domain call limitation is not longer an issue. PCKE or Proof of Code Key Exchange leverages CORS in the browser to negotiate an access token in two steps.&lt;/p&gt;

&lt;p&gt;A code is negotiated in the first step with the following request,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTTP GET https://AzureADURL/authorize 
&amp;amp;response_type=code 
&amp;amp;redirect_uri=https://localhost:3000/login 
&amp;amp;scope=openid profile
&amp;amp;client_id=..... 
&amp;amp;code_challenge=......
&amp;amp;code_challenge_method=S256 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And a second step is executed to get the actual access token,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTTP POST https://AzureADURL/token
&amp;amp;code=.....
&amp;amp;client_id=.... 
&amp;amp;grant_type=authorization_code
&amp;amp;code_verifier=....
&amp;amp;redirect_uri=https://localhost:3000/login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code returned in the first call is the result of a cryptographic algorithm computation (hash) from the code challenge and code challenge method arguments passed in the first call. The code is later validated in the second call takes the code with the code verifier argument.&lt;/p&gt;

&lt;h2&gt;
  
  
  Authorization Code Flow with PKCE in Azure AD
&lt;/h2&gt;

&lt;p&gt;This authorization code flow was recently enabled in Microsoft Azure AD.&lt;/p&gt;

&lt;p&gt;Microsoft also released an update of the Microsoft Authentication Library (MSAL) for javascript to support this flow, which is now called msal-browser.&lt;/p&gt;

&lt;p&gt;As this library is still in beta, documentation and samples are hard to find. I used one of the Vainila JS starter samples to implement the reusable content provider for React that is shared as part of this article.&lt;/p&gt;

&lt;p&gt;The application must be registered as any other regular app in Azure AD under App Registrations, but the the reply url must be set with the type "spa" as it is shown below,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"replyUrlsWithType": [
        {
            "url": "http://localhost:3000/",
            "type": "Spa"
        }
    ],
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="http://localhost:3000"&gt;http://localhost:3000&lt;/a&gt; is where the React application is running.&lt;/p&gt;

&lt;h2&gt;
  
  
  Context Provider Hook in React
&lt;/h2&gt;

&lt;p&gt;In a typical React application, data/state is passed from top/parent to down/children components using properties, but this might not be ideal for cross-cutting corners that apply to all components or state that is shared between all of them. Security is one of those concerns, so it is a good candidate to be implemented as a context provider.&lt;/p&gt;

&lt;p&gt;A context provider allows sharing state between components without explicitly passing it as properties through every level of the three. It would be equivalent to a global state that can be accessed on demand by the components.&lt;/p&gt;

&lt;p&gt;React provides a hook "useContext" to inject a context with shared state in any component.&lt;/p&gt;

&lt;p&gt;Context Provider for Azure AD authentication&lt;br&gt;
The context provider I wrote for this article provides different accessors for state representing the current security context in the applications and functions for user authentication.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;MsalContext.Provider
            value={{
                isAuthenticated,
                user,
                token,
                loading,
                popupOpen,
                loginError,
                login,
                logout,
                getToken
            }}
        &amp;gt;
        {children}
&amp;lt;/MsalContext.Provider&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is a semantic difference between login/getToken and user/token. While login performs user authentication with Open ID/Connect for getting an ID token (the user information), getToken returns an access token for consuming a backend API.&lt;/p&gt;

&lt;p&gt;The configuration passed to these two functions (login and getToken) is slightly different. One uses the "openid profile" scopes, and the other uses one scope defined by the specific api to be consumed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ID token request
export const loginRequest = {
    scopes: ["openid", "profile", "User.Read"],
    forceRefresh: false // Set this to "true" to skip a cached token and go to the server to get a new token
};

// Access token request.
export const apiRequest = {
    scopes: ["api://{API ID}/ReadWrite"],
    forceRefresh: false 
}
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The entry point for using the new msal browser library is the PublicClientApplication object, which receives the configuration for connecting to Azure AD as part of the constructor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const config = {
    auth: {
        clientId: "{CLIENT ID}",
        authority: 'https://login.microsoftonline.com/{TENANT ID}',
        redirectUri: 'http://localhost:3000/',
    },
    cache: {
        cacheLocation: "localStorage", // This configures where your cache will be stored
        storeAuthStateInCookie: false, // Set this to "true" if you are having issues on IE11 or Edge


};
}

const pc = new msal.PublicClientApplication(config);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The following component shows how the context provider is imported and used to log in/out the user with two different buttons.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const Welcome = () =&amp;gt; {
  const { user, logout, getToken, token, loginError } = useMsal();


  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;Welcome {user.userName}&amp;lt;/h1&amp;gt;
      {token &amp;amp;&amp;amp; (&amp;lt;span&amp;gt;Your token is {token}&amp;lt;/span&amp;gt;)}
      &amp;lt;br&amp;gt;&amp;lt;/br&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; getToken(apiRequest, "loginPopup")}&amp;gt;Get Token&amp;lt;/button&amp;gt;
      &amp;lt;br&amp;gt;&amp;lt;/br&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; logout()}&amp;gt;Log out&amp;lt;/button&amp;gt;
      &amp;lt;br&amp;gt;&amp;lt;/br&amp;gt;
      {loginError &amp;amp;&amp;amp; (&amp;lt;span&amp;gt;Error: {loginError.message}&amp;lt;/span&amp;gt;)}
    &amp;lt;/div&amp;gt;
  );
};


export default Welcome;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Full source code for this sample&lt;/p&gt;

&lt;p&gt;The full source code for this context provider and sample is available in &lt;a href="https://github.com/pcibraro/msal-browser-react"&gt;Github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;﻿&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Role Based Authentication for .NET Core APIs with Auth0</title>
      <dc:creator>Cibrax</dc:creator>
      <pubDate>Thu, 22 Jul 2021 12:25:07 +0000</pubDate>
      <link>https://dev.to/cibrax/role-based-authentication-for-net-core-apis-with-auth0-46j2</link>
      <guid>https://dev.to/cibrax/role-based-authentication-for-net-core-apis-with-auth0-46j2</guid>
      <description>&lt;p&gt;Auth0 offers two alternatives for implementing authorization in an API, scopes and roles.&lt;/p&gt;

&lt;p&gt;Scopes represent access levels that an API exposes and users can grant to client applications on his/her behalf. For example, "read emails" or "write calendar", which gives a client application permissions to read the user's emails o write the calendar. &lt;/p&gt;

&lt;p&gt;On other hand, roles represent the old school for doing authorization. Users are assigned to roles that represent one or more permissions. Those permissions are passed to the API when the user invokes it through a client application. In Auth0, roles are configured through a feature called &lt;a href="https://auth0.com/docs/authorization/rbac/" rel="noopener noreferrer"&gt;Role Based Access Control&lt;/a&gt; or RBAC in short.&lt;/p&gt;

&lt;p&gt;It is worth mentioning that only scopes are mentioned as part of the OAuth 2.0 specification, and roles are usually implemented in proprietary ways by different vendors. As Auth0 uses JWT for representing access tokens, it relies on extension attributes for injecting the permissions for a role into the tokens. We will cover this more in detail later in this post.&lt;/p&gt;

&lt;p&gt;For the API, we will use the one included as template with Visual Studio for .NET Core that returns the weather forecast.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating an API in Auth0
&lt;/h2&gt;

&lt;p&gt;First step before jumping into any API implementation is to configure the API in the Auth0 dashboard. &lt;/p&gt;

&lt;p&gt;Go the APIs and click on Create API&lt;/p&gt;

&lt;p&gt;&lt;a href="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%2Farticles%2Fr8h3iwenugdn4jnhujqm.png" class="article-body-image-wrapper"&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%2Farticles%2Fr8h3iwenugdn4jnhujqm.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Under the settings tab, configure the following fields.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Name&lt;/strong&gt;, a friendly name or description for the API. Enter *&lt;em&gt;Weather Forecast API&lt;/em&gt; for this sample.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Identifier&lt;/strong&gt; or &lt;strong&gt;Audience&lt;/strong&gt;, which is a identifier that client application uses to request access tokens for the API. Enter &lt;strong&gt;&lt;a href="https://weatherforecast" rel="noopener noreferrer"&gt;https://weatherforecast&lt;/a&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Under RBAC settings, enable &lt;strong&gt;RBAC&lt;/strong&gt; and &lt;strong&gt;Add Permissions&lt;/strong&gt; in the Access Tokens**. This will be used by Auth0 to inject the user's permissions into the access tokens.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Under the permissions tab, add a new permission &lt;strong&gt;read-weather&lt;/strong&gt; with a description &lt;strong&gt;It allows getting the weather forecast&lt;/strong&gt;. This is the permission that Auth0 will inject in the JWT token if the user is member of any of the roles that are allowed to execute that operation. &lt;/p&gt;

&lt;p&gt;Finally, click on the Save button to save the changes. At this point, our API is ready to be used from .NET Core.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding a new role in Auth0
&lt;/h2&gt;

&lt;p&gt;Under User &amp;amp; Roles, click on &lt;strong&gt;Create Role&lt;/strong&gt; to define a new Role for our API.&lt;/p&gt;

&lt;p&gt;&lt;a href="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%2Farticles%2F5kqyctin317vqe980806.png" class="article-body-image-wrapper"&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%2Farticles%2F5kqyctin317vqe980806.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the *&lt;em&gt;Settings&lt;/em&gt; tab, enter *&lt;em&gt;meteorologist&lt;/em&gt; as role name and description.&lt;/p&gt;

&lt;p&gt;On the &lt;strong&gt;Permissions&lt;/strong&gt; tab, click on &lt;strong&gt;Add Permissions&lt;/strong&gt;, select our  &lt;strong&gt;Weather Forecast API* from the dropdown, and **read-weather&lt;/strong&gt; as permission. Click on *&lt;em&gt;Add Permissions&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Assign the role to existing users
&lt;/h2&gt;

&lt;p&gt;As final step for the API configuration in Auth0, we need to assign the &lt;strong&gt;meteorologist&lt;/strong&gt; role to any of the users you will be using for testing the API. If you do not have one yet, you will have to create it and assign it to this role.&lt;br&gt;
Roles are assigned by clicking on the ellipsis button &lt;strong&gt;...&lt;/strong&gt; available on each user in the list, and selecting &lt;strong&gt;Assign Roles&lt;/strong&gt; option from the displayed menu.&lt;/p&gt;
&lt;h2&gt;
  
  
  Anatomy of the JWT access token
&lt;/h2&gt;

&lt;p&gt;If everything is configured correctly, any access token issued by Auth0 for our API should look like the one below,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"iss"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://....us.auth0.com/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sub"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"auth0|..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"aud"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://weatherforecast"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"iat"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1621346933&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"exp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1621354133&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"azp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"nW5WUNks1eQgHZB0oyc9183NNILpsWMe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scope"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"permissions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"read:weather"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Scopes are not required when requesting an access token for an API configured with RBAC. Only the audience must be passed to Auth0, which is &lt;a href="https://weatherforecast" rel="noopener noreferrer"&gt;https://weatherforecast&lt;/a&gt; in our sample.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Create the ASP.NET Core API in Visual Studio
&lt;/h2&gt;

&lt;p&gt;Visual Studio ships with a single template for .NET Core APIs. That is &lt;strong&gt;ASP.NET Core Web API&lt;/strong&gt; as it is shown in the image below.&lt;/p&gt;

&lt;p&gt;&lt;a href="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%2Farticles%2Fgd1m3cxavzchs5quk2nb.png" class="article-body-image-wrapper"&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%2Farticles%2Fgd1m3cxavzchs5quk2nb.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The structure of the project
&lt;/h3&gt;

&lt;p&gt;Projects created with that template from Visual Studio will have the following structure.&lt;/p&gt;

&lt;p&gt;&lt;a href="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%2Farticles%2Fp7h2sz4xvf11ojczcf7w.png" class="article-body-image-wrapper"&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%2Farticles%2Fp7h2sz4xvf11ojczcf7w.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Controllers, this folder contains the controllers for the API implementation.&lt;/li&gt;
&lt;li&gt;Startups.cs, this is the main class where the ASP.NET Core Middleware classes are configured as well as the dependency injection container.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Configuring the project
&lt;/h3&gt;

&lt;p&gt;Our application will only use a middleware for supporting authentication with JWT as bearer tokens.&lt;/p&gt;

&lt;p&gt;Open the Package Manager Console for Nuget in Visual Studio and run the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Install-Package Microsoft.AspNetCore.Authentication.JwtBearer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the Nuget packages are installed in our project, we can go ahead and configure them in the Startup.cs class.&lt;/p&gt;

&lt;p&gt;Modify the ConfigureServices method in that class to include the following code.&lt;br&gt;
&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;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ConfigureServices&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IServiceCollection&lt;/span&gt; &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;authentication&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;services&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddAuthentication&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;JwtBearerDefaults&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AuthenticationScheme&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddJwtBearer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Bearer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Authority&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;$"https://&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Auth0:Domain"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TokenValidationParameters&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;TokenValidationParameters&lt;/span&gt;
       &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="n"&gt;ValidateAudience&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="n"&gt;ValidAudiences&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Auth0:Audience"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;Split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;";"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
         &lt;span class="n"&gt;ValidateIssuer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="n"&gt;ValidIssuer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;$"https://&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Auth0:Domain"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddControllers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

   &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddSwaggerGen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
   &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SwaggerDoc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"v1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;OpenApiInfo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Title&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Api"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"v1"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
   &lt;span class="p"&gt;});&lt;/span&gt;

   &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddAuthorization&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
   &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddPolicy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"read-weather"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;policy&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; 
       &lt;span class="n"&gt;policy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RequireClaim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"permissions"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"read:weather"&lt;/span&gt;&lt;span class="p"&gt;));&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;This code performs two things. It configures the JWT middleware to accept access tokens issued by Auth0, and an authorization policy for checking the permissions set on the token. &lt;br&gt;
The policy checks for a claim or attribute called &lt;strong&gt;permissions&lt;/strong&gt; with a value &lt;strong&gt;read:weather&lt;/strong&gt;, which is the permission we previously configured for our API in the Auth0 dashboard.&lt;br&gt;
The middleware configuration relies on some settings that we will configure later in the appSettings.json file associated to the application.&lt;/p&gt;

&lt;p&gt;Next step is to modify the Configure method to tell ASP.NET Core that we want to use the Authentication And Authorization Middleware. &lt;/p&gt;

&lt;p&gt;Insert the following code as it shown below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
  app.UseRouting();

  app.UseAuthentication();

  app.UseAuthorization();

...
  app.UseEndpoints(endpoints =&amp;gt;
  {
    endpoints.MapControllers();
  });
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a new appSettings.json file and include the settings we got from the Auth0 dashboard before. Those are Domain, and API's Audience.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "Logging": {
      "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
      }
    },
  "AllowedHosts": "*",
  "Auth0": {
    "Domain": "&amp;lt;domain&amp;gt;",
    "Audience": "https://weatherforecast"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Require authentication in other controllers
&lt;/h3&gt;

&lt;p&gt;The WeatherForecast controller included in the template allows anonymous calls. We will convert it to require authenticated calls. Fortunately, that is as simple as adding a top level [Authorize] attribute in the class definition. That attribute will also reference the policy we previously defined in the Startup.cs file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ApiController&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[controller]"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WeatherForecastController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ControllerBase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;HttpGet&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Authorize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"read-weather"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;WeatherForecast&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Get&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;This attribute will do two things,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It will activate the Authorization Middleware that will check if the call was authenticated and there is one user identity set in the current execution context.&lt;/li&gt;
&lt;li&gt;It will run the &lt;strong&gt;read-weather&lt;/strong&gt; policy to make sure the user identity contains the required permissions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once we ran this project in Visual Studio, the API will only accept authenticated calls with JWT tokens coming from Auth0.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;We discussed two of the authorization alternatives available for you in Auth0 when implementing an API in .NET core, and selected &lt;strong&gt;RBAC&lt;/strong&gt; for our sample. We also showed how to configure the ASP.NET Core Middleware for Authentication and Authorization, and how to use Authorization Policies for checking permissions on the JWT bearer tokens. &lt;br&gt;
In a next post, we will see how to implement a client application that negotiates access tokens from Auth0 to consume this API.&lt;/p&gt;

</description>
      <category>netcore</category>
      <category>oauth</category>
      <category>webapi</category>
      <category>auth0</category>
    </item>
    <item>
      <title>Developing a Dapp in Ethreum with Social Authentication using Next.js and Next-Auth-js</title>
      <dc:creator>Cibrax</dc:creator>
      <pubDate>Thu, 22 Jul 2021 12:21:40 +0000</pubDate>
      <link>https://dev.to/cibrax/developing-a-dapp-in-ethreum-with-social-authentication-using-next-js-and-next-auth-js-1p8f</link>
      <guid>https://dev.to/cibrax/developing-a-dapp-in-ethreum-with-social-authentication-using-next-js-and-next-auth-js-1p8f</guid>
      <description>&lt;h1&gt;
  
  
  Developing a Dapp in Ethreum with Social Authentication using Next.js and Next-Auth-js
&lt;/h1&gt;

&lt;p&gt;My last article &lt;a href="https://auth0.com/blog/101-smart-contracts-and-decentralized-apps-in-ethereum/"&gt;101 Smart Contracts and Decentralized Apps in Ethereum&lt;/a&gt; discussed all the introductory concepts for developing Smart Contracts and Decentralized Applications in Ethreum. &lt;/p&gt;

&lt;p&gt;This article is focused on implementing a concrete sample that includes Smart Contracts and a Decentralized Application (DApp) written with Next.js.&lt;/p&gt;

&lt;p&gt;The smart contracts in this article include a custom ERC-20 token and a Faucet. Don't worry if you don't know what those are. I am planning to give a short overview first.&lt;/p&gt;

&lt;h2&gt;
  
  
  ERC-20
&lt;/h2&gt;

&lt;p&gt;The acronym ERC stands for Ethereum Request for Comments. Those are Application-Level standards and conventions for Smart Contract development in Ethereum. They are available &lt;a href="https://eips.ethereum.org/erc"&gt;here&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Any new standard related to Smart Contract development (e.g., new tokens, wallet formats) is proposed through an ERC draft and eventually approved and released on that site.&lt;/p&gt;

&lt;p&gt;ERC-20 is the standard for fungible tokens. Fungibility is the ability of an asset to be interchanged for another of the same type. If you have a token of the type "FOO", you can change it for another of the same type without losing any value. &lt;/p&gt;

&lt;p&gt;If you look into the specification, it is no other thing than an interface for a smart contract that represents a fungible token.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function name() public view returns (string)
function symbol() public view returns (string)
function decimals() public view returns (uint8)
function totalSupply() public view returns (uint256)
function balanceOf(address _owner) public view returns (uint256 balance)
function transfer(address _to, uint256 _value) public returns (bool success)
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success)
function approve(address _spender, uint256 _value) public returns (bool success)
function allowance(address _owner, address _spender) public view returns (uint256 remaining)

event Transfer(address indexed _from, address indexed _to, uint256 _value)
event Approval(address indexed _owner, address indexed _spender, uint256 _value)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Suppose you take a Smart Contract and implement those methods using Solidity or any other language compatible with the Ethereum VM. In that case, your contract will adhere to the ERC-20 standard and can be considered a token.&lt;/p&gt;

&lt;p&gt;Let's discuss those methods more in detail.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function name() public view returns (string)
function symbol() public view returns (string)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;name and symbol are the name and symbol associated with the token. For example, a token "My Foo Token" with the symbol "FOO".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function decimals() public view returns (uint8)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ethereum does not support decimals for amounts. Decimals is a workaround to express how many decimal positions a token supports. For example, 18 would mean a single token uses 18 zeros (1000000000000000000)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function totalSupply() public view returns (uint256)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It returns the total number/supply of available tokens.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function balanceOf(address _owner) public view returns (uint256 balance)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It returns the balance for a given address.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function transfer(address _to, uint256 _value) public returns (bool success)
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These two allow transferring tokens from one address to another.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function approve(address _spender, uint256 _value) public returns (bool success)
function allowance(address _owner, address _spender) public view returns (uint256 remaining)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Approve allows allocating/lending some tokens to a third party (a different address, the spender). The owner of those tokens is taken from the sender address when the smart contract is invoked. This method is what we will use for our Faucet contract.&lt;br&gt;
The other method, allowance returns the number of tokens allocated/lent to a given address by the owner. &lt;/p&gt;

&lt;p&gt;As you can see, a fungible token never leaves this contract. The available supply and owners are all reflected and stored on it.&lt;/p&gt;
&lt;h2&gt;
  
  
  Minting vs. Mining
&lt;/h2&gt;

&lt;p&gt;Minting and Mining are two terms often mention when talking about token issuance. &lt;br&gt;
ERC-20 are not native tokens in the ETH Blockchain; smart contracts represent them, so you can not obtain those as part of the mining process. You can only mine Ether.&lt;br&gt;
On the other hand, minting is about issuing ERC-20 tokens, and it's usually part of the internal implementation of the smart contract. The initial supply can probably be minted in the Smart Contract constructor and updated later by other methods.&lt;/p&gt;
&lt;h2&gt;
  
  
  A sample token
&lt;/h2&gt;

&lt;p&gt;As part of this article, I decided to implement a fictitious token called "Cibrax". Here is the code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// SPDX-License-Identifier: MIT

pragma solidity ^0.8.4;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract CibraxToken is ERC20 {
    constructor(uint256 initialSupply) ERC20("Cibrax", "CIBRAX") {
        _mint(msg.sender, initialSupply);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There isn't much to show here. I borrowed the ERC20 contract implementation from OpenZepellin and used that one as the base class for my contract. OpenZepellin distributes the contracts as a library via &lt;a href="https://www.npmjs.com/package/@openzeppelin/contracts"&gt;NPM&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;You provide the token name and symbol as part of the constructor and call the base method _mint to specify the initial supply. My implementation takes the initial supply from the constructor when you run the initial deployment. Also, the default value for decimals is 18, but you can optionally override that one too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Faucet
&lt;/h2&gt;

&lt;p&gt;You might need tokens for paying gas or for any other operation in smart contracts. When you are in a production Blockchain, you can buy those or get them as rewards/fees from mining blocks. However, it does not make much sense to do the same in a testing network. Those networks provide Faucets, which are smart contracts for borrowing tokens.  There is no standard for the implementation of a Faucet. &lt;br&gt;
Here is a Faucet I implemented for the sample included with this article.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// SPDX-License-Identifier: MIT

pragma solidity ^0.8.4;

import "@openzeppelin/contracts/access/Ownable.sol";

interface ERC20 {
    function transfer(address to, uint256 value) external returns (bool);
    function name() view external returns (string memory);
    event Transfer(address indexed from, address indexed to, uint256 value);
}

contract Faucet is Ownable {
    uint256 constant public waitTime = 30 minutes;

    ERC20 public tokenInstance;

    mapping(address =&amp;gt; uint256) lastAccessTime;

    constructor(address _tokenInstance) Ownable() {
        require(_tokenInstance != address(0));

        tokenInstance = ERC20(_tokenInstance);
    }

    function requestTokens(address _receiver, uint256 tokenAmount) onlyOwner public {
        require(allowedToWithdraw(_receiver, tokenAmount));
        tokenInstance.transfer(_receiver, tokenAmount);
        lastAccessTime[_receiver] = block.timestamp + waitTime;
    }

    function allowedToWithdraw(address _address, uint256 tokenAmount) public view returns (bool) {
        if(tokenAmount &amp;gt; 3) {
            return false;
        }

        if(lastAccessTime[_address] == 0) {
            return true;
        } else if(block.timestamp &amp;gt;= lastAccessTime[_address]) {
            return true;
        }

        return false;
    }

    function tokenName() public view returns (string memory) {
        return tokenInstance.name();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This contract works like a private Faucet, as only the owner can transfer tokens to other addresses. I did this on purpose, so we can assign our Dapp as owner of the Faucet and only allow transferring tokens from it.  If someone wants to bypass the Dapp and send a transaction to this Smart Contract, it will be rejected.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;contract Faucet is Ownable {
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The contract inherits from the Ownable Smart Contract implementation from OpenZeppelin. This contract gives you access to a "onlyOwner" condition for methods, which means only the assigned owner can be invoke them. In our scenario, the Dapp will be the assigned owner.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;constructor(address _tokenInstance) Ownable() {
        require(_tokenInstance != address(0));

        tokenInstance = ERC20(_tokenInstance);
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The constructor ties the Faucet to any Smart Contract implementation that provides a ERC20 interface. In our example, we will assign our Cibrax token. You provide the address of the ERC20 contract, which can not be the empty address (address(0)) for deploying new contracts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; function allowedToWithdraw(address _address, uint256 tokenAmount) public view returns (bool) {
        if(tokenAmount &amp;gt; 3) {
            return false;
        }

        if(lastAccessTime[_address] == 0) {
            return true;
        } else if(block.timestamp &amp;gt;= lastAccessTime[_address]) {
            return true;
        }

        return false;
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It checks for different conditions before any token is giving away. You can not ask for more than three tokens or do multiple calls within 30 minutes. These are vague conditions, but it shows a purpose. They prevent someone from exhausting all your available tokens.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing our Smart Contracts
&lt;/h2&gt;

&lt;p&gt;I decided to use the &lt;a href="https://hardhat.org/getting-started/"&gt;HardHat&lt;/a&gt; tools to compile, test the contracts, and deploy them in an emulator. &lt;/p&gt;

&lt;p&gt;Hardhat uses ethers.js as the client library for connecting to a local ETH node, and Waffle as the testing framework.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;describe("CibraxToken", function () {

    let owner, addr1, addr2, addr3, addr4, addr5;
    let CibraxToken, cibraxToken;
    let Faucet, faucet;

    before(async function() {
        [owner, addr1, addr2, addr3, addr4, addr5] = await ethers.getSigners();

        CibraxToken = await ethers.getContractFactory("CibraxToken");
        cibraxToken = await CibraxToken.deploy(1000);

        await cibraxToken.deployed();

        Faucet = await ethers.getContractFactory("Faucet");
        faucet = await Faucet.deploy(cibraxToken.address);

        await faucet.deployed();

        await cibraxToken.transfer(faucet.address, 500);
    });

    it("Deployment should assign a name", async function () {
        const name = await cibraxToken.name();
        expect(name).to.equal("Cibrax");
    });

    it("Deployment should assign a symbol", async function () {
        const name = await cibraxToken.symbol();
        expect(name).to.equal("CIBRAX");
    });

    it("Owner can transfer tokens", async function () {
        const amount = 100;

        const tx = await cibraxToken.transfer(addr1.address, amount)        ;

        const receipt = await tx.wait();

        const otherBalance = await cibraxToken.balanceOf(addr1.address);

        expect(amount).to.equal(otherBalance);
        expect(receipt.events?.filter((x) =&amp;gt; {return x.event == "Transfer"})).to.not.be.null;
    });

    it("Faucet can transfer assigned tokens", async function () {
        const amount = 1;

        await faucet.requestTokens(addr3.address, amount);

        const balance = await cibraxToken.balanceOf(addr3.address);

        expect(amount).to.equal(balance);
    });

    it("Faucet returns token name", async function () {

        const name = await faucet.tokenName();
        expect(name).to.equal("Cibrax");

    });

    it("Faucet can not transfer more than assigned tokens", async function () {

        await expect(faucet.requestTokens(addr4.address, 5)).to.be.reverted;

    });

    it("Faucet can not transfer on consecutive calls", async function () {
        const amount = 1;

        await faucet.requestTokens(addr4.address, amount);

        await expect(faucet.requestTokens(addr4.address, amount)).to.be.reverted;

    });

    it("Faucet can transfer allowed tokens", async function () {

        const allowedAmount = 5;
        const amount = 1;

        await cibraxToken.approve(faucet.address, allowedAmount);

        await faucet.requestTokens(addr5.address, amount);

        const balance = await cibraxToken.balanceOf(addr5.address);

        expect(amount).to.equal(balance);
    });

});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The "before" method is used for test initialization. It deploys the ERC-20 and Faucet contracts, and obtains their address. The other methods describe the tests.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; it("Faucet can transfer allowed tokens", async function () {

        const allowedAmount = 5;
        const amount = 1;

        await cibraxToken.approve(faucet.address, allowedAmount);

        await faucet.requestTokens(addr5.address, amount);

        const balance = await cibraxToken.balanceOf(addr5.address);

        expect(amount).to.equal(balance);
    });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, the test above uses the "approve" method in our custom token to pre-assign or authorize some tokens to the Faucet (five tokens in total). To be clear, the tokens are not directly assigned to the Faucet, but it allows the Faucet to use them.&lt;br&gt;
The Faucet later transfers one of those tokens to a ETH address (addr5), and the balance on that address is verified.&lt;/p&gt;

&lt;p&gt;For compiling the contracts and running the tests, you can run these commands in a console.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx hardhat compile
npx hardhat test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Dapp
&lt;/h2&gt;

&lt;p&gt;The Decentralized App or DApp, in short, it's the visible layer for our Faucet. &lt;/p&gt;

&lt;p&gt;It's implemented in Next.js and leverages Next-Auth.js for authentication with social providers.&lt;/p&gt;

&lt;p&gt;The .env file is used to assign the address of the Faucet and private key to our application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ETH_NODE_URL=http://127.0.0.1:8545/
ETH_FAUCET_ADDRESS=&amp;lt;address&amp;gt;
ETH_PRIVATE_KEY=&amp;lt;private key&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to deploy the contracts in the local Hardhat emulator, you can run the script "cibraxtoken-deploy.js" under contracts/scripts. That script will return the address of the contracts. Also, Hardhat always uses the first address from the available accounts in the emulator for deploying the contracts, so you can take the private key from that account and configure it in the Next.js app.&lt;/p&gt;

&lt;h3&gt;
  
  
  User authentication
&lt;/h3&gt;

&lt;p&gt;The main page in our application uses the Next-Auth.js react hooks for coordinating the sign-on process.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import Head from 'next/head'
import { TokenForm } from './components/TokenForm';
import { signIn, signOut, useSession } from 'next-auth/client'

export default function Home() {

  const [ session ] = useSession()

  return (
    &amp;lt;div className="flex flex-col items-center justify-center min-h-screen py-2"&amp;gt;
      &amp;lt;Head&amp;gt;
        &amp;lt;title&amp;gt;Faucet with Social Auth&amp;lt;/title&amp;gt;
        &amp;lt;link rel="icon" href="/favicon.ico" /&amp;gt;
      &amp;lt;/Head&amp;gt;

      &amp;lt;main className="flex flex-col items-center justify-center w-full flex-1 px-20 text-center"&amp;gt;
      &amp;lt;p className="mt-3 text-2xl"&amp;gt;

        You can use this Faucet to request Cibrax tokens
      &amp;lt;/p&amp;gt;

      {session &amp;amp;&amp;amp; &amp;lt;TokenForm session={session}/&amp;gt;}

      &amp;lt;p className="mt-3 text-2xl"&amp;gt;
        {(session) ? 
          &amp;lt;button onClick={() =&amp;gt; signOut()} className="shadow bg-blue-500 hover:bg-blue-400 focus:shadow-outline focus:outline-none text-white font-bold py-2 px-4 rounded"&amp;gt;Logout&amp;lt;/button&amp;gt; : 
          &amp;lt;button onClick={() =&amp;gt; signIn()} className="shadow bg-blue-500 hover:bg-blue-400 focus:shadow-outline focus:outline-none text-white font-bold py-2 px-4 rounded"&amp;gt;Login&amp;lt;/button&amp;gt;
        }

    &amp;lt;/p&amp;gt;  
      &amp;lt;/main&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The useSession hook returns the existing user session if there is one. If no session is available, we can display the Login button and assign the signIn hook to it. This method will do the sign-on handshake with the social providers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Smart Contract Calls
&lt;/h3&gt;

&lt;p&gt;The integration with the Smart Contract is done server-side through an API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import type { TransactionResponse } from '../types'
import type { NextApiRequest, NextApiResponse } from 'next'
import { getSession } from "next-auth/client"
import { ethers } from 'ethers';

import artifact from '../../contracts/Faucet.json';

const url = process.env.ETH_NODE_URL;
const privateKey = process.env.ETH_PRIVATE_KEY || "";
const faucetAddress = process.env.ETH_FAUCET_ADDRESS || "";

const provider = new ethers.providers.JsonRpcProvider(); 

const wallet = new ethers.Wallet(privateKey, provider);
const faucet = new ethers.Contract(faucetAddress, artifact.abi, wallet);

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse&amp;lt;TransactionResponse&amp;gt;
) {

  const session = await getSession({ req })

  if(!session) {
    res.status(401);
    return;
  }

  if(!req.body.address) {
    res.status(400);
    return;
  }

  await faucet.requestTokens(req.body.address, 1, {
    gasPrice: 25e9
  });

  res.status(200).json({ successful: true })
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This API does two things,&lt;br&gt;
It connects the Faucet contract using ether.js. The settings for connecting to the node are retrieved from the .env file. &lt;br&gt;
It checks the user session from Next-Auth.js. If the user is not authenticated, it returns 401. Otherwise, it makes a call to the Faucet to transfer tokens.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get and Run the code
&lt;/h2&gt;

&lt;p&gt;The complete sample is available to download from this Github repository - &lt;a href="https://github.com/pcibraro/social-faucet"&gt;social-faucet&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
