<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Julien Genestoux</title>
    <description>The latest articles on Forem by Julien Genestoux (@julien51).</description>
    <link>https://forem.com/julien51</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%2F41239%2F400fcc4a-8ce8-42dd-8b1f-df619a981d5f.jpeg</url>
      <title>Forem: Julien Genestoux</title>
      <link>https://forem.com/julien51</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/julien51"/>
    <language>en</language>
    <item>
      <title>🔐 Creating a Crypto Token Gated Express application</title>
      <dc:creator>Julien Genestoux</dc:creator>
      <pubDate>Wed, 03 Nov 2021 13:34:48 +0000</pubDate>
      <link>https://forem.com/julien51/creating-a-crypto-token-gated-express-application-1i62</link>
      <guid>https://forem.com/julien51/creating-a-crypto-token-gated-express-application-1i62</guid>
      <description>&lt;p&gt;Web3 encompasses a plethora of elements that empower us to build a more accessible web for everyone -- including Non-Fungible-Tokens, Token Gating, and decentralization. One perk from the emergence of web3 is moving away from the monetization of our personal data to sell ads. Win-win for us all!&lt;/p&gt;

&lt;p&gt;I'm here to show you how simple the process is for token gating content in an Express.js application using the &lt;a href="https://unlock-protocol.com/" rel="noopener noreferrer"&gt;Ʉnlock Protocol&lt;/a&gt;. Ʉnlock is a protocol for memberships that allows anyone to deploy a "lock" (a membership smart contract). The contract specifies the &lt;em&gt;terms&lt;/em&gt; of the membership: including price, duration, number of members, and many more parameters necessary to run a thriving membership subscription. When a supporter wants to join your membership, they simply pay the specified amount to the contract and will receive an NFT that represents the purchased membership.&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;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/premium&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;membersOnly&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&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;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ... unchanged&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;TL;DR: that's all you need to monetize your application!&lt;br&gt;
&lt;a href="http://locked-time.herokuapp.com/" rel="noopener noreferrer"&gt;Try it&lt;/a&gt; | &lt;a href="https://github.com/julien51/locked-time" rel="noopener noreferrer"&gt;Code&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🚀 Let's get started!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Requirements&lt;/em&gt;: you need to use an ethereum/web3 wallet such as &lt;a href="https://metamask.io/" rel="noopener noreferrer"&gt;MetaMask&lt;/a&gt;. We will be using a the Rinkeby test network for this tutorial (no need to spend &lt;em&gt;real&lt;/em&gt; money, get some fake Ether &lt;a href="https://faucet.rinkeby.io/" rel="noopener noreferrer"&gt;on this faucet&lt;/a&gt;), and when you decide to ship, you can use Ethereum's mainnet, or the &lt;a href="https://unlock-protocol.com/blog/xdai" rel="noopener noreferrer"&gt;xDAI&lt;/a&gt; and &lt;a href="https://unlock-protocol.com/blog/unlock-on-polygon" rel="noopener noreferrer"&gt;Polygon&lt;/a&gt; networks if you want to skip the high gas fees.&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%2Fgithub.com%2Funlock-protocol%2Funlock%2Fblob%2Fmaster%2Fdesign%2Fbrand%2FPNG%2FUnlock-LogoMark-Circle.png%3Fraw%3Dtrue" 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%2Fgithub.com%2Funlock-protocol%2Funlock%2Fblob%2Fmaster%2Fdesign%2Fbrand%2FPNG%2FUnlock-LogoMark-Circle.png%3Fraw%3Dtrue"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Deploying a lock 🔒
&lt;/h2&gt;

&lt;p&gt;This is the first step. Unlock Inc provides a front-end for this to be a bit easier, but know that you could also do it directly from the smart contracts.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://app.unlock-protocol.com/dashboard" rel="noopener noreferrer"&gt;Go to the Unlock Dashboard&lt;/a&gt;. Connect your wallet and then click on the "Create Lock" button.&lt;/p&gt;

&lt;p&gt;You can then complete the form to specify the name of your membership contract, the duration (in days) of each membership, the amount of members, as well as the price for each membership.&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%2F8awt3uzh2vnpdkwflcr5.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%2F8awt3uzh2vnpdkwflcr5.png" alt="Dashboard Example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clicking on "Submit" will prompt you to submit a transaction that will deploy your lock! It usually does not take much more than a few seconds but you will be able to see the address of your lock right away. This is the address of the smart contract you just deployed! It is yours, and only yours.&lt;/p&gt;

&lt;p&gt;The one I deployed is called "Another Lock", and its memberships are valid for 1 day, and they cost 0.001 Ether. It is at the address &lt;code&gt;0x32BeC8e1Fc72509fFa115bd6a0f064Ec77319E4A&lt;/code&gt; and we can &lt;a href="https://rinkeby.etherscan.io/address/0x32BeC8e1Fc72509fFa115bd6a0f064Ec77319E4A" rel="noopener noreferrer"&gt;inspect it on Etherscan&lt;/a&gt;.&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%2Fliqijhj24miky8dpz7vk.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%2Fliqijhj24miky8dpz7vk.png" alt="Deployed Lock"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The side bar shows lets you enable credit cards 💳 (for users who do not have a crypto wallet, withdraw its funds, and more... feel free to tinker with it!)&lt;/p&gt;
&lt;h2&gt;
  
  
  Express application for date and times
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;If you're familiar with Express, you won't learn much so skip to next section!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For this demo, I created a dummy &lt;a href="https://expressjs.com/" rel="noopener noreferrer"&gt;Express&lt;/a&gt; application that gives the time ⏰ in all timezones. The "free" version just includes 4 cities around the world, but the premium version offers a list of 457 cities!&lt;/p&gt;

&lt;p&gt;Here is how the code looks like:&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;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&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;cookieParser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cookie-parser&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;zones&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./zones&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;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&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;port&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;PORT&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cookieParser&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="c1"&gt;// Helper function that returns date as a string in a city&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dateInZone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;zone&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="p"&gt;)&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;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLocaleString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en-US&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;timeZone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;zone&lt;/span&gt; &lt;span class="p"&gt;})}&lt;/span&gt;&lt;span class="s2"&gt; in &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;city&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="c1"&gt;// Main root of the application that only shows 4 cities&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&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="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&amp;lt;h1&amp;gt;World Clocks&amp;lt;/h1&amp;gt;
  &amp;lt;p&amp;gt;It is now: &amp;lt;/p&amp;gt;
  &amp;lt;ul&amp;gt;
    &amp;lt;li&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;dateInZone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Asia/Tokyo&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;Tokyo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;dateInZone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Asia/Kolkata&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;Kolkata&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;dateInZone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Europe/Paris&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;Paris&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;dateInZone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;America/New_York&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;New York&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/li&amp;gt;
  &amp;lt;/ul&amp;gt;
  &amp;lt;p&amp;gt;Premium version: &amp;lt;a href="/premium"&amp;gt;select any time zone&amp;lt;/a&amp;gt;!&amp;lt;/p&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// Premium route where times in all timezones are displayed!&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/premium&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="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&amp;lt;h1&amp;gt;World Clocks&amp;lt;/h1&amp;gt;
  &amp;lt;p&amp;gt;Thank you for your support!&amp;lt;/p&amp;gt;
  ... (check github for code that renders all zones!)
  &amp;lt;p&amp;gt;Premium version: select any time zone!&amp;lt;/p&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&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="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="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Example app listening at http://localhost:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;port&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="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see it is a pretty standard Express application. The list of zones is stored in &lt;code&gt;zones.js&lt;/code&gt; file that you can &lt;a href="https://github.com/julien51/locked-time/blob/master/zones.js" rel="noopener noreferrer"&gt;find on the repo&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding the lock
&lt;/h2&gt;

&lt;p&gt;There are multiple ways to &lt;a href="https://docs.unlock-protocol.com/developers/unlock-platform" rel="noopener noreferrer"&gt;integrate Ʉnlock in application&lt;/a&gt;, from the lowest levels by hooking into smart contracts directly, all the way to the front-end where some JavaScript can be used to hide/show content. &lt;/p&gt;

&lt;p&gt;Here we will use the &lt;code&gt;@unlock-protocol/unlock-express&lt;/code&gt; npm module. This module provides a middleware that can be added to any Express route in order to ensure that members only can indeed access the content.&lt;/p&gt;

&lt;p&gt;Add the plugin through &lt;code&gt;yarn add @unlock-protocol/unlock-express&lt;/code&gt; or &lt;code&gt;npm i --save @unlock-protocol/unlock-express&lt;/code&gt;, and then let's include it in our application:&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;configUnlock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@unlock-protocol/unlock-express&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;p&gt;After this, it's just a matter of configuring the express and using the middleware. The configuration has 3 important elements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;yieldPaywallConfig&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;getUserEthereumAddress&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;updateUserEthereumAddress&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's go through them one by one.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;yieldPaywallConfig&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This one is used by the plugin to ask the application what configuration it should use. The main aspect of this is of course to list what "locks" should be used specifically. You can find more details &lt;a href="https://docs.unlock-protocol.com/developers/paywall/configuring-checkout#the-paywallconfig-object" rel="noopener noreferrer"&gt;in the Unlock docs&lt;/a&gt;, but here is what we'll use:&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;yieldPaywallConfig&lt;/span&gt;&lt;span class="p"&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="o"&gt;=&amp;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="na"&gt;locks&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="s1"&gt;0x32BeC8e1Fc72509fFa115bd6a0f064Ec77319E4A&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;network&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&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="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;Quite simply, we say that we only have a single lock that we accept memberships from and it is on the network &lt;code&gt;4&lt;/code&gt; (the Rinkeby test network).&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;getUserEthereumAddress&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This one is a way for the middleware to ask the application for the user's Ethereum address, if it knows about it. Here for example, the application could look up its user database and just yield the address of the user... etc. However, in this example, we do not have a user database/table, so we will only use a cookie. So here is what that looks like:&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;getUserEthereumAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &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="o"&gt;=&amp;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;request&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="nx"&gt;userAddress&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;updateUserEthereumAddress&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Finally, the middleware has a way to inform the application of the user's wallet address, so that the application can store it. There again, the application could decide to store that information in a database or, like we do it here, just store the address in a 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="nx"&gt;updateUserEthereumAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &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;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;address&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;userAddress&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;address&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;And that's it, here is how the full configuration looks like:&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;membersOnly&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;configureUnlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;yieldPaywallConfig&lt;/span&gt;&lt;span class="p"&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="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;locks&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="s1"&gt;0xafa8fE6D93174D17D98E7A539A90a2EFBC0c0Fc1&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;network&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&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="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;getUserEthereumAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &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="o"&gt;=&amp;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;request&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="nx"&gt;userAddress&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;updateUserEthereumAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &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;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&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="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;userAddress&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;address&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="nx"&gt;app&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;💡 Please note that the configuration block yields the &lt;code&gt;membersOnly&lt;/code&gt; middleware that we'll use in the last step!&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding the middleware to our premium route
&lt;/h3&gt;

&lt;p&gt;Now that the middleware exists, we can very easily plug it into our premium route and here is how it looks like:&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;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/premium&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;membersOnly&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&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;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ... unchanged&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ As you can see, it's quite trivial! &lt;/p&gt;

&lt;h2&gt;
  
  
  Final touches
&lt;/h2&gt;

&lt;p&gt;A nice addition is to let the user "log out" by just deleting the cookie. For this, we're adding a route:&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;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/logout&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="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clearCookie&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;userAddress&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&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;/&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;🧪 Want to try it out? We deployed the application &lt;a href="http://locked-time.herokuapp.com/" rel="noopener noreferrer"&gt;on Heroku&lt;/a&gt;.&lt;br&gt;
🧐 Want to look at the code? It is all on &lt;a href="https://github.com/julien51/locked-time" rel="noopener noreferrer"&gt;Github&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A note on security&lt;/em&gt;: one could note that the cookie itself could be spoofed. This is true, but also easily fixable using multiple approaches. One of them is to change how &lt;code&gt;updateUserEthereumAddress&lt;/code&gt; is implemented by using the 4th and 5th arguments passed to this function that include a signature and the message signed by the user. By recovering the signature, the application can get the &lt;em&gt;certainty&lt;/em&gt; that the user's address actually matches the visitor (especially if the message signed includes a timestamp or some kind of unique nonce, configurable in the paywall config).&lt;/p&gt;

&lt;h2&gt;
  
  
  👋 Closing thoughts!
&lt;/h2&gt;

&lt;p&gt;Using this &lt;a href="https://www.npmjs.com/package/@unlock-protocol/unlock-express" rel="noopener noreferrer"&gt;express plugin&lt;/a&gt; means that a developer can start monetizing their application from anywhere in the world, in a matter of minutes. There is no need to agree to terms of service, apply for an API key and no approval or review of your application!&lt;/p&gt;

&lt;p&gt;Additionally you as a developer can decide of the benefits you want to offer to your members, whether its access to unique content, special features. One of my favorite feature is that the locks themselves are not even tied to a specific platform. For example, if you decide to do support over Discord, you could use a bot like &lt;a href="https://swordybot.com/" rel="noopener noreferrer"&gt;SwordyBot&lt;/a&gt; to easily identify paying members (or grant them access to a special channel!)&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%2F1qjuxc3vwbcsowmxg8ex.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%2F1qjuxc3vwbcsowmxg8ex.png" alt="Unlock Showcase"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.unlockshowcase.com/" rel="noopener noreferrer"&gt;Examples of Projects using Unlock&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;If you enjoyed this and want to learn more, please &lt;a href="https://discord.com/invite/Ah6ZEJyTDp" rel="noopener noreferrer"&gt;join the Unlock Discord&lt;/a&gt;. I would also recommend that &lt;a href="https://docs.unlock-protocol.com/governance/grants-bounties-and-matchings" rel="noopener noreferrer"&gt;you apply for an Unlock grant&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;👩‍💻 Oh! And we're &lt;a href="https://www.notion.so/unlockprotocol/Unlock-Jobs-907811d15c4d490091eb298f71b0954c" rel="noopener noreferrer"&gt;hiring a Dev Evangelist&lt;/a&gt;. Is that you?&lt;/p&gt;

</description>
      <category>nft</category>
      <category>web3</category>
      <category>express</category>
      <category>ethereum</category>
    </item>
    <item>
      <title>Front End Engineering is Nothing to Sneer At</title>
      <dc:creator>Julien Genestoux</dc:creator>
      <pubDate>Mon, 08 Oct 2018 17:45:59 +0000</pubDate>
      <link>https://forem.com/julien51/front-end-engineering-is-nothing-to-sneer-at-1ipa</link>
      <guid>https://forem.com/julien51/front-end-engineering-is-nothing-to-sneer-at-1ipa</guid>
      <description>&lt;p&gt;Even though &lt;a href="https://unlock-protocol.com/"&gt;Unlock&lt;/a&gt;, at its core, is a protocol to build a better business model for the web, I believe it cannot succeed if it does not provide a stellar experience to both creators and consumers. The fact that Unlock is a blockchain based protocol means that there are a few extra challenges to handle, but our goal is to build the best “unlocking” experience anyway.&lt;/p&gt;

&lt;p&gt;Because of that, we’re focusing our early hires on software engineers who can help us build both that amazing experience and the architecture which will support it. For this reason, we are particularly looking for front end engineers.&lt;/p&gt;

&lt;p&gt;Unfortunately, as we made progress and looked at applications and feedback from the candidates, we started to witness that front end software still has a stigma for a lot of software engineers as not being real engineering. It is time to end that myth.&lt;/p&gt;

&lt;p&gt;Many still think that front end is not real engineering. It is time to end that myth.&lt;br&gt;
At this point, any modern web application has probably more happening on the client (web browser) than it does on the server. That was certainly different 20 years ago, when most web applications were serving “static” HTML documents, but 2 trends have since then taken us to a very different place:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Most of the backend “platforms” have gotten infinitely more powerful. For example, when I started my career (early 2000s), sharding a MySQL database was pretty much considered cutting edge. Today, Google’s cloud platform offers what a lot of people consider to be the Grail with Cloud Spanner. While you had to design your whole web application around a database limitation, you can now build application which can (almost) completely ignore how the data is stored. Platforms like AWS, Azure or GCP, brought us transparent infinite file storage, managed queue servers, email services or auto-magic scaling, and now, services likes on-demand AI… I will go as far as saying that, unless you’re building some of the largest systems/APIs out there (hundreds of millions of users and more), you can go very very far with “out of the box(cloud!)” solutions.&lt;/li&gt;
&lt;li&gt;The front-end constraints, requirements and usages have seen a Cambrian explosion. It started with Ajax, which, despite being a hack, paved the way for much smoother user interfaces (remember when each click meant a full page reload?). The mobile revolution of course made everything orders of magnitude more difficult: when most websites had to consider a dozen different resolutions, we now have dozens of aspect ratios alone! Mobile devices also took us a couple years back when it comes to available resources (CPU, memory and bandwidth) and added a new one: energy consumption. The web stack itself became incredibly more complex with half a dozen in browser data storage mechanisms (we started with cookies… only!), multiple streaming protocols, and of course a whole set of new JavaScript APIs. It’s no wonder why we have dedicate javaScript libraries to manage state alone.
This means that, at least for me, the biggest impact that most engineering teams can have is on the front end, not on the backend. I’d even go as far as saying that a great front end experience can still make up for slow API requests, eventual consistency (have you tried reloading your FB home page twice?) or badly designed backend services… while there is no way a modern web application can recover from a sub-par front end layer.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Of course, the concept of a full stack engineer still has a great future, but we should also consider that, like always, context switching has a cost. One can be a great front end engineer and a great back end engineer in their career (after all, these are 2 facets of software engineering…), but I’d start to challenge the idea that they can be both at the same time. In the same way that a great musician can be both a great pianist and great guitarist, the amount of work to master any of these 2 instruments means that it’s nearly impossible to master both at the same time.&lt;/p&gt;

&lt;p&gt;(this was initially &lt;a href="https://medium.com/@julien51/front-end-engineering-is-nothing-to-sneer-at-23e70324443c"&gt;published here&lt;/a&gt;)&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>javascript</category>
      <category>discuss</category>
      <category>react</category>
    </item>
    <item>
      <title>Oracle-less bets on the Blockchain</title>
      <dc:creator>Julien Genestoux</dc:creator>
      <pubDate>Tue, 14 Nov 2017 20:33:07 +0000</pubDate>
      <link>https://forem.com/julien51/oracle-less-bets-on-the-blockchain-9ok</link>
      <guid>https://forem.com/julien51/oracle-less-bets-on-the-blockchain-9ok</guid>
      <description>&lt;p&gt;The blockchain is a decentralized database whose data can be trusted because it is the sum of other previously recorded transactions. That data can then be used as an input for all sort of transactions (called smart contracts).&lt;/p&gt;

&lt;p&gt;Yet, one of the challenges is that there is actually not a lot of physical data on the blockchain. The way around this is to use trusted third parties called Oracles which are expected to speak the truth. Their job is to capture “real world” knowledge and store it on the blockchain. That data becomes immutable and part of the long chain of transactions.&lt;/p&gt;

&lt;p&gt;An obviously financial example is stock prices. In order to write a smart contract which would rebalance a portfolio, one would have to use an oracle to capture the stock prices of assets in that portfolio.&lt;/p&gt;

&lt;p&gt;Some people expect that oracle will eventually becomes obsolete in a world where all possible data sources are available “natively” on the blockchain. For example, if stocks where actually traded on the blockchain, then the price data itself is in the blockchain and the rebalancing algorithm does not need to use and rely on a 3rd party oracle.&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fsjvt6vdnphjizmgym7pl.jpeg" 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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fsjvt6vdnphjizmgym7pl.jpeg" alt="consensus"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Can we go without oracles?
&lt;/h2&gt;

&lt;p&gt;If we’ve crossed path in the last couple weeks, you know that I am researching the blockchain these days. (but no, I am not doing an ICO!). As part of this work, and I wanted to see if we could actually not rely on oracles, but rely only the participants good behavior and their ability to form a consensus with the right incentive. Staking is one of the key concepts of the blockchain world and I think this solves our problem here.&lt;/p&gt;

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

&lt;p&gt;Let’s take a simple example: we want to write a smart contract which lets an arbitrary number of people bet on an outcome. For the sake of simplicity, we use only binary draws (the thing people bet on actually happens or does not).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In the “traditional” smart contract, participants would be asked to bet on whether the statement is true or false and their bet would be placed in a shared wallet. The oracle would then deliver the truth and all the participants who bet on the right outcome should be able to withdraw their share of the shared walled.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If we did not want to rely on a 3rd party oracle, we would have to ask the participants themselves to contribute the truth, before the payout can happen. Our smart contract would then have 3 phases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Betting phase&lt;/li&gt;
&lt;li&gt;Consensus formation phase&lt;/li&gt;
&lt;li&gt;Payout phase&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Consensus formation
&lt;/h2&gt;

&lt;p&gt;Unfortunately for mankind, we have to assume malice: some participants will lie and submit lies as truth.&lt;br&gt;
One way to prevent this is by requiring a “stake”. The smart contract only allows people to place bets if they are staking an amount larger than their bet along with the bet to show their intent to contribute truth.&lt;br&gt;
Once the event has been realized, all players are asked to contribute its outcome if they want their stake to be returned to them. If they don’t, then their stake is lost. Participants do this by voting on what is the actual outcome. Once enough participants have voted, the &lt;strong&gt;truth is determined by seeing which proposition got more “votes” compared to it share of bets&lt;/strong&gt; (not necessarily the majority).&lt;/p&gt;

&lt;p&gt;All the players who have placed a bet on the right value have a strong incentive to vote: not only would they get the stake back, but also their share of the jackpot.&lt;/p&gt;

&lt;p&gt;Players who have placed the wrong bet, on the other end, also have an incentive to vote on the right value because they would get their stake back. If they did not, not only would they have lost the bet, but they would also lose their stake. If all the losers where cheaters, then they could, in theory, break the smart contract, but if only a single one of them is indeed a fair participant, then all the losers but this one would lose their stake. This is a typical prisoner’s dilemma which lets us expect that most losers would not try to lie in order to not worsen their situation.&lt;/p&gt;

&lt;h3&gt;
  
  
  An example
&lt;/h3&gt;

&lt;p&gt;In order to clarify things, let’s take an example: people have been asked whether this story will get strictly more than 100 reads before November 5th 2017. They are each asked to bet $1 on what they think is the most likely outcome and they are also asked to stake $2 to come and contribute the truth after November 5th. Betting is only open before that post goes public (I shared the draft with players).&lt;/p&gt;

&lt;p&gt;At the publishing time, 65 people said that yes this story is good enough to get 100 reads and 35 people placed the bet that it would not. We have a pot of $100 which will be shared among winners.&lt;/p&gt;

&lt;p&gt;Time passes and we are eventually on November 5th. Unfortunately (I am biased), this story did not get the 100 reads it deserves. Each participant is asked to contribute to the truth. Out of the 35 people who placed the right bet, 34 contributed the truth (the last one forgot about the bet and the story!). Most of the 65 people who placed the wrong bet were honest (or too scared that their fellow losers were more honest than them) so 50 of them contributed the truth. 13 of them did not bother to vote as they were too disappointed and did not care much about their stake and 2 cheaters lied.&lt;/p&gt;

&lt;p&gt;The voting is pretty clear: 85 (97% of votes) people claimed that the story did not get its 100 claps, while only 35% of bets where for that proposition. Consensus was formed and these 85 people got their stake back. The winers also each get $2.8 payout.&lt;/p&gt;




&lt;p&gt;In my mind, decentralized staking is one of the most important elements of the blockchains economies and incentives. In this example, we can encourage (enforce?) good behavior and actually turn each participant into an oracle, eventually removing the need to share and trust a third party.&lt;/p&gt;

&lt;p&gt;One of the benefits of removing 3rd party oracle is to also reduce the cost to operate such a contract: there is no need to pay for that oracle. In the example above, 100% of the bets are passed down to the winning participants. The house could very well use the lost stakes as its payment for operating the contract.&lt;/p&gt;

&lt;p&gt;Additionally, this “framework” can also be incremented with many other aspects. For example, one could add the ability to trade bets by adding a “cooling” period between the betting period and the consensus formation period where participants can trade their votes (and cash out early or minimize risk exposure…).&lt;/p&gt;

&lt;p&gt;Originally &lt;a href="https://medium.com/@julien51/oracle-less-bets-on-the-blockchain-dfc6a44f6d6" rel="noopener noreferrer"&gt;published there&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>oracle</category>
      <category>ethereum</category>
    </item>
  </channel>
</rss>
