<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Web3dAppDevCamp</title>
        <link>https://paragraph.com/@apecoder</link>
        <description>the Online Camp focusing on Web3.0 dApp Development.</description>
        <lastBuildDate>Tue, 07 Apr 2026 22:56:51 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <image>
            <title>Web3dAppDevCamp</title>
            <url>https://storage.googleapis.com/papyrus_images/9cb5da88fe2456a589702ed1286542b7de436f147792069c1b1bcd03a106a1a6.png</url>
            <link>https://paragraph.com/@apecoder</link>
        </image>
        <copyright>All rights reserved</copyright>
        <item>
            <title><![CDATA[Preface | Building the "Decentralized Developer Society"]]></title>
            <link>https://paragraph.com/@apecoder/preface-building-the-decentralized-developer-society</link>
            <guid>PmKRyTVqcu4DIOGlnSnE</guid>
            <pubDate>Thu, 27 Apr 2023 08:46:51 GMT</pubDate>
            <description><![CDATA[天下皆知美之為美，斯惡已。皆知善之為善，斯不善已。故有無相生，難易相成，長短相較，高下相傾，音聲相和，前後相隨。是以聖人處無為之事，行不言之教；萬物作焉而不辭，生而不有。為而不恃，功成而弗居。夫唯弗居，是以不去。 —— "Tao Te Ching, Chapter 0x02"0x01 BackgroundIn Vitalik&apos;s "Decentralized Society: Finding the Soul of Web3", a cool and fascinating picture of the future is presented. With Web3, we have the opportunity to construct a Web3 Society based on "new building blocks" such as DID, Coin, NFT, and SBT. What Vitalik proposes, however, is a general Web3 Society. Under this background, we can ...]]></description>
            <content:encoded><![CDATA[<blockquote><p>天下皆知美之為美，斯惡已。皆知善之為善，斯不善已。故有無相生，難易相成，長短相較，高下相傾，音聲相和，前後相隨。是以聖人處無為之事，行不言之教；萬物作焉而不辭，生而不有。為而不恃，功成而弗居。夫唯弗居，是以不去。</p><p>—— &quot;Tao Te Ching, Chapter 0x02&quot;</p></blockquote><h2 id="h-0x01-background" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x01 Background</h2><p>In Vitalik&apos;s <strong>&quot;Decentralized Society: Finding the Soul of Web3&quot;</strong>, a cool and fascinating picture of the future is presented.</p><p>With Web3, we have the opportunity to construct a Web3 Society based on &quot;new building blocks&quot; such as DID, Coin, NFT, and SBT.</p><p>What Vitalik proposes, however, is a general Web3 Society. Under this background, we can fork out the branch of the subdivision field. For example, what we need to discuss today is the &quot;Decentralized Developer Society&quot; composed of Developers.</p><p>Next, we will use the idea of &quot;beginning with the end in mind&quot; to discuss if there is a &quot;decentralized developer society&quot; in the future, what are its key principles? In other words, what matters most?</p><ul><li><p>**Benefits💰: **Realize the developer&apos;s &quot;earning for work&quot;</p></li><li><p>**Re-Education📚: **Achieving a &quot;good upgrade path&quot; for developers</p></li><li><p>**Globalization🌏: **Helping developers get rid of geographical restrictions</p></li><li><p>**Opportunity 😘 : **Helps developers build their personal brand</p></li></ul><h2 id="h-0x02-realize-the-developers-earning-for-work" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x02 Realize the developer&apos;s &quot;earning for work&quot;</h2><p>The first and foremost point is that the &quot;decentralized developer society&quot; needs to realize the developer&apos;s &quot;earning for work&quot;. Otherwise there will be such an unfortunate situation for <code>core-js</code> author:</p><blockquote><p>&quot;Open source core-js was probably the biggest mistake of my life.&quot;</p><p>—— <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.oschina.net/news/228389/corejs-maintainer-so-whats-next#:~:text=core%2Djs%20%E4%BD%9C%E8%80%85Denis%20Pushkarev,%E5%92%8C%E9%81%AD%E9%81%87%EF%BC%8C%E4%BB%A5%E5%8F%8A%E5%BF%83%E6%80%81%E5%8F%98%E5%8C%96%E3%80%82">https://www.oschina.net/news/228389/corejs-maintainer-so-whats-next#:~:text=core-js 作者Denis Pushkarev,和遭遇，以及心态变化。</a></p></blockquote><p>Fortunately, Web3 technology provides developers with the opportunity to upgrade the original open source model of &quot;purely generating power for love&quot;—independent developers have a cool idea, and develop a cool Web3 project on this basis. You can use this project to participate in Hackathon, apply for Grant, obtain financing, and so on. In the previous Web2 world, it was difficult for developers to gain this level of voice and initiative.</p><p>In short, **Web3 Society itself is more developer-friendly. **</p><h2 id="h-0x03-implement-a-good-upgrade-path-for-developers" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x03 Implement a &quot;good upgrade path&quot; for developers</h2><p>Secondly, the &quot;decentralized developer society&quot; must realize the <strong>&quot;good upgrade path&quot;</strong> for developers.</p><p>What is a &quot;good upgrade path&quot;?</p><p>A key point is that if the member is willing and able enough, then he can master his &quot;upgrade&quot; completely autonomously. For example, in this system, as long as the ability is sufficient, then level skipping is completely allowed.</p><p>The opposite example is the &quot;seniority ranking&quot; system, where &quot;level&quot; is strongly related to &quot;time&quot; rather than &quot;ability&quot;. This system runs counter to the spirit of Web3.</p><p>The second key point is that if the **upgrade path can be &quot;gradually promoted&quot;. **</p><p>The escalation path for startups in the Web2 world is steep, often requiring a large sum of money to start a startup. Therefore, in the traditional world, for the vast majority of people, they will never start a business in their lifetime.</p><p>However, in the Web3 Society, a smoother &quot;upgrade path&quot; has spontaneously formed:</p><pre data-type="codeBlock" text="+-----------------+    +--------------------+
| Technical Study |----|Working On Bounties |---- Got Money
+-----------------+    +--------------------+
     ↓↓↓
+---------------+
| Amazing Ideas |
+---------------+
     ↓↓↓
+----------------+
| Join Hackathon |---- Got Money
+----------------+
     ↓↓↓
+-----------------+
| Apply for Grant |---- Got Money
+-----------------+
    ↓↓↓
+-----------------+
| Financing |---- Got Money
+-----------------+
"><code><span class="hljs-operator">+</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">+</span>    <span class="hljs-operator">+</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">+</span>
<span class="hljs-operator">|</span> Technical Study <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">|</span>Working On Bounties <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> Got Money
<span class="hljs-operator">+</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">+</span>    <span class="hljs-operator">+</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">+</span>
     ↓↓↓
<span class="hljs-operator">+</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">+</span>
<span class="hljs-operator">|</span> Amazing Ideas <span class="hljs-operator">|</span>
<span class="hljs-operator">+</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">+</span>
     ↓↓↓
<span class="hljs-operator">+</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">+</span>
<span class="hljs-operator">|</span> Join Hackathon <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> Got Money
<span class="hljs-operator">+</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">+</span>
     ↓↓↓
<span class="hljs-operator">+</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">+</span>
<span class="hljs-operator">|</span> Apply <span class="hljs-keyword">for</span> Grant <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> Got Money
<span class="hljs-operator">+</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">+</span>
    ↓↓↓
<span class="hljs-operator">+</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">+</span>
<span class="hljs-operator">|</span> Financing <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> Got Money
<span class="hljs-operator">+</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">+</span>
</code></pre><p>**In each stage, Buidlers have the opportunity to get money, so as to proceed to the next stage, thus achieving the &quot;flywheel effect&quot;. What NonceGeekDA has to do is to make this path clearer, more explicit, and developer-friendly. **</p><h2 id="h-0x04-help-developers-get-rid-of-geographical-restrictions" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x04 Help developers get rid of geographical restrictions</h2><p>**It seems to be common sense that the long-term income of workers is strongly bound to the region where they are located. **</p><p>When the regional economy declines, no matter how high the level of workers is, their income will inevitably be affected; in addition, for workers of the same level, their income levels vary greatly in different regions.</p><p>Therefore, in the past, capable workers tended to go to places with the highest income levels—but higher income levels often also meant higher living costs, such as Silicon Valley.</p><p>The global collaboration brought about by Web3 and the open source paradigm can theoretically break this traditional situation - break the strong relationship between the developer&apos;s work and the place of work, achieve geographic freedom and time freedom, and allow developers to enjoy the &quot;geographic arbitrage dividend&quot; .</p><p>However, for most developers, especially domestic developers, there are still many obstacles to achieve global links, for example, insufficient language skills make it difficult to communicate smoothly, lack of linking institutions with overseas developers and organizations, etc. wait.</p><p>** Therefore, it is an important mission of NonceGeekDAO to help developers get rid of geographical restrictions, realize global links, create More &amp; More Serendipity through global links, and finally achieve rapid growth. **</p><h2 id="h-0x05-help-developers-build-their-personal-brand" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x05 Help developers build their personal brand</h2><p>&quot;Personal branding&quot; seems to have become a cliché in today&apos;s era, but few people really understand the law behind &quot;personal branding&quot;: **&quot;Always attract, not pursue&quot;. **</p><ul><li><p>When looking for a job, always attract rather than pursue;</p></li><li><p>When looking for a partner, always attract rather than pursue</p></li><li><p>...</p></li></ul><p>When the world facing you gradually opens up, you will find that only attraction is the only correct answer. If you use pursuit, then your daily attention will be exhausted in the pursuit; but if you learn to attract, even if you just master how to write <code>Github Personal README</code> correctly, then you also have a <code>24</code> h automatic operation There is nothing more cost-effective and more important than attracting machines.</p><p>**How to help developers build their personal brands, especially through the early days when personal brands lack positive feedback? It will be a proposition that NonceGeekDAO will continue to explore. **</p><h2 id="h-0x06-epilogue" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x06 Epilogue</h2><p>NonceGeekDAO firmly believes that, as Developers DAOs / Orgs, it is very important to be developer-oriented and focus on developer rights. On the basis of the original intention, follow the inevitable trend and do the right thing. In the long run, the world will definitely give positive feedback.</p><p>Best wishes for all Buidlers/Developers/Orgs/DAOs working for the better world!</p><p>In the future, the theme of &quot;Building a decentralized developer society&quot; will be elaborated in more detail through a series of articles, including two levels of concept and practice.</p>]]></content:encoded>
            <author>apecoder@newsletter.paragraph.com (Web3dAppDevCamp)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/8d544c81beaed03adfc6c7a7cb8926df892a111e3b9d03c95774414060701b45.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[Hello Move | Move dApp Quick Learning 0x01]]></title>
            <link>https://paragraph.com/@apecoder/hello-move-move-dapp-quick-learning-0x01</link>
            <guid>PuGusDz7ZjyEMmfPQgJJ</guid>
            <pubDate>Sat, 30 Jul 2022 01:13:56 GMT</pubDate>
            <description><![CDATA[Authors: Leeduckgo, Ningbo Wang, Junfeng Chen @ NonceGeekDAO Translator: msfew We&apos;ve been evolving from binary to assembly to various high-level languages. Smart contracts, too, have taken a big step forward from Bitcoin&apos;s Script to Ethereum&apos;s Solidity, but can Solidity take over the world? In fact, the endless security issues that have been plaguing us have largely limited the development of the industry as a whole. "Security" is more important than ever in the financial scena...]]></description>
            <content:encoded><![CDATA[<blockquote><p><strong>Authors:</strong> Leeduckgo, Ningbo Wang, Junfeng Chen @ NonceGeekDAO</p><p><strong>Translator:</strong> msfew</p><p>We&apos;ve been evolving from binary to assembly to various high-level languages. Smart contracts, too, have taken a big step forward from Bitcoin&apos;s Script to Ethereum&apos;s Solidity, but can Solidity take over the world? In fact, the endless security issues that have been plaguing us have largely limited the development of the industry as a whole. &quot;Security&quot; is more important than ever in the financial scenario, especially in the DeFi era, and we cannot turn a blind eye to these issues. If the blockchain industry continues to evolve, there will inevitably be better smart contract languages coming out.</p><p>With these premises in mind, a new smart contract language, Move, was designed for &quot;resource&quot; oriented programming. I personally think that &quot;resource-oriented programming&quot; is a change in the smart contract language, and frankly, it is a big step forward.</p><p>——jolestar</p><p>——<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://starcoin.org/zh/developer/blog/starcoin_move_resource">https://starcoin.org/zh/developer/blog/starcoin_move_resource</a></p><p>——<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/jolestar.eth/sQ0nMCO3eNig6gCzqQO7xew1mn8oUi1-rKtfZKmGlNI">https://mirror.xyz/jolestar.eth/sQ0nMCO3eNig6gCzqQO7xew1mn8oUi1-rKtfZKmGlNI</a></p></blockquote><p>This series will explain the Move language and the development of the Move dApp, and the computer principles behind it, using Starcoin as an example.</p><p>For a full update of this series, see:</p><blockquote><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/WeLightProject/Web3-dApp-Camp/tree/main/move-dapp">https://github.com/WeLightProject/Web3-dApp-Camp/tree/main/move-dapp</a></p></blockquote><p>Assignments:</p><blockquote><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/WeLightProject/Web3-dApp-Camp/discussions/categories/projects-others">https://github.com/WeLightProject/Web3-dApp-Camp/discussions/categories/projects-others</a></p></blockquote><h2 id="h-1-node-start-up" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">1 Node Start-up</h2><p>Download the latest distribution of the Starcoin node program (for MacOS just copy it to the <code>/usr/local/bin</code> directory):</p><blockquote><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/starcoinorg/starcoin/releases">https://github.com/starcoinorg/starcoin/releases</a></p></blockquote><p>Here is a demonstration of how to start a node based on the <code>Starcoin</code> network:</p><blockquote><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://starcoinorg.github.io/starcoin-cookbook/docs/getting-started/setup/">https://starcoinorg.github.io/starcoin-cookbook/docs/getting-started/setup/</a></p></blockquote><p>TLDR version - key commands:</p><pre data-type="codeBlock" text="# Start a local dev node
$ starcoin -n dev
# Start a local dev node and open the console at the same time. The -d parameter ensures that historical data is kept each time the console is opened instead of reopened
$ mkdir [folder_name]
$ cd [folder_name]
$ pwd
$ starcoin -d [path_to_your_data_folder] -n dev console
"><code><span class="hljs-comment"># Start a local dev node</span>
<span class="hljs-variable">$ </span>starcoin -n dev
<span class="hljs-comment"># Start a local dev node and open the console at the same time. The -d parameter ensures that historical data is kept each time the console is opened instead of reopened</span>
<span class="hljs-variable">$ </span>mkdir [folder_name]
<span class="hljs-variable">$ </span>cd [folder_name]
<span class="hljs-variable">$ </span>pwd
<span class="hljs-variable">$ </span>starcoin -d [path_to_your_data_folder] -n dev console
</code></pre><p>starcoin Console commands.</p><pre data-type="codeBlock" text="# Designated accounts receive test tokens
starcoin% dev get-coin 0xb7c46353c6c0e3a2559d5b12cad981e4 -v 100STC
# Account list
starcoin% account list
# Single account status view
starcoin% account show 0xb7c46353c6c0e3a2559d5b12cad981e4
# Create new account
starcoin% account create -p [pwd]
"><code><span class="hljs-meta prompt_"># </span><span class="bash">Designated accounts receive <span class="hljs-built_in">test</span> tokens</span>
<span class="hljs-meta prompt_">starcoin% </span><span class="bash">dev get-coin 0xb7c46353c6c0e3a2559d5b12cad981e4 -v 100STC</span>
<span class="hljs-meta prompt_"># </span><span class="bash">Account list</span>
<span class="hljs-meta prompt_">starcoin% </span><span class="bash">account list</span>
<span class="hljs-meta prompt_"># </span><span class="bash">Single account status view</span>
<span class="hljs-meta prompt_">starcoin% </span><span class="bash">account show 0xb7c46353c6c0e3a2559d5b12cad981e4</span>
<span class="hljs-meta prompt_"># </span><span class="bash">Create new account</span>
<span class="hljs-meta prompt_">starcoin% </span><span class="bash">account create -p [<span class="hljs-built_in">pwd</span>]</span>
</code></pre><h2 id="h-2-the-first-move-contract-mycounter" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">2 The first Move contract -- MyCounter</h2><p>Minimum practicable example:</p><blockquote><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/starcoinorg/starcoin-cookbook/blob/main/examples/my-counter">https://github.com/starcoinorg/starcoin-cookbook/blob/main/examples/my-counter</a></p></blockquote><pre data-type="codeBlock" text="module MyCounterAddr::MyCounter {
     use StarcoinFramework::Signer;

     struct Counter has key, store {
        value:u64,
     }
     public fun init(account: &amp;signer){
        move_to(account, Counter{value:0});
     }
     public fun incr(account: &amp;signer) acquires Counter {
        let counter = borrow_global_mut&lt;Counter&gt;(Signer::address_of(account));
        counter.value = counter.value + 1;
     }

     public(script) fun init_counter(account: signer){
        Self::init(&amp;account)
     }

     public(script) fun incr_counter(account: signer)  acquires Counter {
        Self::incr(&amp;account)
     }
}
"><code>module MyCounterAddr::MyCounter {
     use StarcoinFramework::Signer;

     struct Counter has key, store {
        value:u64,
     }
     <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">init</span><span class="hljs-params">(account: &#x26;<span class="hljs-type">signer</span>)</span></span>{
        move_to(account, Counter{value:<span class="hljs-number">0</span>});
     }
     <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">incr</span><span class="hljs-params">(account: &#x26;<span class="hljs-type">signer</span>)</span></span> acquires Counter {
        let counter = borrow_global_mut&#x3C;Counter>(Signer::address_of(account));
        counter.value = counter.value + <span class="hljs-number">1</span>;
     }

     <span class="hljs-keyword">public</span>(script) <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">init_counter</span><span class="hljs-params">(account: <span class="hljs-type">signer</span>)</span></span>{
        Self::<span class="hljs-keyword">init</span>(&#x26;account)
     }

     <span class="hljs-keyword">public</span>(script) <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">incr_counter</span><span class="hljs-params">(account: <span class="hljs-type">signer</span>)</span></span>  acquires Counter {
        Self::incr(&#x26;account)
     }
}
</code></pre><p>MyCounter source code analysis</p><p>A module is a set of functions and structures packaged together at a specific address. To use script, you need to run it with a published module or standard library, which is itself a set of modules published at address 0x1.</p><p>module MyCounterAddr::MyCounter{ } then a module is created under this MyCounterAddr address (corresponding to MyCounterAddr = &quot;0xb7c46353c6c0e3a2559d5b12cad981e4&quot; under Move.toml).</p><p>use StarcoinFramework::Signer, is using the Signer module under the standard library. Signer is a native Resource-like non-reproducible type that contains the address of the sender of the transaction. One of the reasons for introducing the signer type was to explicitly show which functions require sender privileges and which do not. Thus, functions cannot trick users into unauthorized access to their Resource. See <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/starcoinorg/starcoin-framework/blob/main/sources/Signer.move">source code</a> for details.</p><pre data-type="codeBlock" text="struct Counter has key, store {
        value:u64,
     }
"><code><span class="hljs-keyword">struct</span> <span class="hljs-title class_">Counter</span> has key, store {
        value:<span class="hljs-type">u64</span>,
     }
</code></pre><p>A structure called Counter is defined using struct, modified by both key,store constraints, and Move has a flexible type system where each type can be modified by four constraints. These four constraints, which we call abilities, define whether the type&apos;s values can be copied, dropped, and stored. The four abilities constraints are: Copy, Drop, Store and Key.</p><p>Their functions are.</p><ul><li><p>Copy - The modified value can be copied.</p></li><li><p>Drop - The modified value can be dropped at the end of the scope.</p></li><li><p>Key - the modified value can be accessed as a key to the global state.</p></li><li><p>Store - The modified value can be stored to the global state.</p></li></ul><p>The key,store modifier here means that it cannot be copied, discarded or reused, but it can be safely stored and transferred.</p><p>The following is the definition:</p><pre data-type="codeBlock" text="public fun init(account: &amp;signer){
    move_to(account, Counter{value:0});
}
public fun incr(account: &amp;signer) acquires Counter {
    let counter = borrow_global_mut&lt;Counter&gt;(Signer::address_of(account));
    counter.value = counter.value + 1;
}
"><code><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">init</span><span class="hljs-params">(account: &#x26;<span class="hljs-type">signer</span>)</span></span>{
    move_to(account, Counter{value:<span class="hljs-number">0</span>});
}
<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">incr</span><span class="hljs-params">(account: &#x26;<span class="hljs-type">signer</span>)</span></span> acquires Counter {
    let counter = borrow_global_mut&#x3C;Counter>(Signer::address_of(account));
    counter.value = counter.value + <span class="hljs-number">1</span>;
}
</code></pre><p>The definition format is:</p><p>public fun functionName(parameter: parameter type){ }</p><p>The move functions are private by default and can only be accessed in the module where they are defined. The keyword public will change the default visibility of the function and make it public, i.e. accessible from outside.</p><p>The init method argument is a &amp;signer, meaning that the method must be legally signed by an account before it can be called, and move_to is an original language for move, which serves to publish and add Counter resources to the signer&apos;s address. move&apos;s account model, code and data are stored under an account address.</p><p>The following is a list of common original phrases</p><ul><li><p>move_to&lt; T &gt;(&amp;signer, T): Publish, add a resource of type T to the address of signer.</p></li><li><p>move_from&lt; T &gt;(addr: address): T - removes a resource of type T from under the address and returns this resource.</p></li><li><p>borrow_global&lt; T &gt;(addr: address): &amp;T - Returns an immutable reference to a resource of type T at the address.</p></li><li><p>borrow_global_mut&lt; T &gt;(addr: address): &amp;mut T - Returns a mutable reference to a resource of type T at address.</p></li><li><p>exists&lt; T &gt;(address): bool: Determines if there is a resource of type T under address.</p></li></ul><p>The incr method argument is also a &amp;signer, meaning that the method must be legally signed by an account before it can be called,</p><p>The keyword acquires, placed after the function return value, is used to explicitly define all the Resources acquired by this function.</p><p>Signer::address_of(account) gets the address from the signer</p><p>borrow_global_mut is described above, variable borrow to address under the resource Counter, and then the value under the Counter structure for +1 operation.</p><p>The following two methods are script methods, what is the difference between it and the above two functions?</p><ul><li><p>public fun: method can be called from any module.</p></li><li><p>public(script) fun: script function is the entry method in the module, indicating that the method can be called by initiating a transaction from the console, just like a locally executed script</p></li></ul><p>The next version of Move will replace public(script) fun with public entry fun</p><p>Self represents its own module.</p><pre data-type="codeBlock" text="  public(script) fun init_counter(account: signer){
        Self::init(&amp;account)
     }

     public(script) fun incr_counter(account: signer)  acquires Counter {
        Self::incr(&amp;account)
     }
"><code>  <span class="hljs-keyword">public</span>(script) <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">init_counter</span><span class="hljs-params">(account: <span class="hljs-type">signer</span>)</span></span>{
        Self::<span class="hljs-keyword">init</span>(&#x26;account)
     }

     <span class="hljs-keyword">public</span>(script) <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">incr_counter</span><span class="hljs-params">(account: <span class="hljs-type">signer</span>)</span></span>  acquires Counter {
        Self::incr(&#x26;account)
     }
</code></pre><h3 id="h-21-compilation" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2.1 Compilation</h3><p>Download the source code for the first example at:</p><pre data-type="codeBlock" text="$ git clone git@github.com:WeLightProject/Web3-dApp-Camp.git
$ cd Web3-dApp-Camp/move-dapp/my-counter
"><code>$ git clone git@github.com:WeLightProject<span class="hljs-operator">/</span>Web3<span class="hljs-operator">-</span>dApp<span class="hljs-operator">-</span>Camp.git
$ cd Web3<span class="hljs-operator">-</span>dApp<span class="hljs-operator">-</span>Camp<span class="hljs-operator">/</span>move<span class="hljs-operator">-</span>dapp<span class="hljs-operator">/</span>my<span class="hljs-operator">-</span>counter
</code></pre><p>The package management tool for Move is the Move Package Manager (mpm), which is similar to Rust&apos;s Cargo or Node&apos;s NPM. You can create a new project with <code>mpm package new my-counter</code>, the typical directory structure is:</p><pre data-type="codeBlock" text="my-counter
├── Move.toml
└── sources
    └── MyCounter.move
"><code>my<span class="hljs-operator">-</span>counter
├── Move.toml
└── sources
    └── MyCounter.move
</code></pre><ul><li><p>sources is used to archive Move&apos;s modules, which are similar to class files in Java.</p></li><li><p>Move.toml - used to store configuration files: including the original package data, dependencies and named addresses.</p></li><li><p>The above files constitute a Move Package. For more details on Move Package management refer to the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://starcoinorg.github.io/starcoin-cookbook/zh/docs/move/move-language/packages/">documentation</a></p></li></ul><p>Change the address in <code>move.toml</code> to the one you use for deployment.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">image-20220727123922351</figcaption></figure><p>Compiled with:</p><pre data-type="codeBlock" text="$ mpm release
"><code>$ mpm release
</code></pre><p>Next you will see your compiled binaries in the <code>release</code> folder.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">image-20220727124134402</figcaption></figure><h3 id="h-22-console-deployment" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2.2 Console Deployment</h3><p>Deployment is done by executing the following command in the Starcoin Console:</p><pre data-type="codeBlock" text="starcoin% dev deploy [path to blob] -s [addr] -b
"><code>starcoin% dev deploy <span class="hljs-selector-attr">[path to blob]</span> -s <span class="hljs-selector-attr">[addr]</span> -<span class="hljs-selector-tag">b</span>
</code></pre><blockquote><p>-s means --sender,-b means --blocking, which means blocking and waiting for command execution to finish</p></blockquote><p>If the account is locked, use the <code>unlock</code> command to unlock it.</p><pre data-type="codeBlock" text="account unlock [addr] -p [pwd]
"><code>account unlock <span class="hljs-selector-attr">[addr]</span> -<span class="hljs-selector-tag">p</span> <span class="hljs-selector-attr">[pwd]</span>
</code></pre><p>where <code>pwd</code> is the password created in <code>1.2</code>.</p><p>After successful deployment you can see:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">image-20220727124625807</figcaption></figure><blockquote><p>💡 It is important to note that in Move the code is stored on a personal address, not a public address like in Ethereum. So no new address is created after the contract is deployed, when we want to call the contract we need to use the address of the person who deployed the contract + the contract name to call the contract.</p></blockquote><h3 id="h-23-console-calls" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2.3 Console calls</h3><blockquote><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://starcoinorg.github.io/starcoin-cookbook/docs/move/interacting-with-the-contract">https://starcoinorg.github.io/starcoin-cookbook/docs/move/interacting-with-the-contract</a></p></blockquote><ol><li><p>Call the init_counter script function to initialize the resource.</p></li></ol><pre data-type="codeBlock" text="starcoin% account execute-function --function {MyCounterAddr-in-Move.toml}::MyCounter::init_counter -s 0x23dc2c167fcd16e28917765848e189ce -b
"><code>starcoin<span class="hljs-operator">%</span> account execute<span class="hljs-operator">-</span><span class="hljs-function"><span class="hljs-keyword">function</span> --<span class="hljs-title"><span class="hljs-keyword">function</span></span> </span>{MyCounterAddr<span class="hljs-operator">-</span>in<span class="hljs-operator">-</span>Move.toml}::MyCounter::init_counter <span class="hljs-operator">-</span>s <span class="hljs-number">0x23dc2c167fcd16e28917765848e189ce</span> <span class="hljs-operator">-</span>b
</code></pre><p>Among them:</p><ul><li><p><code>{MyCounterAddr-in-Move.toml}::MyCounter::init_counter</code>is the complete address on the function onchain, including the address where the contract is located + package name + function name.</p></li><li><p>-s means --sender,-b means --blocking, which means blocking and waiting for command execution to finish</p></li></ul><ol><li><p>View Counter resources</p></li></ol><pre data-type="codeBlock" text="starcoin% state get resource 0x23dc2c167fcd16e28917765848e189ce 0x23dc2c167fcd16e28917765848e189ce::MyCounter::Counter
"><code>starcoin% state get resource <span class="hljs-number">0x23dc2c167fcd16e28917765848e189ce</span> <span class="hljs-number">0x23dc2c167fcd16e28917765848e189ce</span>::MyCounter::Counter
</code></pre><p>The data of the contract in Move is called <code>Resource(resource)</code>, and since reading data does not change the state on the chain, no -s -b is needed, no transactions are executed, and no state is consumed.</p><blockquote><p>Interested students can try to call <code>incr_counter</code> and check again if <code>Counter</code> is +1.</p></blockquote>]]></content:encoded>
            <author>apecoder@newsletter.paragraph.com (Web3dAppDevCamp)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/7d504b70a2be3b6f187bf1f2e2e7a2ab60f4333d3a413ea660a01e0abf729591.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[Hello Move | Move dApp极速入门（一）]]></title>
            <link>https://paragraph.com/@apecoder/hello-move-move-dapp</link>
            <guid>ZnoEZeTAqXTIf8YSLPQS</guid>
            <pubDate>Sat, 30 Jul 2022 01:09:20 GMT</pubDate>
            <description><![CDATA[作者： 李大狗、王宁波、陈俊锋 @ NonceGeekDAO 我们从二进制到汇编到各种高级语言，一直都在发展。智能合约也一样，从比特币的Script到以太坊的Solidity，往前跨了一大步，但是，Solidity能包打天下了吗？事实上，层出不穷的安全问题一直在困扰我们，在很大程度上限制了整个行业的发展。「安全」在金融场景，尤其是DeFi时代，比以往任何时候都更加重要，这些问题我们不能视而不见。如果区块链行业继续发展，势必会有更好的智能合约语言出来。 在这些大前提下，新的智能合约语言Move被设计出来了。Move是面向「资源」编程的。我个人认为，「面向资源编程」是智能合约语言的一个变革，说白了，智能合约语言又往前迈了一大步。 ——jolestar ——https://starcoin.org/zh/developer/blog/starcoin_move_resource ——https://mirror.xyz/jolestar.eth/sQ0nMCO3eNig6gCzqQO7xew1mn8oUi1-rKtfZKmGlNI本系列将以 Starcoin 为例，讲解 Move 语言...]]></description>
            <content:encoded><![CDATA[<blockquote><p><strong>作者：</strong> 李大狗、王宁波、陈俊锋 @ NonceGeekDAO</p><p>我们从二进制到汇编到各种高级语言，一直都在发展。智能合约也一样，从比特币的Script到以太坊的Solidity，往前跨了一大步，但是，Solidity能包打天下了吗？事实上，层出不穷的安全问题一直在困扰我们，在很大程度上限制了整个行业的发展。「安全」在金融场景，尤其是DeFi时代，比以往任何时候都更加重要，这些问题我们不能视而不见。如果区块链行业继续发展，势必会有更好的智能合约语言出来。</p><p>在这些大前提下，新的智能合约语言Move被设计出来了。Move是面向「资源」编程的。我个人认为，「面向资源编程」是智能合约语言的一个变革，说白了，智能合约语言又往前迈了一大步。</p><p>——jolestar</p><p>——<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://starcoin.org/zh/developer/blog/starcoin_move_resource">https://starcoin.org/zh/developer/blog/starcoin_move_resource</a></p><p>——<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/jolestar.eth/sQ0nMCO3eNig6gCzqQO7xew1mn8oUi1-rKtfZKmGlNI">https://mirror.xyz/jolestar.eth/sQ0nMCO3eNig6gCzqQO7xew1mn8oUi1-rKtfZKmGlNI</a></p></blockquote><p>本系列将以 Starcoin 为例，讲解 Move 语言以及 Move dApp 的开发，及其背后的计算机原理。</p><p>本系列的全文更新中，见：</p><blockquote><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/WeLightProject/Web3-dApp-Camp/tree/main/move-dapp">https://github.com/WeLightProject/Web3-dApp-Camp/tree/main/move-dapp</a></p></blockquote><p>同步的打卡任务：</p><blockquote><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/WeLightProject/Web3-dApp-Camp/discussions/categories/projects-others">https://github.com/WeLightProject/Web3-dApp-Camp/discussions/categories/projects-others</a></p></blockquote><h2 id="h-1" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">1 节点启动</h2><p>下载最新的发行版 Starcoin 节点程序（MacOS 将其拷贝至<code>/usr/local/bin</code>目录即可）：</p><blockquote><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/starcoinorg/starcoin/releases">https://github.com/starcoinorg/starcoin/releases</a></p></blockquote><p>在此以<code>Starcoin</code>网络为基础，展现如何启动一个节点：</p><blockquote><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://starcoinorg.github.io/starcoin-cookbook/docs/getting-started/setup/">https://starcoinorg.github.io/starcoin-cookbook/docs/getting-started/setup/</a></p></blockquote><p>太长不看版——关键命令合集：</p><pre data-type="codeBlock" text="# 启动一个本地 dev 节点
$ starcoin -n dev
# 启动一个本地 dev 节点的同时打开控制台，-d 参数可以确保每次打开控制台时都保有历史的数据而不是重开
$ mkdir [folder_name]
$ cd [folder_name]
$ pwd
$ starcoin -d [path_to_your_data_folder] -n dev console
"><code><span class="hljs-meta prompt_"># </span><span class="bash">启动一个本地 dev 节点</span>
<span class="hljs-meta prompt_">$ </span><span class="bash">starcoin -n dev</span>
<span class="hljs-meta prompt_"># </span><span class="bash">启动一个本地 dev 节点的同时打开控制台，-d 参数可以确保每次打开控制台时都保有历史的数据而不是重开</span>
<span class="hljs-meta prompt_">$ </span><span class="bash"><span class="hljs-built_in">mkdir</span> [folder_name]</span>
<span class="hljs-meta prompt_">$ </span><span class="bash"><span class="hljs-built_in">cd</span> [folder_name]</span>
<span class="hljs-meta prompt_">$ </span><span class="bash"><span class="hljs-built_in">pwd</span></span>
<span class="hljs-meta prompt_">$ </span><span class="bash">starcoin -d [path_to_your_data_folder] -n dev console</span>
</code></pre><p>starcoin 控制台命令：</p><pre data-type="codeBlock" text="# 指定账户获得测试代币
starcoin% dev get-coin 0xb7c46353c6c0e3a2559d5b12cad981e4 -v 100STC
# 账户列表
starcoin% account list
# 单一账户情况查看
starcoin% account show 0xb7c46353c6c0e3a2559d5b12cad981e4
# 创建新账户
starcoin% account create -p [pwd]
"><code><span class="hljs-meta prompt_"># </span><span class="bash">指定账户获得测试代币</span>
<span class="hljs-meta prompt_">starcoin% </span><span class="bash">dev get-coin 0xb7c46353c6c0e3a2559d5b12cad981e4 -v 100STC</span>
<span class="hljs-meta prompt_"># </span><span class="bash">账户列表</span>
<span class="hljs-meta prompt_">starcoin% </span><span class="bash">account list</span>
<span class="hljs-meta prompt_"># </span><span class="bash">单一账户情况查看</span>
<span class="hljs-meta prompt_">starcoin% </span><span class="bash">account show 0xb7c46353c6c0e3a2559d5b12cad981e4</span>
<span class="hljs-meta prompt_"># </span><span class="bash">创建新账户</span>
<span class="hljs-meta prompt_">starcoin% </span><span class="bash">account create -p [<span class="hljs-built_in">pwd</span>]</span>
</code></pre><h2 id="h-2-move-mycounter" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">2 第一个 Move 合约 —— MyCounter</h2><p>最小可实践例子：</p><blockquote><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/starcoinorg/starcoin-cookbook/blob/main/examples/my-counter">https://github.com/starcoinorg/starcoin-cookbook/blob/main/examples/my-counter</a></p></blockquote><pre data-type="codeBlock" text="module MyCounterAddr::MyCounter {
     use StarcoinFramework::Signer;

     struct Counter has key, store {
        value:u64,
     }
     public fun init(account: &amp;signer){
        move_to(account, Counter{value:0});
     }
     public fun incr(account: &amp;signer) acquires Counter {
        let counter = borrow_global_mut&lt;Counter&gt;(Signer::address_of(account));
        counter.value = counter.value + 1;
     }

     public(script) fun init_counter(account: signer){
        Self::init(&amp;account)
     }

     public(script) fun incr_counter(account: signer)  acquires Counter {
        Self::incr(&amp;account)
     }
}
"><code>module MyCounterAddr::MyCounter {
     use StarcoinFramework::Signer;

     struct Counter has key, store {
        value:u64,
     }
     <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">init</span><span class="hljs-params">(account: &#x26;<span class="hljs-type">signer</span>)</span></span>{
        move_to(account, Counter{value:<span class="hljs-number">0</span>});
     }
     <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">incr</span><span class="hljs-params">(account: &#x26;<span class="hljs-type">signer</span>)</span></span> acquires Counter {
        let counter = borrow_global_mut&#x3C;Counter>(Signer::address_of(account));
        counter.value = counter.value + <span class="hljs-number">1</span>;
     }

     <span class="hljs-keyword">public</span>(script) <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">init_counter</span><span class="hljs-params">(account: <span class="hljs-type">signer</span>)</span></span>{
        Self::<span class="hljs-keyword">init</span>(&#x26;account)
     }

     <span class="hljs-keyword">public</span>(script) <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">incr_counter</span><span class="hljs-params">(account: <span class="hljs-type">signer</span>)</span></span>  acquires Counter {
        Self::incr(&#x26;account)
     }
}
</code></pre><p>MyCounter 源码分析</p><p>module 是发布在特定地址下的打包在一起的一组函数和结构体。使用script时需要与已发布的module或标准库一起运行，而标准库本身就是在 0x1 地址下发布的一组module。</p><p>module MyCounterAddr::MyCounter{ } 则在该MyCounterAddr地址下(对应Move.toml下的MyCounterAddr = &quot;0xb7c46353c6c0e3a2559d5b12cad981e4&quot;)创建一个module。</p><p>use StarcoinFramework::Signer，是使用标准库下的Signer module，Signer 是一种原生的类似 Resource 的不可复制的类型，它包含了交易发送者的地址。引入signer类型的原因之一是要明确显示哪些函数需要发送者权限，哪些不需要。因此，函数不能欺骗用户未经授权访问其 Resource。具体可参考<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/starcoinorg/starcoin-framework/blob/main/sources/Signer.move">源码</a>。</p><pre data-type="codeBlock" text="struct Counter has key, store {
        value:u64,
     }
"><code><span class="hljs-keyword">struct</span> <span class="hljs-title class_">Counter</span> has key, store {
        value:<span class="hljs-type">u64</span>,
     }
</code></pre><p>使用struct定义了一个叫做Counter的结构体，同时被 key,store两种限制符修饰，Move的类型系统灵活，每种类型都可以被四种限制符所修饰。这四种限制符我们称之为 abilities，它们定义了类型的值是否可以被复制、丢弃和存储。 这四种 abilities 限制符分别是: Copy, Drop, Store 和 Key.</p><p>它们的功能分别是：</p><ul><li><p>Copy - 被修饰的值可以被复制。</p></li><li><p>Drop - 被修饰的值在作用域结束时可以被丢弃。</p></li><li><p>Key - 被修饰的值可以作为键值对全局状态进行访问。</p></li><li><p>Store - 被修饰的值可以被存储到全局状态。</p></li></ul><p>这里用key,store修饰，则表示它不能被复制，也不能被丢弃或重新使用，但是它却可以被安全地存储和转移。</p><p>下面则是定义的方法，</p><pre data-type="codeBlock" text="public fun init(account: &amp;signer){
    move_to(account, Counter{value:0});
}
public fun incr(account: &amp;signer) acquires Counter {
    let counter = borrow_global_mut&lt;Counter&gt;(Signer::address_of(account));
    counter.value = counter.value + 1;
}
"><code><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">init</span><span class="hljs-params">(account: &#x26;<span class="hljs-type">signer</span>)</span></span>{
    move_to(account, Counter{value:<span class="hljs-number">0</span>});
}
<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">incr</span><span class="hljs-params">(account: &#x26;<span class="hljs-type">signer</span>)</span></span> acquires Counter {
    let counter = borrow_global_mut&#x3C;Counter>(Signer::address_of(account));
    counter.value = counter.value + <span class="hljs-number">1</span>;
}
</code></pre><p>定义格式则是:</p><p>public fun 函数名(参数：参数类型){ }</p><p>move函数默认是私有函数，只能在定义它们的模块中访问。关键字 public 将更改函数的默认可见性并使其公开，即可以从外部访问。</p><p>init方法参数是一个&amp;signer，意味着该方法必须是一个账户合法签名过后才可以调用，move_to则是move的一个原语，作用是发布、添加Counter资源到 signer 的地址下。Move的账户模型，code和data是存储在一个账户地址下的。</p><p>下面是列举的常用原语</p><ul><li><p>move_to&lt; T &gt;(&amp;signer, T)：发布、添加类型为 T 的资源到 signer 的地址下。</p></li><li><p>move_from&lt; T &gt;(addr: address): T - 从地址下删除类型为 T 的资源并返回这个资源。</p></li><li><p>borrow_global&lt; T &gt;(addr: address): &amp;T - 返回地址下类型为 T 的资源的不可变引用。</p></li><li><p>borrow_global_mut&lt; T &gt;(addr: address): &amp;mut T - 返回地址下类型为 T 的资源的可变引用。</p></li><li><p>exists&lt; T &gt;(address): bool：判断地址下是否有类型为 T 的资源。。</p></li></ul><p>incr方法参数也是一个&amp;signer，意味着该方法必须是一个账户合法签名过后才可以调用,</p><p>关键字 acquires，放在函数返回值之后，用来显式定义此函数获取的所有 Resource。</p><p>Signer::address_of(account) 从签名者中拿到address</p><p>borrow_global_mut上面有介绍到，可变借用到address下到resource Counter，然后将Counter结构体下的value进行+1操作。</p><p>这下面的两个方法则是script方法,它与上面两个函数有什么区别呢？</p><ul><li><p>public fun : 方法可以在任何模块中被调用。</p></li><li><p>public(script) fun：script function 是模块中的入口方法，表示该方法可以通过控制台发起一个交易来调用，就像本地执行脚本一样</p></li></ul><p>下个版本的 Move 会用 public entry fun 替代 public(script) fun</p><p>Self则是代表自身module。</p><pre data-type="codeBlock" text="  public(script) fun init_counter(account: signer){
        Self::init(&amp;account)
     }

     public(script) fun incr_counter(account: signer)  acquires Counter {
        Self::incr(&amp;account)
     }
"><code>  <span class="hljs-keyword">public</span>(script) <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">init_counter</span><span class="hljs-params">(account: <span class="hljs-type">signer</span>)</span></span>{
        Self::<span class="hljs-keyword">init</span>(&#x26;account)
     }

     <span class="hljs-keyword">public</span>(script) <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">incr_counter</span><span class="hljs-params">(account: <span class="hljs-type">signer</span>)</span></span>  acquires Counter {
        Self::incr(&#x26;account)
     }
</code></pre><h3 id="h-21" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2.1 编译</h3><p>下载第一个实例的源码：</p><pre data-type="codeBlock" text="$ git clone git@github.com:WeLightProject/Web3-dApp-Camp.git
$ cd Web3-dApp-Camp/move-dapp/my-counter
"><code>$ git clone git@github.com:WeLightProject<span class="hljs-operator">/</span>Web3<span class="hljs-operator">-</span>dApp<span class="hljs-operator">-</span>Camp.git
$ cd Web3<span class="hljs-operator">-</span>dApp<span class="hljs-operator">-</span>Camp<span class="hljs-operator">/</span>move<span class="hljs-operator">-</span>dapp<span class="hljs-operator">/</span>my<span class="hljs-operator">-</span>counter
</code></pre><p>Move的包管理工具为Move Package Manager(mpm),它类似于Rust的Cargo或者Node的NPM。 可以通过<code>mpm package new my-counter</code>来创建一个新项目，典型的目录结构为:</p><pre data-type="codeBlock" text="my-counter
├── Move.toml
└── sources
    └── MyCounter.move 
"><code>my<span class="hljs-operator">-</span>counter
├── Move.toml
└── sources
    └── MyCounter.move 
</code></pre><ul><li><p>sources用来存档Move的模块,它类似于与Java中的类文件。</p></li><li><p>Move.toml-用来存放配置文件：包括包的原数据、依赖和命名地址。</p></li><li><p>上述文件构成一个Move包(Move Package) 更详细的Move包管理参考<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://starcoinorg.github.io/starcoin-cookbook/zh/docs/move/move-language/packages/">文档</a></p></li></ul><p>修改<code>move.toml</code>中的地址为你用来部署的地址。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">image-20220727123922351</figcaption></figure><p>编译：</p><pre data-type="codeBlock" text="$ mpm release
"><code>$ mpm release
</code></pre><p>接下来会在<code>release</code>文件夹中，看到你编译好的二进制文件。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">image-20220727124134402</figcaption></figure><h3 id="h-22" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2.2 控制台部署</h3><p>在 Starcoin Console 中执行如下命令即可部署：</p><pre data-type="codeBlock" text="starcoin% dev deploy [path to blob] -s [addr] -b
"><code>starcoin% dev deploy <span class="hljs-selector-attr">[path to blob]</span> -s <span class="hljs-selector-attr">[addr]</span> -<span class="hljs-selector-tag">b</span>
</code></pre><blockquote><p>-s 即--sender,-b即--blocking，表示阻塞等待命令执行完成</p></blockquote><p>如果遇到账户被锁，用 <code>unlock</code>命令解锁即可。</p><pre data-type="codeBlock" text="account unlock [addr] -p [pwd]
"><code>account unlock <span class="hljs-selector-attr">[addr]</span> -<span class="hljs-selector-tag">p</span> <span class="hljs-selector-attr">[pwd]</span>
</code></pre><p>其中<code>pwd</code>即是在<code>1.2</code>中创建的密码。</p><p>部署成功后能看到：</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">image-20220727124625807</figcaption></figure><blockquote><p>💡需要注意的是，在Move中代码存储在个人的地址上，而非像以太坊那样的公共地址上。因此合约部署后并不会创建新地址，当我们想要调用合约时需要采用部署合约人的地址+合约名来调用该合约。</p></blockquote><h3 id="h-23" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2.3 控制台调用</h3><blockquote><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://starcoinorg.github.io/starcoin-cookbook/docs/move/interacting-with-the-contract">https://starcoinorg.github.io/starcoin-cookbook/docs/move/interacting-with-the-contract</a></p></blockquote><ol><li><p>调用 init_counter 脚本函数来初始化资源。</p></li></ol><pre data-type="codeBlock" text="starcoin% account execute-function --function {MyCounterAddr-in-Move.toml}::MyCounter::init_counter -s 0x23dc2c167fcd16e28917765848e189ce -b
"><code>starcoin<span class="hljs-operator">%</span> account execute<span class="hljs-operator">-</span><span class="hljs-function"><span class="hljs-keyword">function</span> --<span class="hljs-title"><span class="hljs-keyword">function</span></span> </span>{MyCounterAddr<span class="hljs-operator">-</span>in<span class="hljs-operator">-</span>Move.toml}::MyCounter::init_counter <span class="hljs-operator">-</span>s <span class="hljs-number">0x23dc2c167fcd16e28917765848e189ce</span> <span class="hljs-operator">-</span>b
</code></pre><p>其中:</p><ul><li><p><code>{MyCounterAddr-in-Move.toml}::MyCounter::init_counter</code>为完整的函数链上地址，包括合约所在地址+包名+函数名。</p></li><li><p>-s 即--sender,-b即--blocking，表示阻塞等待命令执行完成</p></li></ul><ol><li><p>查看Counter资源</p></li></ol><pre data-type="codeBlock" text="starcoin% state get resource 0x23dc2c167fcd16e28917765848e189ce 0x23dc2c167fcd16e28917765848e189ce::MyCounter::Counter
"><code>starcoin% state get resource <span class="hljs-number">0x23dc2c167fcd16e28917765848e189ce</span> <span class="hljs-number">0x23dc2c167fcd16e28917765848e189ce</span>::MyCounter::Counter
</code></pre><p>在Move中合约的数据被称为<code>资源(resource)</code>，由于读取数据不改变链上状态，因此不需要-s -b，不会执行交易，也不消耗状态。</p><blockquote><p>感兴趣的同学可以试着调用<code>incr_counter</code>，并再次查看<code>Counter</code>是否+1。</p></blockquote>]]></content:encoded>
            <author>apecoder@newsletter.paragraph.com (Web3dAppDevCamp)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/7d504b70a2be3b6f187bf1f2e2e7a2ab60f4333d3a413ea660a01e0abf729591.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[Staker | Web3.0 dApp Dev 0x09]]></title>
            <link>https://paragraph.com/@apecoder/staker-web3-0-dapp-dev-0x09</link>
            <guid>kaWUrstKgihcmGoT0aDL</guid>
            <pubDate>Tue, 19 Jul 2022 00:22:09 GMT</pubDate>
            <description><![CDATA[国内用户请加微信：19726581 Authors: Fenix, msfew0x00 GoalBuidl a decentralized Staking dApp. This example also corresponds to Challenge 0x01 in SpeedrunEthereum (an official Ethereum developer challenge):https://speedrunethereum.com/challenge/decentralized-stakingAn example of one of these completions can be found at:Contract: https://rinkeby.etherscan.io/address/0x4707468C95558E9B2F339c2A41DAEF483Ce11104 dApp: https://duckgo_staking.surge.sh/image-202207171211476670x01 What is StakingStaking, which t...]]></description>
            <content:encoded><![CDATA[<blockquote><p>国内用户请加微信：19726581</p><p>Authors: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/zhenfeng-zhu">Fenix</a>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/fewwwww">msfew</a></p></blockquote><h1 id="h-0x00-goal" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x00 Goal</h1><p>Buidl a decentralized Staking dApp.</p><p>This example also corresponds to <code>Challenge 0x01</code> in <code>SpeedrunEthereum</code> (an official Ethereum developer challenge):</p><blockquote><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://speedrunethereum.com/challenge/decentralized-staking">https://speedrunethereum.com/challenge/decentralized-staking</a></p></blockquote><p>An example of one of these completions can be found at:</p><blockquote><p>Contract: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://rinkeby.etherscan.io/address/0x4707468C95558E9B2F339c2A41DAEF483Ce11104">https://rinkeby.etherscan.io/address/0x4707468C95558E9B2F339c2A41DAEF483Ce11104</a> dApp: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://duckgo_staking.surge.sh/">https://duckgo_staking.surge.sh/</a></p></blockquote><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">image-20220717121147667</figcaption></figure><h1 id="h-0x01-what-is-staking" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x01 What is Staking</h1><p>Staking, which translates to pledge, staking mining, or staking of interest, is the algorithm used to generate new blocks, and is derived from Proof of Stake.</p><p>If you&apos;re familiar with how Bitcoin works, you&apos;re probably familiar with Proof of Work (PoW). This mechanism allows transactions to be collected into blocks. These blocks are then linked together to create a blockchain.</p><p>Specifically, miners compete to solve complex mathematical puzzles, and whoever solves the puzzle first is entitled to add the next block to the blockchain. Proof of workload has proven to be a very powerful mechanism to facilitate consensus in a decentralized manner. The problem is that this mechanism involves a lot of arbitrary computation. Miners are scrambling to solve the puzzle just to maintain network security and nothing else.</p><p>Moving on to proof of stake, the main idea is that participants can lock in tokens (their &quot;pledged interest&quot;) and the protocol will randomly assign rights to one of them for verification of the next block at a given time interval. Usually, the probability of being selected is proportional to the number of tokens: the more tokens locked, the better the chances.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/48cc0a40bde9c6e3604d30ea448761f0e37b43c56fbe2a318cce8f4e1eb06869.png" alt="Staking &amp; Mining" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">Staking &amp; Mining</figcaption></figure><p>In the cryptocurrency market, mining has been gradually replaced by staking in recent years, with the benefit of lower power consumption and passive income than the former.</p><h1 id="h-0x02-speed-run-web3" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x02 Speed Run Web3</h1><p>Some students may not have experience with web3 related development, so here is a speed run on your behalf to facilitate a quick introduction to the development on Ether.</p><p><strong>Prerequisites</strong></p><ul><li><p>metamask Wallet</p></li></ul><p><strong>Environment</strong></p><ul><li><p>nodejs</p></li><li><p>yarn</p></li><li><p>git</p></li><li><p>vscode</p></li></ul><p><strong>Tech Stack</strong></p><ul><li><p>Framework: scaffold-eth</p></li><li><p>Frontend: react</p></li><li><p>Contract Development: hardhat</p></li></ul><p><strong>Step 1: Scaffolding</strong></p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/scaffold-eth/scaffold-eth">https://github.com/scaffold-eth/scaffold-eth</a></p><pre data-type="codeBlock" text="git clone https://github.com/scaffold-eth/scaffold-eth.git
cd scaffold-eth
yarn install
"><code>git <span class="hljs-built_in">clone</span> https://github.com/scaffold-eth/scaffold-eth.git
<span class="hljs-built_in">cd</span> scaffold-eth
yarn install
</code></pre><p><strong>Step 2: Start a local network</strong></p><pre data-type="codeBlock" text="cd scaffold-eth
yarn chain
"><code><span class="hljs-built_in">cd</span> scaffold-eth
yarn chain
</code></pre><p><strong>Step 3: Deploy Smart Contracts</strong></p><pre data-type="codeBlock" text="cd scaffold-eth
yarn deploy
"><code><span class="hljs-built_in">cd</span> scaffold-eth
yarn deploy
</code></pre><p><strong>Step 4: Open the front-end page</strong></p><pre data-type="codeBlock" text="cd scaffold-eth
yarn start
"><code><span class="hljs-built_in">cd</span> scaffold-eth
yarn start
</code></pre><ul><li><p>Technology Stack</p><ul><li><p>Top Level Technology Stack</p><ul><li><p>solidity contract programming language</p></li><li><p>hardhat local development test chain</p></li><li><p>react front-end</p></li><li><p>etherseth api sdk</p></li><li><p>antd front-end components ui</p></li></ul></li><li><p>Libraries &amp; Components &amp; Services</p><ul><li><p>Eth-components</p></li><li><p>Eth-services</p></li><li><p>Command Line</p></li></ul></li><li><p>Underlying Foundation</p><ul><li><p>the graph</p></li><li><p>tenderly</p></li><li><p>etherscan</p></li><li><p>rpc</p></li><li><p>blocknative</p></li><li><p>L2/Sidechain Services</p><ul><li><p>Arbitrum</p></li><li><p>Optimism</p></li><li><p>Graph Node</p></li></ul></li></ul></li><li><p>Examples</p><ul><li><p>General</p><ul><li><p>simple dao</p></li><li><p>Diamond Standard</p></li><li><p>Meta-Multi-Sig Wallet</p></li><li><p>Minimal Proxy</p></li><li><p>Minimum Viable Payment Channel</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://punkwallet.io/">PunkWallet.io</a></p></li><li><p>Push The Button - Multi-player Turn Based Game</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://radwallet.io/">radwallet.io</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://signator.io/">Signator.io</a></p></li><li><p>Simple Stream</p></li><li><p>Token Allocator</p></li><li><p>Streaming Meta Multi Sig</p></li></ul></li><li><p>DeFi</p><ul><li><p>Bonding Curve</p></li><li><p>rTokens</p></li><li><p>Quadratic Funding</p></li><li><p>Uniswapper</p></li><li><p>Lender</p></li><li><p>Aave Flash Loans Intro</p></li><li><p>Aave Ape</p></li><li><p>DeFi Subgraphs</p></li></ul></li><li><p>NFT</p><ul><li><p>Simple NFT</p></li><li><p>Simple ERC-1155 NFT</p></li><li><p>Chainlink VRF NFT</p></li><li><p>Merkle Mint NFT</p></li><li><p>Nifty Viewer</p></li><li><p>NFT Auction</p></li><li><p>NFT Signature Based Auction</p></li></ul></li><li><p>Security</p><ul><li><p>Honeypot</p></li><li><p>Re-entrancy Attack</p></li><li><p>Denial of Service</p></li></ul></li><li><p>Infrastructure</p><ul><li><p>ChainLink</p></li></ul></li><li><p>Layer2</p><ul><li><p>Optimism Starter Pack</p></li><li><p>Optimism NFT</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://xnft.io/">xNFT.io</a></p></li></ul></li></ul></li></ul></li></ul><h1 id="h-0x03-staking-contract" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x03 Staking Contract</h1><p>We all know that the most important part of dApp development is writing smart contracts, so let&apos;s analyze the basic format of a Staking contract.</p><blockquote><p>Pledge (stake) a certain amount of tokens (threshold) within a certain time (deadline). After the expiration date, you can transfer (execute) the tokens to another contract, or withdraw (withdraw) the tokens.</p></blockquote><p>So we abstracted out three key functions.</p><ol><li><p><code>stake()</code></p></li><li><p><code>execute()</code></p></li><li><p><code>withdraw()</code></p></li></ol><p>scaffold-eth also provides us with such a scaffold, just pull down the code and we will build on it step by step this time.</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/scaffold-eth/scaffold-eth-challenges">https://github.com/scaffold-eth/scaffold-eth-challenges</a></p><pre data-type="codeBlock" text="git clone https://github.com/scaffold-eth/scaffold-eth-challenges.git
cd scaffold-eth-challenges
git checkout challenge-1-decentralized-staking
yarn install
"><code>git clone https:<span class="hljs-comment">//github.com/scaffold-eth/scaffold-eth-challenges.git</span>
cd scaffold<span class="hljs-operator">-</span>eth<span class="hljs-operator">-</span>challenges
git checkout challenge<span class="hljs-number">-1</span><span class="hljs-operator">-</span>decentralized<span class="hljs-operator">-</span>staking
yarn install
</code></pre><p>Then open three terminal windows and execute the following three commands:</p><pre data-type="codeBlock" text="yarn chain
"><code></code></pre><pre data-type="codeBlock" text="yarn start
"><code>yarn <span class="hljs-keyword">start</span>
</code></pre><pre data-type="codeBlock" text="yarn deploy --reset
"><code>yarn deploy <span class="hljs-operator">-</span><span class="hljs-operator">-</span>reset
</code></pre><h1 id="h-0x04-live-coding" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x04 Live Coding</h1><h2 id="h-41-stake" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">4.1 stake</h2><ul><li><p>Key point 1: Stake a certain amount of eth at a time.</p></li></ul><pre data-type="codeBlock" text="pragma solidity 0.8.4;

import &quot;hardhat/console.sol&quot;;
import &quot;./ExampleExternalContract.sol&quot;;

contract Staker {
    mapping(address =&gt; uint256) public balances;

    event Stake(address indexed staker, uint256 amount);

    function stake() public payable {
        balances[msg.sender] += msg.value;
        emit Stake(msg.sender, msg.value);
    }
}
"><code><span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> 0.8.4;</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">"hardhat/console.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./ExampleExternalContract.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Staker</span> </span>{
    <span class="hljs-keyword">mapping</span>(<span class="hljs-keyword">address</span> <span class="hljs-operator">=</span><span class="hljs-operator">></span> <span class="hljs-keyword">uint256</span>) <span class="hljs-keyword">public</span> balances;

    <span class="hljs-function"><span class="hljs-keyword">event</span> <span class="hljs-title">Stake</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> <span class="hljs-keyword">indexed</span> staker, <span class="hljs-keyword">uint256</span> amount</span>)</span>;

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">stake</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
        balances[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">+</span><span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span>;
        <span class="hljs-keyword">emit</span> Stake(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span>);
    }
}
</code></pre><ul><li><p>Key point 2, deploy the script to remove the constructor&apos;s parameters</p></li></ul><pre data-type="codeBlock" text="// deploy/01_deploy_staker.js
// ....

await deploy(&apos;Staker&apos;, {
  // Learn more about args here: https://www.npmjs.com/package/hardhat-deploy#deploymentsdeploy
  from: deployer,
  // args: [exampleExternalContract.address],
  log: true,
});

//...
"><code><span class="hljs-comment">// deploy/01_deploy_staker.js</span>
<span class="hljs-comment">// ....</span>

await <span class="hljs-title function_">deploy</span><span class="hljs-params">(<span class="hljs-string">'Staker'</span>, {
  <span class="hljs-comment">// Learn more about args here: https://www.npmjs.com/package/hardhat-deploy#deploymentsdeploy</span>
  from: deployer,
  <span class="hljs-comment">// args: [exampleExternalContract.address],</span>
  <span class="hljs-built_in">log</span>: <span class="hljs-literal">true</span>,
})</span>;

<span class="hljs-comment">//...</span>
</code></pre><ul><li><p>Key Point 3, Deployment</p></li></ul><pre data-type="codeBlock" text="yarn deploy --reset
"><code>yarn deploy <span class="hljs-operator">-</span><span class="hljs-operator">-</span>reset
</code></pre><ul><li><p>Key point 4, airdrop some test coins</p></li><li><p>Key point 5, test staking</p></li></ul><h2 id="h-42-execute" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">4.2 execute</h2><p>The funds raised are transferred to another contract after certain conditions are met.</p><ul><li><p>Key point 1, another contract</p></li></ul><pre data-type="codeBlock" text="contract ExampleExternalContract {

  bool public completed;

  function complete() public payable {
    completed = true;
  }

}
"><code><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">ExampleExternalContract</span> </span>{

  <span class="hljs-keyword">bool</span> <span class="hljs-keyword">public</span> completed;

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">complete</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
    completed <span class="hljs-operator">=</span> <span class="hljs-literal">true</span>;
  }

}
</code></pre><p>It&apos;s simple, there is a flag to indicate whether it is finished or not.</p><ul><li><p>Key point 2, the constructor</p></li></ul><p>In the stake contract, to bring in this contract, there is a constructor.</p><pre data-type="codeBlock" text="ExampleExternalContract public exampleExternalContract;

constructor(address exampleExternalContractAddress) public {
        exampleExternalContract = ExampleExternalContract(
            exampleExternalContractAddress
        );
}
"><code>ExampleExternalContract <span class="hljs-keyword">public</span> exampleExternalContract;

<span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> exampleExternalContractAddress</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        exampleExternalContract <span class="hljs-operator">=</span> ExampleExternalContract(
            exampleExternalContractAddress
        );
}
</code></pre><ul><li><p>Key point 3, initialize when deploying</p></li></ul><pre data-type="codeBlock" text="// deploy/01_deploy_staker.js
// ....

await deploy(&apos;Staker&apos;, {
  // Learn more about args here: https://www.npmjs.com/package/hardhat-deploy#deploymentsdeploy
  from: deployer,
  args: [exampleExternalContract.address],
  log: true,
});

//...
"><code><span class="hljs-comment">// deploy/01_deploy_staker.js</span>
<span class="hljs-comment">// ....</span>

await deploy(<span class="hljs-string">'Staker'</span>, {
  <span class="hljs-comment">// Learn more about args here: https://www.npmjs.com/package/hardhat-deploy#deploymentsdeploy</span>
  <span class="hljs-keyword">from</span>: deployer,
  args: [exampleExternalContract.<span class="hljs-built_in">address</span>],
  log: <span class="hljs-literal">true</span>,
});

<span class="hljs-comment">//...</span>
</code></pre><ul><li><p>Key Point 4, Staking Limit</p></li></ul><pre data-type="codeBlock" text="uint256 public constant threshold = 1 ether;
"><code><span class="hljs-keyword">uint256</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">constant</span> threshold <span class="hljs-operator">=</span> <span class="hljs-number">1</span> <span class="hljs-literal">ether</span>;
</code></pre><ul><li><p>Key point 5, transfer to the second contract.</p></li></ul><pre data-type="codeBlock" text="    function execute() public {
        uint256 contractBalance = address(this).balance;

        // check the contract has enough ETH to reach the treshold
        require(contractBalance &gt;= threshold, &quot;Threshold not reached&quot;);

        // Execute the external contract, transfer all the balance to the contract
        // (bool sent, bytes memory data) = exampleExternalContract.complete{value: contractBalance}();
        (bool sent, ) = address(exampleExternalContract).call{
            value: contractBalance
        }(abi.encodeWithSignature(&quot;complete()&quot;));
        require(sent, &quot;exampleExternalContract.complete failed&quot;);
    }
"><code>    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">execute</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        <span class="hljs-keyword">uint256</span> contractBalance <span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>).<span class="hljs-built_in">balance</span>;

        <span class="hljs-comment">// check the contract has enough ETH to reach the treshold</span>
        <span class="hljs-built_in">require</span>(contractBalance <span class="hljs-operator">></span><span class="hljs-operator">=</span> threshold, <span class="hljs-string">"Threshold not reached"</span>);

        <span class="hljs-comment">// Execute the external contract, transfer all the balance to the contract</span>
        <span class="hljs-comment">// (bool sent, bytes memory data) = exampleExternalContract.complete{value: contractBalance}();</span>
        (<span class="hljs-keyword">bool</span> sent, ) <span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(exampleExternalContract).<span class="hljs-built_in">call</span>{
            <span class="hljs-built_in">value</span>: contractBalance
        }(<span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encodeWithSignature</span>(<span class="hljs-string">"complete()"</span>));
        <span class="hljs-built_in">require</span>(sent, <span class="hljs-string">"exampleExternalContract.complete failed"</span>);
    }
</code></pre><ul><li><p>The final code is as follows</p></li></ul><pre data-type="codeBlock" text="// SPDX-License-Identifier: MIT
pragma solidity 0.8.4;

import &quot;hardhat/console.sol&quot;;
import &quot;./ExampleExternalContract.sol&quot;;

contract Staker {
    ExampleExternalContract public exampleExternalContract;

    mapping(address =&gt; uint256) public balances;

    uint256 public constant threshold = 1 ether;

    event Stake(address indexed staker, uint256 amount);

    constructor(address exampleExternalContractAddress) public {
        exampleExternalContract = ExampleExternalContract(
            exampleExternalContractAddress
        );
    }

    function stake() public payable {
        balances[msg.sender] += msg.value;
        emit Stake(msg.sender, msg.value);
    }

    function execute() public {
        uint256 contractBalance = address(this).balance;

        require(contractBalance &gt;= threshold, &quot;Threshold not reached&quot;);

        (bool sent, ) = address(exampleExternalContract).call{
            value: contractBalance
        }(abi.encodeWithSignature(&quot;complete()&quot;));
        require(sent, &quot;exampleExternalContract.complete() failed&quot;);
    }
}
"><code><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> 0.8.4;</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">"hardhat/console.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./ExampleExternalContract.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Staker</span> </span>{
    ExampleExternalContract <span class="hljs-keyword">public</span> exampleExternalContract;

    <span class="hljs-keyword">mapping</span>(<span class="hljs-keyword">address</span> <span class="hljs-operator">=</span><span class="hljs-operator">></span> <span class="hljs-keyword">uint256</span>) <span class="hljs-keyword">public</span> balances;

    <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">constant</span> threshold <span class="hljs-operator">=</span> <span class="hljs-number">1</span> <span class="hljs-literal">ether</span>;

    <span class="hljs-function"><span class="hljs-keyword">event</span> <span class="hljs-title">Stake</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> <span class="hljs-keyword">indexed</span> staker, <span class="hljs-keyword">uint256</span> amount</span>)</span>;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> exampleExternalContractAddress</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        exampleExternalContract <span class="hljs-operator">=</span> ExampleExternalContract(
            exampleExternalContractAddress
        );
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">stake</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
        balances[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">+</span><span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span>;
        <span class="hljs-keyword">emit</span> Stake(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">execute</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        <span class="hljs-keyword">uint256</span> contractBalance <span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>).<span class="hljs-built_in">balance</span>;

        <span class="hljs-built_in">require</span>(contractBalance <span class="hljs-operator">></span><span class="hljs-operator">=</span> threshold, <span class="hljs-string">"Threshold not reached"</span>);

        (<span class="hljs-keyword">bool</span> sent, ) <span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(exampleExternalContract).<span class="hljs-built_in">call</span>{
            <span class="hljs-built_in">value</span>: contractBalance
        }(<span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encodeWithSignature</span>(<span class="hljs-string">"complete()"</span>));
        <span class="hljs-built_in">require</span>(sent, <span class="hljs-string">"exampleExternalContract.complete() failed"</span>);
    }
}
</code></pre><ul><li><p>Deployment</p></li></ul><pre data-type="codeBlock" text="yarn deploy --reset
"><code>yarn deploy <span class="hljs-operator">-</span><span class="hljs-operator">-</span>reset
</code></pre><ul><li><p>Airdrop test coins</p></li><li><p>stake some coins reach the limit</p></li><li><p>test execute</p></li></ul><h2 id="h-43-withdraw" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">4.3 withdraw</h2><p>Withdrawing the staked money is relatively simple - just transfer the money out.</p><pre data-type="codeBlock" text="    function withdraw() public {
        uint256 userBalance = balances[msg.sender];

        require(userBalance &gt; 0, &quot;You don&apos;t have balance to withdraw&quot;);

        balances[msg.sender] = 0;

        (bool sent, ) = msg.sender.call{value: userBalance}(&quot;&quot;);
        require(sent, &quot;Failed to send user balance back to the user&quot;);
    }
"><code>    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">withdraw</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        <span class="hljs-keyword">uint256</span> userBalance <span class="hljs-operator">=</span> balances[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>];

        <span class="hljs-built_in">require</span>(userBalance <span class="hljs-operator">></span> <span class="hljs-number">0</span>, <span class="hljs-string">"You don't have balance to withdraw"</span>);

        balances[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">=</span> <span class="hljs-number">0</span>;

        (<span class="hljs-keyword">bool</span> sent, ) <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>.<span class="hljs-built_in">call</span>{<span class="hljs-built_in">value</span>: userBalance}(<span class="hljs-string">""</span>);
        <span class="hljs-built_in">require</span>(sent, <span class="hljs-string">"Failed to send user balance back to the user"</span>);
    }
</code></pre><ul><li><p>The complete code is as follows</p></li></ul><pre data-type="codeBlock" text="// SPDX-License-Identifier: MIT
pragma solidity 0.8.4;

import &quot;hardhat/console.sol&quot;;
import &quot;./ExampleExternalContract.sol&quot;;

contract Staker {
    ExampleExternalContract public exampleExternalContract;

    mapping(address =&gt; uint256) public balances;

    uint256 public constant threshold = 1 ether;

    uint256 public deadline = block.timestamp + 30 seconds;

    event Stake(address indexed sender, uint256 amount);

    constructor(address exampleExternalContractAddress) public {
        exampleExternalContract = ExampleExternalContract(
            exampleExternalContractAddress
        );
    }

    function stake() public payable {
        balances[msg.sender] += msg.value;

        emit Stake(msg.sender, msg.value);
    }

    function execute() public {
        uint256 contractBalance = address(this).balance;

        require(contractBalance &gt;= threshold, &quot;Threshold not reached&quot;);

        (bool sent, ) = address(exampleExternalContract).call{
            value: contractBalance
        }(abi.encodeWithSignature(&quot;complete()&quot;));
        require(sent, &quot;exampleExternalContract.complete failed&quot;);
    }

    function withdraw() public {
        uint256 userBalance = balances[msg.sender];

        require(userBalance &gt; 0, &quot;You don&apos;t have balance to withdraw&quot;);

        balances[msg.sender] = 0;

        (bool sent, ) = msg.sender.call{value: userBalance}(&quot;&quot;);
        require(sent, &quot;Failed to send user balance back to the user&quot;);
    }
}
"><code><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> 0.8.4;</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">"hardhat/console.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./ExampleExternalContract.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Staker</span> </span>{
    ExampleExternalContract <span class="hljs-keyword">public</span> exampleExternalContract;

    <span class="hljs-keyword">mapping</span>(<span class="hljs-keyword">address</span> <span class="hljs-operator">=</span><span class="hljs-operator">></span> <span class="hljs-keyword">uint256</span>) <span class="hljs-keyword">public</span> balances;

    <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">constant</span> threshold <span class="hljs-operator">=</span> <span class="hljs-number">1</span> <span class="hljs-literal">ether</span>;

    <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">public</span> deadline <span class="hljs-operator">=</span> <span class="hljs-built_in">block</span>.<span class="hljs-built_in">timestamp</span> <span class="hljs-operator">+</span> <span class="hljs-number">30</span> <span class="hljs-literal">seconds</span>;

    <span class="hljs-function"><span class="hljs-keyword">event</span> <span class="hljs-title">Stake</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> <span class="hljs-keyword">indexed</span> sender, <span class="hljs-keyword">uint256</span> amount</span>)</span>;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> exampleExternalContractAddress</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        exampleExternalContract <span class="hljs-operator">=</span> ExampleExternalContract(
            exampleExternalContractAddress
        );
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">stake</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
        balances[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">+</span><span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span>;

        <span class="hljs-keyword">emit</span> Stake(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">execute</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        <span class="hljs-keyword">uint256</span> contractBalance <span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>).<span class="hljs-built_in">balance</span>;

        <span class="hljs-built_in">require</span>(contractBalance <span class="hljs-operator">></span><span class="hljs-operator">=</span> threshold, <span class="hljs-string">"Threshold not reached"</span>);

        (<span class="hljs-keyword">bool</span> sent, ) <span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(exampleExternalContract).<span class="hljs-built_in">call</span>{
            <span class="hljs-built_in">value</span>: contractBalance
        }(<span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encodeWithSignature</span>(<span class="hljs-string">"complete()"</span>));
        <span class="hljs-built_in">require</span>(sent, <span class="hljs-string">"exampleExternalContract.complete failed"</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">withdraw</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        <span class="hljs-keyword">uint256</span> userBalance <span class="hljs-operator">=</span> balances[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>];

        <span class="hljs-built_in">require</span>(userBalance <span class="hljs-operator">></span> <span class="hljs-number">0</span>, <span class="hljs-string">"You don't have balance to withdraw"</span>);

        balances[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">=</span> <span class="hljs-number">0</span>;

        (<span class="hljs-keyword">bool</span> sent, ) <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>.<span class="hljs-built_in">call</span>{<span class="hljs-built_in">value</span>: userBalance}(<span class="hljs-string">""</span>);
        <span class="hljs-built_in">require</span>(sent, <span class="hljs-string">"Failed to send user balance back to the user"</span>);
    }
}
</code></pre><ul><li><p>Deployment</p></li></ul><pre data-type="codeBlock" text="yarn deploy --reset
"><code>yarn deploy <span class="hljs-operator">-</span><span class="hljs-operator">-</span>reset
</code></pre><ul><li><p>Airdrop test coins</p></li><li><p>stake some coins</p></li><li><p>test withdraw</p></li></ul><h2 id="h-44-add-time-or-staking-expiration-restrictions" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">4.4 Add time or staking expiration restrictions</h2><p>There are two criteria to judge here</p><p>The first is whether the time has been reached, and the other is whether the pledge has been completed.</p><ul><li><p>Whether the first one is completed or not, just go directly to the mark of the other contract</p></li></ul><pre data-type="codeBlock" text="        modifier stakeNotCompleted() {
        bool completed = exampleExternalContract.completed();
        require(!completed, &quot;staking process is already completed&quot;);
        _;
    }
"><code>        <span class="hljs-function"><span class="hljs-keyword">modifier</span> <span class="hljs-title">stakeNotCompleted</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">bool</span> completed <span class="hljs-operator">=</span> exampleExternalContract.completed();
        <span class="hljs-built_in">require</span>(<span class="hljs-operator">!</span>completed, <span class="hljs-string">"staking process is already completed"</span>);
        <span class="hljs-keyword">_</span>;
    }
</code></pre><ul><li><p>Is the second one up to time?</p><ul><li><p>The first is to have a deadline variable</p></li></ul><pre data-type="codeBlock" text="uint256 public deadline = block.timestamp + 60 seconds;
"><code><span class="hljs-keyword">uint256</span> <span class="hljs-keyword">public</span> deadline <span class="hljs-operator">=</span> <span class="hljs-built_in">block</span>.<span class="hljs-built_in">timestamp</span> <span class="hljs-operator">+</span> <span class="hljs-number">60</span> <span class="hljs-literal">seconds</span>;
</code></pre><ul><li><p>Then there is also a timeLeft function</p></li></ul><pre data-type="codeBlock" text="        function timeLeft() public view returns (uint256 timeleft) {
        if (block.timestamp &gt;= deadline) {
            return 0;
        } else {
            return deadline - block.timestamp;
        }
    }
"><code>        <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">timeLeft</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span> timeleft</span>) </span>{
        <span class="hljs-keyword">if</span> (<span class="hljs-built_in">block</span>.<span class="hljs-built_in">timestamp</span> <span class="hljs-operator">></span><span class="hljs-operator">=</span> deadline) {
            <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">return</span> deadline <span class="hljs-operator">-</span> <span class="hljs-built_in">block</span>.<span class="hljs-built_in">timestamp</span>;
        }
    }
</code></pre><ul><li><p>Next is the deadlineReached function</p></li></ul><pre data-type="codeBlock" text="        modifier deadlineReached(bool requireReached) {
        uint256 timeRemaining = timeLeft();
        if (requireReached) {
            require(timeRemaining == 0, &quot;deadline is not reached yet&quot;);
        } else {
            require(timeRemaining &gt; 0, &quot;deadline has already reached&quot;);
        }
        _;
    }
"><code>        <span class="hljs-function"><span class="hljs-keyword">modifier</span> <span class="hljs-title">deadlineReached</span>(<span class="hljs-params"><span class="hljs-keyword">bool</span> requireReached</span>) </span>{
        <span class="hljs-keyword">uint256</span> timeRemaining <span class="hljs-operator">=</span> timeLeft();
        <span class="hljs-keyword">if</span> (requireReached) {
            <span class="hljs-built_in">require</span>(timeRemaining <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">0</span>, <span class="hljs-string">"deadline is not reached yet"</span>);
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-built_in">require</span>(timeRemaining <span class="hljs-operator">></span> <span class="hljs-number">0</span>, <span class="hljs-string">"deadline has already reached"</span>);
        }
        <span class="hljs-keyword">_</span>;
    }
</code></pre></li><li><p>How to modify these functions</p><ul><li><p>stake</p></li></ul><pre data-type="codeBlock" text="    function stake() public payable deadlineReached(false) stakeNotCompleted {
        balances[msg.sender] += msg.value;
        emit Stake(msg.sender, msg.value);
    }
"><code>    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">stake</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> <span class="hljs-title">deadlineReached</span>(<span class="hljs-params"><span class="hljs-literal">false</span></span>) <span class="hljs-title">stakeNotCompleted</span> </span>{
        balances[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">+</span><span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span>;
        <span class="hljs-keyword">emit</span> Stake(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span>);
    }
</code></pre><ul><li><p>execute function</p></li></ul><pre data-type="codeBlock" text="    function execute() public stakeNotCompleted deadlineReached(false) {
        uint256 contractBalance = address(this).balance;

        require(contractBalance &gt;= threshold, &quot;Threshold not reached&quot;);

        (bool sent, ) = address(exampleExternalContract).call{
            value: contractBalance
        }(abi.encodeWithSignature(&quot;complete()&quot;));
        require(sent, &quot;exampleExternalContract.complete() failed&quot;);
    }
"><code>    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">execute</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title">stakeNotCompleted</span> <span class="hljs-title">deadlineReached</span>(<span class="hljs-params"><span class="hljs-literal">false</span></span>) </span>{
        <span class="hljs-keyword">uint256</span> contractBalance <span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>).<span class="hljs-built_in">balance</span>;

        <span class="hljs-built_in">require</span>(contractBalance <span class="hljs-operator">></span><span class="hljs-operator">=</span> threshold, <span class="hljs-string">"Threshold not reached"</span>);

        (<span class="hljs-keyword">bool</span> sent, ) <span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(exampleExternalContract).<span class="hljs-built_in">call</span>{
            <span class="hljs-built_in">value</span>: contractBalance
        }(<span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encodeWithSignature</span>(<span class="hljs-string">"complete()"</span>));
        <span class="hljs-built_in">require</span>(sent, <span class="hljs-string">"exampleExternalContract.complete() failed"</span>);
    }
</code></pre><ul><li><p>withdraw function</p></li></ul><pre data-type="codeBlock" text="    function withdraw() public deadlineReached(true) stakeNotCompleted {
        uint256 userBalance = balances[msg.sender];

        require(userBalance &gt; 0, &quot;You don&apos;t have balance to withdraw&quot;);

        balances[msg.sender] = 0;

        (bool sent, ) = msg.sender.call{value: userBalance}(&quot;&quot;);
        require(sent, &quot;Failed to send user balance back to the user&quot;);
    }
"><code>    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">withdraw</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title">deadlineReached</span>(<span class="hljs-params"><span class="hljs-literal">true</span></span>) <span class="hljs-title">stakeNotCompleted</span> </span>{
        <span class="hljs-keyword">uint256</span> userBalance <span class="hljs-operator">=</span> balances[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>];

        <span class="hljs-built_in">require</span>(userBalance <span class="hljs-operator">></span> <span class="hljs-number">0</span>, <span class="hljs-string">"You don't have balance to withdraw"</span>);

        balances[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">=</span> <span class="hljs-number">0</span>;

        (<span class="hljs-keyword">bool</span> sent, ) <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>.<span class="hljs-built_in">call</span>{<span class="hljs-built_in">value</span>: userBalance}(<span class="hljs-string">""</span>);
        <span class="hljs-built_in">require</span>(sent, <span class="hljs-string">"Failed to send user balance back to the user"</span>);
    }
</code></pre></li><li><p>Functions that can be called by external contracts</p></li></ul><pre data-type="codeBlock" text="    receive() external payable {
        stake();
    }
"><code>    <span class="hljs-built_in">receive</span>() external payable {
        <span class="hljs-built_in">stake</span>();
    }
</code></pre><p>The final code is as follows:</p><pre data-type="codeBlock" text="// SPDX-License-Identifier: MIT
pragma solidity 0.8.4;

import &quot;hardhat/console.sol&quot;;
import &quot;./ExampleExternalContract.sol&quot;;

contract Staker {
    ExampleExternalContract public exampleExternalContract;

    mapping(address =&gt; uint256) public balances;

    uint256 public constant threshold = 1 ether;

    event Stake(address indexed staker, uint256 amount);

    uint256 public deadline = block.timestamp + 60 seconds;

    constructor(address exampleExternalContractAddress) public {
        exampleExternalContract = ExampleExternalContract(
            exampleExternalContractAddress
        );
    }

    modifier stakeNotCompleted() {
        bool completed = exampleExternalContract.completed();
        require(!completed, &quot;staking process is already completed&quot;);
        _;
    }

    modifier deadlineReached(bool requireReached) {
        uint256 timeRemaining = timeLeft();
        if (requireReached) {
            require(timeRemaining == 0, &quot;deadline is not reached yet&quot;);
        } else {
            require(timeRemaining &gt; 0, &quot;deadline has already reached&quot;);
        }
        _;
    }

    function timeLeft() public view returns (uint256 timeleft) {
        if (block.timestamp &gt;= deadline) {
            return 0;
        } else {
            return deadline - block.timestamp;
        }
    }

    function stake() public payable deadlineReached(false) stakeNotCompleted {
        balances[msg.sender] += msg.value;
        emit Stake(msg.sender, msg.value);
    }

    function execute() public stakeNotCompleted deadlineReached(false) {
        uint256 contractBalance = address(this).balance;

        require(contractBalance &gt;= threshold, &quot;Threshold not reached&quot;);

        (bool sent, ) = address(exampleExternalContract).call{
            value: contractBalance
        }(abi.encodeWithSignature(&quot;complete()&quot;));
        require(sent, &quot;exampleExternalContract.complete() failed&quot;);
    }

    function withdraw() public deadlineReached(true) stakeNotCompleted {
        uint256 userBalance = balances[msg.sender];

        require(userBalance &gt; 0, &quot;You don&apos;t have balance to withdraw&quot;);

        balances[msg.sender] = 0;

        (bool sent, ) = msg.sender.call{value: userBalance}(&quot;&quot;);
        require(sent, &quot;Failed to send user balance back to the user&quot;);
    }

    receive() external payable {
        stake();
    }
}
"><code><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> 0.8.4;</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">"hardhat/console.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./ExampleExternalContract.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Staker</span> </span>{
    ExampleExternalContract <span class="hljs-keyword">public</span> exampleExternalContract;

    <span class="hljs-keyword">mapping</span>(<span class="hljs-keyword">address</span> <span class="hljs-operator">=</span><span class="hljs-operator">></span> <span class="hljs-keyword">uint256</span>) <span class="hljs-keyword">public</span> balances;

    <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">constant</span> threshold <span class="hljs-operator">=</span> <span class="hljs-number">1</span> <span class="hljs-literal">ether</span>;

    <span class="hljs-function"><span class="hljs-keyword">event</span> <span class="hljs-title">Stake</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> <span class="hljs-keyword">indexed</span> staker, <span class="hljs-keyword">uint256</span> amount</span>)</span>;

    <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">public</span> deadline <span class="hljs-operator">=</span> <span class="hljs-built_in">block</span>.<span class="hljs-built_in">timestamp</span> <span class="hljs-operator">+</span> <span class="hljs-number">60</span> <span class="hljs-literal">seconds</span>;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> exampleExternalContractAddress</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        exampleExternalContract <span class="hljs-operator">=</span> ExampleExternalContract(
            exampleExternalContractAddress
        );
    }

    <span class="hljs-function"><span class="hljs-keyword">modifier</span> <span class="hljs-title">stakeNotCompleted</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">bool</span> completed <span class="hljs-operator">=</span> exampleExternalContract.completed();
        <span class="hljs-built_in">require</span>(<span class="hljs-operator">!</span>completed, <span class="hljs-string">"staking process is already completed"</span>);
        <span class="hljs-keyword">_</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">modifier</span> <span class="hljs-title">deadlineReached</span>(<span class="hljs-params"><span class="hljs-keyword">bool</span> requireReached</span>) </span>{
        <span class="hljs-keyword">uint256</span> timeRemaining <span class="hljs-operator">=</span> timeLeft();
        <span class="hljs-keyword">if</span> (requireReached) {
            <span class="hljs-built_in">require</span>(timeRemaining <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">0</span>, <span class="hljs-string">"deadline is not reached yet"</span>);
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-built_in">require</span>(timeRemaining <span class="hljs-operator">></span> <span class="hljs-number">0</span>, <span class="hljs-string">"deadline has already reached"</span>);
        }
        <span class="hljs-keyword">_</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">timeLeft</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span> timeleft</span>) </span>{
        <span class="hljs-keyword">if</span> (<span class="hljs-built_in">block</span>.<span class="hljs-built_in">timestamp</span> <span class="hljs-operator">></span><span class="hljs-operator">=</span> deadline) {
            <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">return</span> deadline <span class="hljs-operator">-</span> <span class="hljs-built_in">block</span>.<span class="hljs-built_in">timestamp</span>;
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">stake</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> <span class="hljs-title">deadlineReached</span>(<span class="hljs-params"><span class="hljs-literal">false</span></span>) <span class="hljs-title">stakeNotCompleted</span> </span>{
        balances[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">+</span><span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span>;
        <span class="hljs-keyword">emit</span> Stake(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">execute</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title">stakeNotCompleted</span> <span class="hljs-title">deadlineReached</span>(<span class="hljs-params"><span class="hljs-literal">false</span></span>) </span>{
        <span class="hljs-keyword">uint256</span> contractBalance <span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>).<span class="hljs-built_in">balance</span>;

        <span class="hljs-built_in">require</span>(contractBalance <span class="hljs-operator">></span><span class="hljs-operator">=</span> threshold, <span class="hljs-string">"Threshold not reached"</span>);

        (<span class="hljs-keyword">bool</span> sent, ) <span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(exampleExternalContract).<span class="hljs-built_in">call</span>{
            <span class="hljs-built_in">value</span>: contractBalance
        }(<span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encodeWithSignature</span>(<span class="hljs-string">"complete()"</span>));
        <span class="hljs-built_in">require</span>(sent, <span class="hljs-string">"exampleExternalContract.complete() failed"</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">withdraw</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title">deadlineReached</span>(<span class="hljs-params"><span class="hljs-literal">true</span></span>) <span class="hljs-title">stakeNotCompleted</span> </span>{
        <span class="hljs-keyword">uint256</span> userBalance <span class="hljs-operator">=</span> balances[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>];

        <span class="hljs-built_in">require</span>(userBalance <span class="hljs-operator">></span> <span class="hljs-number">0</span>, <span class="hljs-string">"You don't have balance to withdraw"</span>);

        balances[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">=</span> <span class="hljs-number">0</span>;

        (<span class="hljs-keyword">bool</span> sent, ) <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>.<span class="hljs-built_in">call</span>{<span class="hljs-built_in">value</span>: userBalance}(<span class="hljs-string">""</span>);
        <span class="hljs-built_in">require</span>(sent, <span class="hljs-string">"Failed to send user balance back to the user"</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">receive</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
        stake();
    }
}
</code></pre><ul><li><p>Deployment</p></li></ul><pre data-type="codeBlock" text="yarn deploy --reset
"><code>yarn deploy <span class="hljs-operator">-</span><span class="hljs-operator">-</span>reset
</code></pre><ul><li><p>Testing</p></li></ul><h1 id="h-0x05-related-information" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x05 Related Information</h1><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/scaffold-eth/scaffold-eth">scaffold-eth</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/WeLightProject/Web3-dApp-Camp">Web3-dApp-Camp</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://guoyu.mirror.xyz/RD-xkpoxasAU7x5MIJmiCX4gll3Cs0pAd5iM258S1Ek">https://guoyu.mirror.xyz/RD-xkpoxasAU7x5MIJmiCX4gll3Cs0pAd5iM258S1Ek</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://learnblockchain.cn">learnblockchain community</a></p></li></ul>]]></content:encoded>
            <author>apecoder@newsletter.paragraph.com (Web3dAppDevCamp)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/9cb5da88fe2456a589702ed1286542b7de436f147792069c1b1bcd03a106a1a6.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[Individual and DAO's Win-Win Strategies for Growth | Talk about DAO 0x01]]></title>
            <link>https://paragraph.com/@apecoder/individual-and-dao-s-win-win-strategies-for-growth-talk-about-dao-0x01</link>
            <guid>9W5iERLB1WBAp9OiimNM</guid>
            <pubDate>Sun, 26 Jun 2022 10:40:51 GMT</pubDate>
            <description><![CDATA[国内用户请加微信：19726581 Authors: leeduckgo,msfewThe Talk about DAO section is a collection of NonceGeek&apos;s thoughts on the practice of DAO. A Brief Analysis of the Relationship between Individuals and Organizations In any kind of organization, the relationship between individual and organization is a very important topic that deserves deep consideration. First of all, let&apos;s analyze the state of the organization. Applying the concept of game theory, the game relationship between organizatio...]]></description>
            <content:encoded><![CDATA[<blockquote><p>国内用户请加微信：19726581</p><p>Authors: <code>leeduckgo</code>,<code>msfew</code></p></blockquote><p>The Talk about DAO section is a collection of NonceGeek&apos;s thoughts on the practice of DAO.</p><p>A Brief Analysis of the Relationship between Individuals and Organizations</p><p>In any kind of organization, the relationship between individual and organization is a very important topic that deserves deep consideration.</p><p>First of all, let&apos;s analyze the state of the organization.</p><p>Applying the concept of game theory, the game relationship between organization and individual can be divided into three kinds as follows.</p><ul><li><p>Zero-sum game: the organization creates very little new value, and the organization is only a &quot;middleman&quot; for the realization of individual labor value. At the same time, in order to maintain the organization itself, it also needs to take part of the value of individual labor as &quot;commission&quot;.</p></li><li><p>Negative sum game: The organization is going downhill. This is a very difficult time for both the organization and the individual. Many times the organization will even suppress the individuals, typically by withholding wages from employees.</p></li><li><p>Positive game: The overall development is active.</p></li></ul><p>It seems that, as individuals, we can choose the organization that is in a &quot;positive-sum state&quot; and be done with it.</p><p>But when you think about it, it doesn&apos;t seem so simple.</p><p>Let&apos;s consider two dimensions - the &apos;revenue dimension&apos; and the &apos;growth dimension&apos; - and we can get two tables.</p><pre data-type="codeBlock" text="+--------------------------------------------------+
|               Earnings Table                     |
+--------------------------------------------------+
|            |   Satisfaction  | Dissatisfaction   |
+--------------------------------------------------+
| Individual |                 |                   |
+--------------------------------------------------+
| Org        |                 |                   |
+--------------------------------------------------+

+--------------------------------------------------+
|                 Growth Table                     |
+--------------------------------------------------+
|            |   Satisfaction  | Dissatisfaction   |
+--------------------------------------------------+
| Individual |                 |                   |
+--------------------------------------------------+
| Org        |                 |                   |
+--------------------------------------------------+
"><code><span class="hljs-operator">+</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">+</span>
<span class="hljs-operator">|</span>               Earnings Table                     <span class="hljs-operator">|</span>
<span class="hljs-operator">+</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">+</span>
<span class="hljs-operator">|</span>            <span class="hljs-operator">|</span>   Satisfaction  <span class="hljs-operator">|</span> Dissatisfaction   <span class="hljs-operator">|</span>
<span class="hljs-operator">+</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">+</span>
<span class="hljs-operator">|</span> Individual <span class="hljs-operator">|</span>                 <span class="hljs-operator">|</span>                   <span class="hljs-operator">|</span>
<span class="hljs-operator">+</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">+</span>
<span class="hljs-operator">|</span> Org        <span class="hljs-operator">|</span>                 <span class="hljs-operator">|</span>                   <span class="hljs-operator">|</span>
<span class="hljs-operator">+</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">+</span>

<span class="hljs-operator">+</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">+</span>
<span class="hljs-operator">|</span>                 Growth Table                     <span class="hljs-operator">|</span>
<span class="hljs-operator">+</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">+</span>
<span class="hljs-operator">|</span>            <span class="hljs-operator">|</span>   Satisfaction  <span class="hljs-operator">|</span> Dissatisfaction   <span class="hljs-operator">|</span>
<span class="hljs-operator">+</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">+</span>
<span class="hljs-operator">|</span> Individual <span class="hljs-operator">|</span>                 <span class="hljs-operator">|</span>                   <span class="hljs-operator">|</span>
<span class="hljs-operator">+</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">+</span>
<span class="hljs-operator">|</span> Org        <span class="hljs-operator">|</span>                 <span class="hljs-operator">|</span>                   <span class="hljs-operator">|</span>
<span class="hljs-operator">+</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">+</span>
</code></pre><p>Many companies in a &quot;positive state&quot; are able to achieve win-win on the revenue table, and both individuals and organizations are satisfied with their revenue.</p><p>However, the most difficult part of the entire narrative is the win-win of the growth table, which is often the most neglected.</p><p>Short-term consistency and long-term uncertainty between individual and organizational growth in organizations</p><p>In many cases, personal growth and organizational growth may be consistent in the short term, but they are uncertain in the long term. For example, a fresh graduate will join a suitable organization for high growth; at the same time, the fresh graduate will inject &quot;fresh blood&quot; into the organization.</p><p>However, in the long run, there may be differences in the direction and speed of growth between individuals and organizations.</p><p>Traditional organizations have cumbersome mechanisms for joining and exiting, so when such differences arise, they either have to live with it or go their separate ways.</p><p>However, the DAO format gives a solution to this paradox -- ideally, anyone in the organization has the right to afk (away from keyboard: temporarily leave) and btk (back to keyboard: come back) at any time.</p><p>In this case, even if the development of the individual is not in line with the development of the organization, then it only needs to afk, no need to report to anyone; when you want to develop with the organization, just btk back to participate in organizational activities.</p><p><strong>In other words, the decision to join, work and quit in a traditional organization is in the hands of the organization, but a real DAO will return this right to the individual. Through this &quot;power transfer&quot;, can we truly create a win-win strategy for individuals and organizations?</strong></p><hr><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">msfew</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">leeduckgo</figcaption></figure>]]></content:encoded>
            <author>apecoder@newsletter.paragraph.com (Web3dAppDevCamp)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/9cb5da88fe2456a589702ed1286542b7de436f147792069c1b1bcd03a106a1a6.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[去中心化社会：寻找 Web3 的灵魂]]></title>
            <link>https://paragraph.com/@apecoder/web3</link>
            <guid>gZSPtkakNqdMRkA7rCsP</guid>
            <pubDate>Thu, 12 May 2022 05:23:52 GMT</pubDate>
            <description><![CDATA[原文链接：https://papers.ssrn.com/sol3/papers.cfm?abstract_id=4105763 论文作者：E. Glen Weyl, Puja Ohlhaver, Vitalik Buterin 翻译人：Leeduckgo@NonceGeek, Yaya@NonceGeek 可加我微信：1976265812022 年, 5 月 道（DAO）者万物之奥。善人之宝，不善人之所保。 ——老子, 62 章摘要如今的 Web3 以表达可转移的、金融化的资产为中心，而不是编码的社会信任关系。然而，许多核心的经济活动——如无抵押贷款和个人品牌的简历——都是建立在持久的、不可转移的关系之上的。在本文中，我们阐述了不可转移的灵魂绑定通证（SBTs），其代表“灵魂”的承诺、凭证和“灵魂”的附属物——它可以对实体经济的信任网络进行编码，以构建来源证明和声誉。更重要的是，SBTs 使其他具备远大愿景的应用成为可能，如社区钱包恢复、抗女巫攻击治理、权力下放机制和具有权利分解、权利共享的新市场。我们把这种更丰富、多元的生态系统称为“分散的社会”(DeSoc)——一种共同决定...]]></description>
            <content:encoded><![CDATA[<blockquote><p>原文链接：<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://papers.ssrn.com/sol3/papers.cfm?abstract_id=4105763">https://papers.ssrn.com/sol3/papers.cfm?abstract_id=4105763</a></p><p>论文作者：E. Glen Weyl, Puja Ohlhaver, Vitalik Buterin</p><p>翻译人：Leeduckgo@NonceGeek, Yaya@NonceGeek</p><p>可加我微信：197626581</p></blockquote><p>2022 年, 5 月</p><p>道（DAO）者万物之奥。善人之宝，不善人之所保。</p><p>——老子, 62 章</p><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">摘要</h2><p>如今的 Web3 以表达可转移的、金融化的资产为中心，而不是编码的社会信任关系。然而，许多核心的经济活动——如无抵押贷款和个人品牌的简历——都是建立在持久的、不可转移的关系之上的。在本文中，我们阐述了不可转移的灵魂绑定通证（SBTs），其代表“灵魂”的承诺、凭证和“灵魂”的附属物——它可以对实体经济的信任网络进行编码，以构建来源证明和声誉。更重要的是，SBTs 使其他具备远大愿景的应用成为可能，如社区钱包恢复、抗女巫攻击治理、权力下放机制和具有权利分解、权利共享的新市场。我们把这种更丰富、多元的生态系统称为“分散的社会”(DeSoc)——一种共同决定的社会性，灵魂和社区自下而上聚集在一起，作为彼此的新兴属性，在一定范围内共同创造多种网络商品和智能。</p><p>这种社会性的关键是可分解的产权和增强的治理机制——例如根据相关分数打折的二次方融资机制——奖励信任和合作，同时保护网络不被捕获、提取和支配。 借助这种增强的社交性，web3 可以避开当今的超金融化，转而支持更具变革性、多元化的未来，即跨社会距离的增加回报。</p><h2 id="h-1" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">1 介绍</h2><p>Web3 在不到十年的时间里打造了一个前所未有的灵活性和创造力的金融平行系统，震惊了世界。</p><p>密码学和经济学的原语，如公钥加密、智能合约、基于工作量的证明和基于权益的证明，已经创造了一个用于表现金融交易的，复杂和开放的生态系统。</p><p>然而，经济价值的交易是由人类及其关系产生的。因为 web3 缺乏原语来代表这种社会身份，所以它已经从根本上依赖于它旨在超越的非常集中的 web2 结构，复制了它们的局限性。</p><p>这些依赖关系的例子包括：</p><p>1.大多数 NFT 艺术家都依赖于像 OpenSea 和推特这样的集中式平台来致力于稀缺性和初始<strong>来源</strong>。</p><p>2.试图超越简单的硬币投票的 dao 通常依赖于 web2 基础设施，比如社交媒体的资料，来抵抗女巫攻击。</p><p>3.许多 web3 参与者依赖于由 Coinbase 或 Binance 等集中实体管理的托管钱包。分散的<strong>密钥管理</strong>系统对任何系统都是非用户友好的，是最复杂的系统。</p><p>此外，缺乏原生的 web3 身份使得今天的 DeFi 生态系统无法支持实体经济中无处不在的活动，例如<strong>抵押不足的借贷</strong>或简单的合同，例如<strong>公寓租赁</strong>。 在本文中，我们说明了即使是用灵魂绑定的通证表示社会身份的微小和渐进的步骤也可以克服这些限制，并使生态系统更接近于在原生 web3 环境中以人际关系为基础的再生市场。</p><p>更有希望的是，我们强调了具有丰富社会组合性的原生 web3 社会身份，如何在 web3 中围绕财富集中和金融治理脆弱性的更广泛的长期问题上取得巨大进展 攻击，同时刺激了寒武纪创新的政治、经济和社会应用的大爆炸。我们将这些用例和它们促成的更丰富的多元生态系统称为“分散社会”(DeSoc)。</p><p>更有希望的是，我们强调了具有丰富<strong>社会可组合性</strong>的原生 web3 社会身份如何在 web3 中围绕财富集中和治理易受金融攻击的脆弱性等更广泛的长期问题上取得巨大进展，同时刺激政治 、经济和社会应用的寒武纪式的创新大爆炸。 我们将这些用例和它们所支持的更丰富的多元化生态系统称为 <strong>“去中心化社会”（DeSoc）</strong>。</p><h2 id="h-2" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">2 大纲</h2><p>我们首先解释 DeSoc 的原语，围绕<strong>持有不可转让（最初公开）的灵魂绑定通证</strong>的账户（或钱包）。“灵魂绑定”通证（SBTs）代表承诺、凭证和附属物。这样的通证就像一份延长的简历，由其他钱包发行来证明这些社会关系。</p><p>然后，我们描述了跨社交栈的具有远大志向的应用程序的“阶梯”。这些原语可以赋予权力，包括：</p><p>● 建立来源</p><p>● 通过声誉解锁抵押贷款不足的贷款市场</p><p>● 支持去中心化的密钥管理</p><p>● 挫败和补偿协调的战略行为</p><p>● 衡量去中心化程度</p><p>● 创建了具有可分解的、共享的权利和权限的新市场</p><p>这一描述以 DeSoc 的愿景达到高潮——一种共同决定的社会性，灵魂和社区自下而上聚集在一起，作为彼此的涌现属性，在一系列社会尺度上共同创造多元的网络商品，包括多元的智能。</p><p>最后，我们回答了几个潜在的问题和反对意见，并与 web3 空间中熟悉的其他身份范式进行了比较，考虑到承认我们的愿景只是第一步，尽管如此也是可编程隐私和通信方面的进步。然后，我们考虑技术途径来引导我们想象的愿景。构建这些，我们更哲学地期待 DeSoc 的潜力，将 web3 重定向到一个更深刻、合法和变革性的路径。</p><h2 id="h-3" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">3 灵魂</h2><p>我们的关键原语是<strong>持有公开可见的、不可转让的（但可能是发行者可撤销的）通证</strong>的账户或钱包。我们将账户称为**“灵魂”<strong>，账户持有的标记称为</strong>“灵魂通证”(SBTs)**。尽管我们对隐私有着浓厚的兴趣，但我们最初假设是公开的，因为它在技术上更容易做概念验证，即使受到「愿意公开分享的通证」的这一人群子集的限制。 在本文的后面，我们为更丰富的用例引入了“可编程隐私”的概念。</p><p>想象一下这样一个世界，大多数参与者都有灵魂，它存储了与一系列的与 SBTs 相对应的附属品、成员资格和凭证。例如，一个人可能有一个灵魂，它存储了代表教育证书、就业历史、或他们的作品或艺术作品的 Hash的 SBTs。在它们最简单的形式下，这些 SBTs 可以被“自我认证”，类似于我们如何在简历中分享关于我们自己的信息。但是，当一个灵魂所持有的 SBTs 可以被其他对立的灵魂发行或证明时，这种机制的真正力量就出现了。这些对手灵魂可以是个人、公司或机构。例如，以太坊基金会可以是一个向参加开发者会议的灵魂发行 SBTs 的灵魂。一所大学可能是一个释放SBTs 的灵魂。体育场可能是向道奇队的长期球迷发放 SBTs 的灵魂。</p><p>请注意，灵魂不需要与合法名称相关联，也不需要<strong>任何</strong>协议级别的尝试来确保「每个人一个灵魂」。 灵魂可能是一个持久的化名，具有一系列无法轻易链接的 SBT。</p><p>我们也不假设灵魂在人类之间的不可转移性。 相反，我们试图说明这些属性如何在需要时自然地从设计本身中出现。</p><h2 id="h-4" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">4 通往去中心化社会的阶梯</h2><h3 id="h-41" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">4.1 艺术与灵魂</h3><p>灵魂是艺术家们把声誉押在作品上的一种自然方式。当发行一个可交易的 NFT 时，一个艺术家可以从他们的灵魂中发行 NFT。艺术家的灵魂携带的 SBTs 越多，买家就越容易确定该灵魂属于该艺 术家，因此也可以确保 NFT 的合法性。艺术家可以更进一步，发行一个存储在他们灵魂中的链接 SBT，证明 NFT 的“收藏”成员资格，并保证艺术家希望设置的任何稀缺性限制。因此，灵魂将创造一种可验证的、链上的方式，以确定一个物品的来源和稀缺性来建立声誉。</p><p>应用程序超越了艺术、服务、租赁，以及任何建立在稀缺性、声誉或真实性之上的市场。后者的一个例子是核实所谓的事实记录的真实性，如照片和视频。随着深度造假技术的进步，人类和算法 的直接检查将越来越无法检测出准确性。虽然 <strong>区块链包容性使我们能够追踪特定作品的制作时间</strong>，但 SBT 将使我们能够追踪 <strong>社会出处</strong>，为我们提供了丰富的社会背景来了解发布该作品的灵魂——他们的成员关系 、附属品、证书——以及他们与客体的社交距离。“Deep fakes” 可以很容易地识别出来，因为那些是来自时间和社会环境之外的文物，而可信的文物（如照片）将来自著名摄影师的认证。目前的技术将文化产品（如图片）去背景化，并使它们容易受到缺乏社会背景的未经检查的病毒式攻击，而 SBTs可以将这些对象重新背景化，并赋予灵魂利用社区中已经存在的信任关系，作为保护声誉的有意义的后盾。</p><h3 id="h-42" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">4.2 灵魂借贷</h3><p>直接建立在声誉之上的最大金融价值也许是信用和无抵押贷款。 目前，web3 生态系统无法复制简单形式的无抵押借贷，因为所有资产都是可转让和可销售的——因此只是抵押形式。</p><p>“传统” 金融生态系统支持多种形式的无抵押贷款，但依赖于集中的信用评分来衡量借款人的信用度，这些借款人没有动力分享有关其信用历史的信息。 但是这样的分数有很多 缺陷。 充其量，他们不透明地高估和低估与信用相关的因素，并对那些没有积累足够数据的人持有偏见——主要是少数族裔和穷人。 在最坏的情况下，他们可以启用黑镜中不透明的“社会信用”系统，从而设计社会结果并加强歧视。</p><p>一个 SBTs的生态系统可以开启一种抗审查的、自下而上的替代方案，以替代自上而下的商业和“社会”信贷系统。代表教育证书、工作历史和租赁合同的 SBTs可以作为信用相关历史的持续记录， 允许灵魂拥有有意义的声誉，以避免抵押品要求并获得贷款。贷款和信用额度可以被表示为不可转让但可撤销的 SBTs，所以它们被嵌套在灵魂的其他 SBTs 中——一种不可扣押的声誉抵押品——直到它们被偿还并随后被烧掉，或者更好的是，取而代之的是偿还证明。SBTs 提供了有用的安全属性：不可转让性防止转移或隐藏未偿贷款，而丰富的 SBTs 生态系统确保那些试图逃避还贷的借款人（也许通过创造一个新的灵魂）将缺乏能代表他们的声誉的 SBTs 。</p><p>使用 SBTs 计算公共债务的便利性将成为开源贷款市场。SBTs 和还款风险之间的新相关性将会出现，从而产生更好的预测贷款算法，从而减少集中的、不透明的信用评分基础设施的作用。更好的是，贷款很可能会发生在社会关系中。特别是，社交联系将成为社区贷款实践的基础，类似于穆罕默德·尤努斯和格林银行开创的做法，在那里，社交网络的成员同意支持彼此的债务。因为一个灵魂的 SBTs 归属代表了跨社会群体的成员身份，参与者可以很容易地发现其他的灵魂。他将是一个集团贷款项目的宝贵的共同参与者。商业贷款是一种“先贷后忘”直至还款的模式，而社区贷款可能会采取“先贷后助”的方式——将营运资本与人力资本相结合，从而获得更高的回报率。</p><h3 id="h-43" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">4.3 不要失去你的灵魂</h3><p>关键的 SBTs的不可转移性——比如一次性颁发的教育证书——提出了一个重要的问题：你如何不失去你的灵魂呢？今天的恢复方法，如多签恢复或记忆方法，在心智成本、易于处理和安全性方面做了权衡。「社交恢复」是一种新兴的选择，它依赖于一个人的信任关系。SBTs 允许一个类似的，但更广泛的范式：「社区恢复」。其中灵魂是其社会网络的交叉投票。</p><p>社交恢复是一个很好的安全起点，但在安全性和可用性方面存在一些缺陷。用户策划了一组 “监护人”，并让他们大多数人能够更换钱包里的钥匙。监护人可能是个人、机构或其他钱包的混合体。问题是，用户必须平衡监护人的数量、做好预防措施，即监护人来自离散的社会圈，以避免传统。此外，监护人可能会去世，人际关系恶化，或者人们只是失去联系，需要频繁和耗费注意力的更新。虽然社交恢复避免了单一的失败，但成功的恢复依赖于与大多数监护人的信任关系。</p><p>一个更强大的解决方案是将灵魂恢复与社区中灵魂的成员资格联系起来，利用最广泛的实时关系来确保安全。</p><p>回想一下，SBTs 代表了不同 社区的成员身份。其中一些社区——如雇主、俱乐部、大学或教堂——在本质上可能在链下更自然，而其他社区——如参与协议治理或 DAO——可能更应该在链上。在一个社区恢复模型中，恢复一个灵魂的私钥将需要一个来自灵魂社区的一个合格的大多数（随机子集）的成员才能同意。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">image-20220512140357864</figcaption></figure><p>就像社会恢复一样，我们假设灵魂可以访问安全的、链下通信通道，在这些通道中“认证”——通过对话、面对面的会面，或确定一个共享的秘密——这些都可以发生。这种通信信道将需要更大的带宽（技术上能够携带更丰富的“信息熵”），例如，链上机器人或 SBTs本身的计算。事实上，我们可以认为 SBTs从根本上来说，都是关于代表参与或访问这种真实的——即高带宽的通信通道。</p><p>要完成这项工作的精确细节还需要进行实验。例如，如何选择监护人以及需要多少监护人的同意，是进一步研究的关键安全参数。然而，有了如此丰富的信息基础，社区恢复在计算上应该是可能的，随着灵魂加入更多不同的社区并形成更有意义的关系，安全性也会增加。</p><p>社区恢复作为一种安全机制，涉及到了身份认同理论——这是被20 世纪之交的社会学家 Georg Simmel（社交王伦理论的提出人）在这个理论中，个性从社会群体的交集中出现，就像社会群体作为个体的交集出现一样。维护和恢复灵魂的加密财产需要灵魂网络的同意。通过在社交性中嵌入安全，一个灵魂总是可以通过社区恢复来再生他们的钥匙，这阻止了灵魂盗窃（或出售）：因为卖方需要证明出售恢复关系，任何试图出售一个灵魂的尝试都缺乏可信度。</p><h3 id="h-44" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">4.4 灵魂投放</h3><p>到目前为止，我们已经解释了灵魂如何能够代表个人，并在他们获得反映他们的关系、成员资格和证书的 SBTs 时反映他们的独特特征和团结性。 这种个性化有助于 Souls 建立声誉、确定出处、进入无抵押贷款市场并保护声誉和身份。 但反过来也是如此—— <strong>SBTs 还使社区能够在独特的灵魂交汇处召集</strong>。 到目前为止，web3 主要依靠通证销售或空投来召唤新社区，这几乎没有准确性或精确度。 通证通过算法免费提供给一组钱包的空投，主要属于现有通证持有者和钱包的某种组合——很容易被女巫攻击，鼓励策略行为和马太效应。 SBTs 提供了一种彻底的改进，我们称之为“灵魂投放”。</p><p>“灵魂投放”是基于灵魂内 SBTs 和其他通证计算的空投。 例如，想要在特定的一层网络协议中召集社区的 DAO，可以向持有最近 5 次会议出席 SBTs 中的 3 次的开发人员或其他反映出席情况的通证（如 POAP）的开发人员提供帮助。 协议还可以针对 SBTs 的组合以程序的方式进行加权通证空投。我们可以想象一个非营利组织，其任务是植树造林，将治理通证交给持有环境行动 SBTs、园艺 SBTs 和碳封存通证的灵魂——可能会向碳封存通证持有者投放更多通证。</p><p>灵魂投放还可以引入新的激励措施来鼓励社区参与。</p><p>丢弃的 SBT 可以设计为在一段时间内受到灵魂约束，但最终随着时间的推移“归属”为可转让的通证。 或者反过来也可行。 持有一段时间的可转让通证可以解锁 SBT 的权利，从而赋予协议进一步的治理权。 SBT 开辟了丰富的可能性空间来试验最大化社区参与和其他目标的机制，如权力下放，我们将在下面进一步讨论。</p><h3 id="h-45" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">4.5 灵魂的黎明</h3><p>分布式自治组织 (DAO) 是围绕一个共同目的聚集在一起的虚拟社区，通过公共区块链上的智能合约投票进行协调。 虽然 DAO 为跨距离和不同的全球社区的协调提供了巨大的潜力，但它们很容易受到女巫攻击，其中单个用户可以拥有多个钱包来累积投票权——或者在不太复杂的单通证一票式治理中，简单地囤积通证累积 51% 的投票权并剥夺其他 49% 的投票权。</p><p>DAOs 可以通过以下几种方式减轻女巫攻击，例如：</p><p>● 计算灵魂的 SBT 归属以区分<strong>独特灵魂</strong>和<strong>可能的机器人</strong>，并拒绝<strong>任何</strong>投票权给看似女巫的灵魂。</p><p>● 授予拥有更高声望的 SBT（如工作或教育证书、执照或证书）的灵魂更多的投票权。</p><p>● 发布专门的“人格证明” SBTs，这可以帮助其他 DAO 抵抗女巫攻击。</p><p>● 检查支持特定投票的灵魂持有的 SBT 之间的相关性，并对高度相关的选民应用较低的投票权重。</p><p>后一种相关性检查的想法特别有前途和新颖。 由分享相同 SBTs 的许多灵魂支持的投票更有可能是女巫攻击，而且——即使<strong>不是</strong>女巫攻击——这样的投票更有可能是一群具有相同的判断错误或具有相同偏见的人，因此应该合理地加权低于具有相同数量支持但来自更多样化的参与者基础的投票。</p><p>我们在二次融资的背景下更详细地探讨了后一种想法。在附录中，我们引入了一个新的原语，称为“相关性分数”。“这种相关性折扣的概念可以扩展到构建审慎的对话。例如，容易受到多数主义捕获的 DAOs 可以计算 SBTs，使最大限度地多样化的成员聚集在一起，并确保少数群体的声音被听到。</p><p>DAO 还可以依靠 SBT 来阻止各种形式的战略行为，例如“吸血鬼攻击”。 在此类攻击中，DAO（通常具有相关的具有经济价值的 DeFi 协议）通过复制他们的开源代码并随后用通证吸引用户的流动性来搭便车。 DAO 可以通过以下方式阻止搭便车者：DAO 可以阻止搭便车者，首先围绕灵魂投掷（可能授予 SBT）创建一个规范，仅针对提供流动性的可能的抗女巫灵魂，然后将灵魂投递给在吸血鬼攻击中转移流动性的灵魂。 同样的机制不适用于空投到钱包，因为持有人可以将流动性分散到许多钱包中以混淆他们的流动性轨迹。</p><p>DAO 还可以使用 SBTs 以编程方式响应其社区的领导和治理。 领导角色可以随着社区组成的变化而动态变化——正如 SBT 在成员灵魂中的分布变化中所反映的那样。 根据 DAO 内多个社区的交叉性和覆盖范围，可以将一部分成员提升为潜在的主管角色。 重视社区凝聚力的协议可以使用 SBT 将交叉灵魂保持在中心。 或者，DAO 可能会选择比其他更提升某些特征组合的治理，例如邮政编码之间的多样性或特殊爱好 DAO 子集的参与。</p><h3 id="h-46-yuan" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">4.6 通过多元主义确保去中心化</h3><p>在分析现实世界的生态系统时，最好是衡量生态系统实际上有多去中心化。生态系统在多大程</p><p>度上是真正去中心化的，去中心化在多大程度上是“假的”，而生态系统实际上是由一个或一小部分协调实</p><p>体所主导的？</p><p>两个流行的去中心化指标被称为「Nakamoto 相关性」，由 Balaji Srinivasan 提出，他测量了合并多少不同的实体来收集 51%的一些资源，以及 Herfindahl-Hirschman 用于反垄断目的衡量市场集中度的指数，通过将市场参与者的市场份额的平方相来计算。。然而，这些方法留下了一些关键的问题，即什么是需要衡量的正确资源，如何处理部分协调，以及什么是构成“独特实体”的灰色地带。</p><p>例如，名义上独立的退休股东可能有许多共同的大股东，有彼此是朋友的董事，或受到同一个政府的监管。在通证协议的背景下，通过查看链上的钱包来衡量通证持有的分散化是非常不准确的，因为许多人有多个钱包，而一些钱包（如交易所钱包）代表了很多人。此外，即使地址可以追溯到独特的个体，这些个体也可能是与社会相关的群体，容易发生偶然的协调（在最好的情况下）或有意的勾结（在最坏的情况下）。衡量权力下放的更好方法是捕捉社会依赖、弱关联和强团结。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">image-20220512182735445</figcaption></figure><p>矿工和矿业池运营商总共占比特币哈希功率的 90%，他们一起坐在一个会议小组上。</p><p>SBTs 支持一种不同的方式来衡量 DAO、协议或网络中的去中心化（或多元化）水平。</p><ul><li><p>作为第一步，协议可以限制通证投票到合理的女巫攻击抵抗（或复 SBT）的灵魂；</p></li><li><p>作为第二步，协议可以检查不同灵魂持有的 SBTs 与灵魂的折扣投票之间的相关性（将它们合并为仅部分分离），如果它们共享大量 SBTs（我们在附录 A 的二次融资背景下更详细地探讨了后一个想法，我们在其中引入了一个新的原语，称为「相关分数」）；</p></li><li><p>作为第三步，为了缩小并了解整个网络的去中心化程度，可以测量 Souls 持有的 SBT 在网络堆栈的不同层之间和跨层之间的相关性——测量投票、通证所有权、治理相关的相关性通信，甚至控制计算资源。</p></li></ul><p>SBT 使我们能够开始衡量当今很难衡量的互操作和分层生态系统的去中心化程度。 关于哪些公式最能捕捉我们想要测量的内容并且最不容易受到操纵，仍然存在一个很大的悬而未决的问题。 还有很多关于如何检查 SBT 的关系的问题——对某些 SBT 的权重比其他的更高，对嵌套的 SBT 进行折扣，或者还考虑到 Souls 中可转让通证的组成。 然而，随着 Souls 和 SBT 的丰富生态系统，大量数据可用于进行这些计算并朝着有意义的去中心化方向发展。</p><h3 id="h-47-yuan" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">4.7 多元属性</h3><p>DAO 通常在虚拟世界和物理世界中拥有或围绕拥有资产进行组织。到目前为止，web3 的范围主要限于一小部分财产，其权利捆绑完全可以转让：通证、NFT、艺术品、第一版或像美国宪法这样的稀有手稿。但是，对可转让性的强调对 Web3不利，使其无法代表和支持当今一些最简单且无处不在的财产合同，例如公寓租赁。财产权在罗马法律传统中被定义为使用（“usus”）、消费或破坏（“abusus”）和获取利润（“fructus”）的权利。很少有所有这些权利共同归属于同一所有者。例如，公寓租赁授予出租人有限的使用权（“usus”），但不能无限制地破坏公寓（“abusus”）、将其出售（“fructus”），甚至转让使用（转租） 。不动产（土地）的权利通常受到一系列私人使用限制、公共使用权授予、销售权限制，甚至征用权购买权的限制。他们通常还背负着将一些金融价值转移给贷方的抵押贷款。</p><p>财产创新的未来不太可能建立在迄今为止想象的 web3 完全可转让的私有财产之上。 相反，创新将取决于分解财产权以匹配现有财产制度特征的能力，并编写更丰富的细节。 公司和其他组织形式的演变正是为了以更具创造性的方式重新配置产权——例如，授予员工使用专有设施（“usus”）的权限，但保留经理更改或损坏资产的权利（“abusus”），同时支付股东最大的财务利润（“fructus”）。 SBT 具有表现和扩散实体和虚拟资产的此类细微产权的灵活性，同时鼓励新的实验。 这里是一些用例：</p><ul><li><p>允许访问私人或公共控制的资源（例如，房屋、汽车、博物馆、公园和虚拟等价物）。 可转让的 NFT 未能很好地捕捉到这个用例，因为访问权限通常是有条件的且不可转让的：如果我相信你会进入我的后院并将其用作娱乐空间，这并不意味着我授予你会将这个权益给予他人的子许可。</p></li><li><p>通过SBTs 向研究人员授予数据访问权限的数据联合体，同时赋予成员授予访问权限的权利（可能通过二次方投票）并就研究产生的发现和知识产权的经济权利进行谈判。 我们将在第 4 节“多元意义构建”中进一步探讨这一点。</p></li><li><p>使用当地货币进行实验，其规则使居住在特定地区或属于特定社区的灵魂更有价值地持有和消费它们。</p></li><li><p>参与实验，其中 SBT 为较少情境化的灵魂（例如移民、青少年）在新颖和更广泛的网络中获得影响力创造了持续的基础。 这样的灵魂将从有限的 SBTs 开始，将他们与家人或当地社区集中在一起。 随着他们的联盟逐渐多样化，他们将获得更广泛的 SBTs，以实例化投票权以影响更广泛的网络——本着 Danielle Allen 的多元政治理念的精神——这一过程目前由年龄和居住地限制来调节。</p></li><li><p>市场设计实验，例如 Harberger 税收和 SALSA（在拍卖中出售的自我评估许可证），其中资产持有人发布自我评估价格，任何其他人都可以从他们那里购买资产，并且必须定期按比例缴纳税款对自评价格保持控制。 SBT 可用于创建更细微的 SALSA 版本——例如，社区批准参与权，以尽量减少来自社区内部或外部的策略行为。</p></li><li><p>二次投票等民主机制设计的实验。 代表社区成员的 SBTs 持有者可以对激励和税率等参数进行二次投票。 归根结底，“市场”和“政治”不是独立的设计空间。 SBTs 可以成为技术堆栈的主要部分，可以探索两个类别之间的整个空间。 通过二次方融资提供公共商品是另一个这样的交叉点。</p></li></ul><p>当然，还有一些反乌托邦场景需要考虑。 移民系统可以通过迁移 SBTs 获得许可。 监管捕获可以编入嵌套的社区通证中，其中房主拥有不成比例的投票权并阻碍住房建设。 SBTs 可以使红线自动化。 正如我们在下面进一步讨论的那样，应该在当前不透明的自上而下的权限和歧视的背景下考虑这些场景。 SBTs 使歧视更加透明，因此可能具有争议性。</p><h3 id="h-48-yuan" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">4.8 从私人商品和公共商品到多元网络商品</h3><p>更一般地说，SBTs 可以让我们有效地代表和管理介于完全私有和完全公共之间的任何资产和商品。 实际上，几乎所有东西都在范围内：即使是个人消费的商品也有积极的溢出效应，例如使消费者能够更好地为他们的家庭或社区做出贡献，甚至全球最容易获得的公共商品（例如气候）也不可避免地更有用 有些人比其他人好（例如塞舌尔对比于西伯利亚）。 同样，人类的动机很少是完全自私或完全利他的。 有许多预先存在的合作模式，某些社区比其他社区更多。</p><p>然而，今天的机制设计假设原子化的、自私的代理人没有预先存在的合作，这往往使机制容易受到无意的过度协调的影响，最坏的情况是故意勾结。因此，即使是最好的公共融资模式，包括二次方融资 (QF)，也无法进行扩展。 QF 通过为少数人的集中行动提供递减的奖励来鼓励协调，但为多数人的集体行动提供增加的奖励；例如，10 人平均贡献的 1 美元与 99 美元相匹配，总共产生 100 美元，而一个人贡献的 10 美元则没有匹配。在数学上，这是通过匹配与个人捐款平方根之和的平方成正比的资金来实现的（我们在附录中进一步详细说明）。但是，即使大型团体（比如大多数 K 国公民）之间的合作很弱（比如向一项事业捐款 1 美元）也会主导系统并吸收所有匹配的资金，因为优质 QF 会增加独特贡献者的数量。像现在这样，QF 不会忽视可能淹没 QF 轮次的相关特殊利益之间的协调，而是奖励它。</p><p>但是，与其将预先存在的合作视为我们应该“改写”的错误，关键是承认它反映了我们应该利用和补偿的部分合作。 毕竟，我们从事的是鼓励合作的业务。 诀窍是让二次机制与预先存在的合作网络一起工作，纠正它们的偏见和过度协调的倾向。 SBTs 提供了一种自然的方式，它允许我们倾斜天平以支持跨越差异的合作。 正如诺贝尔奖获得者 Elinor Ostrom 著名地强调的那样，问题不在于协调公共产品本身，而在于帮助由不完全合作但具有社会联系的个人组成的社区克服他们的社会差异，在更广泛的网络中进行大规模协调。</p><p>如果 SBTs 代表反映灵魂偏向性的社区成员资格，那么支持跨差异合作仅仅意味着将合作奖励折扣给类似关联或相关的灵魂——由他们共享的 SBT 衡量的相似性。 假设是，不同关联的更好的共识信号跨更广泛的网络的多种商品，而相似关联的更可能的共识信号是服务于更窄利益的过度协调（或共谋）商品。</p><p>通过揭示 Souls 中的共享成员资格，SBTs 允许我们打折预先存在的合作，并二次扩大在新兴网络中广泛赋予利益的多元商品——由最多样化的成员同意——而不是更狭窄的商品被特殊利益集团无意的过度协调（或故意勾结）。 相关折扣“最佳”的精确公式取决于模型细节，尚未研究，但我们在附录中提供了第一次实验以供进一步研究。</p><h2 id="h-5-yuan" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">5 多元感官</h2><p>在数字世界中日益突出的多元网络商品的一个例子是利用用户数据建立的预测性模型。艺术智能（AI）和预测市场都试图根据主要来自人的数据来预测未来的事件。事件，主要是基于从人那里获得的数据。但这两种模式都有不同的局限性，而且几乎是相反的。恰恰相反。人工智能的主导模式避开了激励机制，而是囤积（公共或私人监控的）数据资料，并对其进行合成监视的）数据源，并通过专有的大规模非线性模型将其合成为预测结果--利用默认的 web2 对 &quot;usus &quot;的垄断，而不对数据劳动者提供任何 &quot;fructus&quot;。预测市场采取相反的方法，人们对结果进行投注，希望获得经济收益。完全依赖金融投机的经济激励（&quot;果实&quot;），而不去综合投注者的信念赌徒的信念来产生可组合的模型。同时，这两种范式得出的结论都是被描述为 &quot;客观 &quot;真理的结论；而人工智能模型被描述为 &quot;普遍的 &quot;或 &quot;一般的而人工智能模型则被描述为 &quot;普遍 &quot;或 &quot;智能&quot;，预测市场则被描述为将市场参与者的所有信念归纳为一个单一的数字: 均衡价格。</p><p>一个更有成效的范式是避开这些极端，而吸取两者的优点, 同时弥补它们的弱点并丰富它们的广度。我们建议深思熟虑地将非线性人工智能模型的复杂性与预测市场的市场激励机制相结合，将被动的数据劳动者变成主动的数据创造者。有了这种扎根于数据创造者的社会性的丰富信息我们说明了DeSoc如何释放出比任何一种方法都更强大的多元网络（ed）智能。</p><h3 id="h-51-yuan" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">5.1 预测市场到预测的多元性</h3><p>预测市场的目的是根据那些愿意赌钱的人的财富和风险偏好来聚集信念-有钱能使鬼推磨。但是，这种 &quot;生存测试 &quot;并不是一种理想的信仰聚集方式。一个零和游戏，一个交易者的收益就是另一个交易者的损失，它假定了一种普遍的预测能力，与 &quot;聪明人 &quot;而不是 &quot;傻瓜 &quot;搏斗。虽然财富可能是某些形式的能力和专业知识的代表，但考虑到其他形式的相对专业知识的预测可能更可靠。在某一特定领域赌输了的参与者，在另一领域可能有更准确的信念。但是，预测市场有一个不幸的结果，那就是激发那些容易赌博的人的信念，这使那些赢得赌注的人变得富有，使其余的人变得贫穷，并使那些不愿承担风险的人不愿意普遍参与。</p><p>有更好的方法来激发人们的信念。研究表明，虽然预测市场的表现通常优于简单的投票，但它们并不优于复杂的团队预测投票，在这种情况下，人们有激励措施来分享和讨论信息。在团队商议模式下，成员可以根据过去的表现和同行的评价等因素进行加权，团队参与半结构化的讨论，以汇集不能简单地封装在买卖合同中的信息。这样的团队商议模型可以用二次方规则进一步改进，以从所有参与者那里获得准确的概率估计（与预测市场相比，预测市场只获得关于当前价格平衡的上下观点）。已经证明，人们有动力购买的合同数量反映了他们的主观概率。买的合同数量反映了他们的主观概率评估。这样的市场也能更平等地分配参与的收益。奖励准确的人而不使其他人破产，从而使每个人都能在未来的回合中成为参与者。奖励准确率而不使其他人破产，从而使每个人都成为未来几轮的参与者。</p><p>SBTs可以开启一类新的丰富的模型，并在预测能力和相对专业知识方面进行实验。预测市场给出了一个数字--合同的价格，而二次投票给出了每个参与者对某一事件的概率的确切信念。SBTs能够在社会背景下对这些信念进行进一步的计算，包括一个人的教育证书、会员资格和一般的社会性。参与者开发更好的加权（或非线性综合）预测模型，很可能在新的、不可预见的交叉点上浮现出专家预测者。因此，即使民意调查没有很好地汇总信仰，也可以对民意调查进行追溯研究，以发现 &quot;更正确 &quot;的参与者的特征，并在未来的民意调查中召集更有针对性的 &quot;专家&quot;，也许是在一个审议小组的背景下。这些机制与我们在本文中倡导的机制密切相关。同样，由相关分数折算的二次方机制可以将协调不佳的自上而下的公共产品转化为强大的。同样，它们也可以将基于零和预测市场的治理系统转变为正和多元的感知机制，因为零和预测市场激励参与者隐藏他们的信息（例如Futarchy）。决策，从而鼓励新的和更好的信息的揭示和综合。</p><h3 id="h-52-yuan" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">5.2 人工智能到多元智能</h3><p>大规模的非线性 &quot;神经网络 &quot;模型（如BERT和GPT-3）也可以通过SBT进行转换。由SBTs进行改造。这类模型可以收集大量的公共或私人监控的数据，以产生丰富的模型和预测。丰富的模型和预测，如基于自然语言提示的代码。大多数被监控的数据创建者没有意识到他们在创建这些模型中的作用，没有保留任何剩余权利，并被视为 &quot;附带的&quot;，而不是关键的参与者。此外，数据收集使模型脱离了它们的社会背景，这掩盖了它们的偏见和局限性，并使它们被视为 &quot;偶然的 &quot;而不是关键的参与者。这掩盖了它们的偏见和局限性，削弱了我们对它们进行补偿的能力。这些紧张关系已经随着对数据可用性的要求越来越高，这些矛盾也日益凸显出来，&quot;数据集的数据表 &quot;等新举措记录了数据出处。数据集的数据表 &quot;等新举措来记录数据出处，以及机器学习的隐私保护方法，这些矛盾日益凸显。这样的这些方法需要给那些产生数据的人以有意义的经济和管理利益，并激励他们合作产生数据。激励他们合作产生比他们单独建立的更强大的模型。</p><p>SBT提供了一种自然的方式，为富含来源的数据制定经济激励措施，同时赋予数据创建者对其数据的剩余治理权。特别是，SBTs允许对个人和社区的数据（和数据质量）基于他们的特点进行仔细和有针对性的激励。同时，模型制作者可以跟踪所收集的数据的特征和他们的社会背景--这是对他们的影响。同时，模型制作者可以跟踪SBT所反映的所收集的数据及其社会背景，并找到能够消除偏见和补偿局限的贡献者的限制。SBTs也可以为数据创造者提供定制的管理权，允许他们组成合作组织，汇集数据并协商使用。数据创造者的这种自下而上的可编程性使得未来的多元智能成为可能。未来的多元智能，模型制作者可以通过竞争来协商使用相同的数据来建立不同的模型。因此，我们摆脱了一个独立的单一的 &quot;艺术智能 &quot;的模式摆脱了脱离人类起源，囤积无出处的监控数据的模式，而变成了寒武纪时期的爆炸性增长，即合作构建的多元智能体。取而代之的是合作构建的多元智能，这些智能植根于社会渊源，并由灵魂管理。</p><p>随着时间的推移，正如SBT使灵魂个体化一样，它们也会使模型个体化--将数据出处、管理和经济权利直接嵌入模型的代码中。因此，多元智能体像人类--建立一个嵌入人类社会性的灵魂。或者取决于你如何看待它，人类随着时间的推移，嵌入在多元智能体中进化。每个人都有一个独特的灵魂，与其他灵魂互补和合作。在这一点上，我们看到了预测市场和人工智能范式的融合，走向多元的感知，结合广泛分布的激励措施和对社会环境的仔细跟踪，创造出一种多种多样的模式，将两种方法的优点结合起来，形成一个比任何一种方法都更强大的技术范式，比任何一种都更强大。</p><h3 id="h-53-yuan" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">5.3 可编程的多元隐私</h3><p>多元智能体提出了关于数据隐私的重要问题。毕竟，要建立这样强大的需要从大型数据集（如健康数据）中汇集不同个体的数据，或捕获非人际但共享的数据（如社交图）。不是人与人之间的，而是共享的（例如，社交图）。&quot;自我主权身份 &quot;的倡导者倾向于把数据作为私有财产：关于这个互动的数据是我的，所以我应该能够选择何时以及向谁披露这些数据。然而，甚至比起实体经济，数据经济在简单的私有财产方面也很难理解。简单的私有财产方面的理解。在简单的双向关系中，比如说非法航空，披露信息的权利信息通常是对称的，通常需要相互许可和同意。正如学者Helen Nissenbaum强调，人们关注的不是 &quot;隐私 &quot;本身，而是在分享信息时缺乏对背景的完整性。信息的完整性。剑桥分析公司的丑闻在很大程度上是关于人们透露他们的社交图谱和朋友的信息的属性，而不涉及他们自己。剑桥分析公司的丑闻主要是关于人们在未经他们同意的情况下透露他们的社交图谱和朋友的信息。</p><p>与其说隐私是可转让的财产权利，不如说更有希望的方法是将隐私视为将隐私视为一个可编程的、松散耦合的权利捆绑，允许访问、改变或从信息中获利。信息的权利。在这种模式下，每一个SBT--例如代表一个证书或访问一个数据存储的SBT--最好也有一个隐含的可编程的产权，指定对构成SBT的基础信息的访问。构成SBT的基础信息：持有者、他们之间的协议、共享财产（如数据）。财产（如数据），以及对第三方的义务。例如，一些发行者会选择将SBTs完全公开。一些SBTs，如护照或健康记录，将是自我主权意义上的隐私，携带SBT的灵魂有单边披露的权利。其他的，如反映数据合作组织成员资格的SBTs，将有多重签名或更复杂的社区投票权限。在这种情况下，所有或大多数的SBT持有者必须同意披露。</p><p>虽然目前存在一些技术问题（SBTs能否以这种方式编程？围绕激励相容性的重要问题（在第7节中进一步探讨）--但我们仍然认为可编程的多元隐私值得进一步研究，并且与其他模式相比具有关键优势。</p><p>根据我们的方法，SBT有可能使隐私成为一种可编程的、可组合的权利，即可以映射到我们今天拥有的一套复杂的期望和协议上。此外，这种可编程性可以帮助我们重新想象新的众生相。隐私--作为一种允许获取信息的权利--可以与 &quot;usus&quot;、&quot;abusus &quot;和 &quot;fructus &quot;组成，以创造一个细微差别的获取权的组合，这有无限多的方式。例如，SBTs可以允许对数据存储的计算--也许是由多个灵魂拥有和管理的--使用一种特殊的隐私保护的技术。一些SBTs甚至可以允许对数据的访问，在这种情况下，某些计算可以进行，但是可以进行计算，但其结果不能向第三方证明。一个简单的例子是投票。投票机制需要统计每个人的票数，但票数不应证明给其他人，以防止买票。</p><p>通信也许是共享数据的最典型形式。然而，今天的通信渠道既缺乏用户控制和管理（&quot;usus &quot;和 &quot;abusus&quot;），同时又将用户的注意力（&quot;fructus&quot;）拍卖给出价最高的人，即使是机器人。SBTs有潜力管理更健康的注意力经济 &quot;的形式，使灵魂有能力从他们的社交图谱之外的可能的机器人那里获得垃圾信息。他们的社交图谱，同时提升来自真实社区和所需交叉点的沟通。听众可以更清楚地知道他们在听谁的声音，并能更好地将功劳分配给那些能激发洞察力的作品。激发洞察力。与其优化最大限度的参与，这样的经济可以优化为正和合作和有价值的共同创造。这样的沟通渠道对安全也很重要。如上所述，&quot;高带宽 &quot;的沟通渠道对建立社区恢复的安全基础至关重要。</p><h2 id="h-6" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">6 去中心化社会</h2><p>Web3希望能广泛地改造社会，而不仅仅是金融系统。然而，今天的社会结构--家庭、教会、团队、公司、公民社会、名人、民主--在虚拟世界（通常称为 &quot;元空间&quot;）中是毫无意义的。如果没有代表人类灵魂和更广泛的关系的基元，虚拟世界（通常称为 &quot;元宇宙&quot;）就没有意义。如果web3摒弃了持久的身份，他们的信任和合作模式，以及他们的可组合的权利和权限，我们就会看到，分别是辛比尔攻击、串通和一个有限的完全可转让的私有财产的经济领域--所有这些都是超金融化的趋势。</p><p>为了避开超级金融化，但又能释放出指数级的增长，我们建议增强和桥接我们在虚拟和物理现实中的社会性，使灵魂和社区有能力编码丰富的社会和经济关系。但是，仅仅建立在信任和合作上是不够的。纠正纠正信任网络中的偏见和过度协调（或勾结）的倾向，对于鼓励比以前更复杂、更多样化的社会关系至关重要。我们将此称为&quot;去中心化社会（DeSoc）&quot;：一种共同决定的社会性，其中灵魂和社区的召集自下而上，作为彼此的新兴属性，在不同的规模上产生多元的网络商品。</p><p>我们强调多元网络商品是DESOC的一个特点，因为网络是经济增长最强大的引擎，但也最容易被私人行为者（如web2）以及其他一些机构（如美国国家航空航天局）破坏。经济增长的引擎，但却最容易被私人行为者（如web2）和强大的政府以神秘主义的方式捕获。大多数显著的经济增长来自于越来越多的网络回报，每增加一个单位的投入就会产生越来越多的产出。简单的物理网络的例子包括道路、电网、城市和其他形式的基础设施。劳动力和其他资本投入建立的网络。强大的数字网络的例子包括市场。预测模型和以数据为基础的多元智能。在这两种情况下，网络经济学与新古典主义经济学不同，后者讲究收益递减--每增加一个单位的投入，产出就会递减，而私有财产会产生最有效的结果。私有财产，应用于收益递增的情况下，会产生相反的效果--通过榨取租金来抑制网络增长。两个城市之间的公路可以从贸易收益中释放出越来越多的回报。但同样的道路，如果业主选择榨取的租金达到了交易价值，那么私人拥有的道路就会扼杀增长和价值。网络的公共所有权也有其自身的危险性，容易受到监管部门的控制或资金不足的影响。</p><p>如果不把网络当作纯粹的公共产品或纯粹的私人产品，而是当作部分和多元的共享产品，那么，收益递增的网络是最有效的。纯粹的私人物品，而是作为部分和多元的共享物品时，收益递增的网络是最有效的。DeSoc提供了一个社会基底对权利进行拆分和重组--使用权（&quot;usus&quot;）、消费权或破坏权（&quot;abusus&quot;）和的权利（&quot;fructus&quot;），并在这些权利之间建立起有效的治理机制，以增强信任和合作，同时检查串通和捕获。我们在本文中已经探讨了几种机制我们在本文中探讨了几种机制，如基于社区的SALSA和由相关分数折算的四次方资金（和投票）。这种部分和多元所有权的第三种方式避免了私人寻租的卡律布迪斯（Charybdis）和公共监管的希拉（Scylla）。</p><p>在许多方面，今天的DeFi是一个递减回报的私有财产范式，并将其追溯到增加回报的网络。建立在不信任的前提下，DeFi本质上被限制在完全可转让的私有财产（如可转让的通证）领域。完全可转让的私有财产（如可转让的通证），主要是将 &quot;usus&quot;、&quot;abusus &quot;和&quot;fructus&quot;。在最好的情况下，DeFi有可能通过榨取租金来扼制网络的发展，在最坏的情况下，有可能迎来的是由 &quot;鲸鱼 &quot;主导的乌托邦式的监控垄断，这些 &quot;鲸鱼 &quot;会收集并囤积数据。鲸鱼 &quot;主宰的神秘主义监控垄断，他们在收集和囤积数据的过程中进行竞争--就像web2.com一样。</p><p>DeSoc将DeFi对网络价值的控制和猜测的竞赛转变为自下而上的协调来建立、参与和管理它们。至少，DeSoc的社会底层可以使DeFi具有抗虫性（实现社区治理）、抗吸血鬼性（将积极的外部性内部化，以建立一个开源的网络）和抗串通性（维护社区治理）。构建一个开源的网络），以及防串通（保持网络的去中心化）。随着DeSoc的结构性修正，DeFi可以支持和扩大复数网络，赋予其利益而不是进一步巩固被狭隘利益所控制的网络。</p><p>然而，DeSoc的最大优势在于其网络的可组合性。持续增长的回报和网络的增长并不只是为了避免榨取租金的危险，也是为了鼓励嵌套网络的扩散和交叉。一条公路可能在两个城市之间形成一个网络。但是，从更广泛的合作中切削减了更广泛的合作，两个合作的城市最终会遇到收益递减的上限，因为拥挤（道路和住房）或枯竭（达到他们所能服务的人群的极限）。只有通过技术创新和越来越广泛的合作，即使是比较松散的邻近网络的合作，以获得不断增长的回报的新来源，价值才能继续成倍增长。一些合作将是有形的，逐步扩大跨空间的物理贸易。但更多的的连接将是信息和数字的。随着时间的推移，我们将看到物理和数字网络之间新的合作矩阵。依赖于并扩展它们所建立的社会互连。这种交叉的、部分嵌套的、跨越数字和物理世界的不断增长的网络合作，正是DeSoc所促成的。</p><p>通过组成网络和协调，DeSoc出现在政治和市场的交汇点上。市场的交汇点--用社会性增强两者。DeSoc增强了JCR Licklider的愿景--他是创建互联网的ARPANET的创始人。他是ARPANET的创始人，该网络创造了互联网--&quot;人机共生 &quot;的 &quot;星系间计算机网络&quot;。在一个 &quot;星系间计算机网络 &quot;中的 &quot;人机共生&quot;，在信任的基础上极大地增加了社会活力。与其说DeFi是建立在无信任的前提下，DeSoc对支撑当今实体经济的信任网络进行编码，并使我们能够利用它们能够产生对捕获、提取或支配有弹性的多元网络商品。有了这种有了这种增强的社会性，web3可以放弃短期的超级金融化，而选择一个无限制的、跨越社会距离的回报的未来。</p><h3 id="h-61" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">6.1 灵魂可以上天堂......也可以下地狱</h3><p>虽然我们有选择地强调了我们认为有希望的DaSoc所释放的潜力，但重要的是要记住，几乎任何具有这种变革潜力的技术都会有类似的特点。重要的是要记住，几乎任何具有这种变革潜力的技术都会有类似的破坏性变革潜力。破坏性改造的潜力：火力燃烧，车轮碾压，电视洗脑，汽车污染，信用卡困住债务，诸如此类。在这里，同样的SBTs可以被用来弥补在这里，同样的SBTs可以用来补偿群体内的动力并实现跨地域的合作，也可以用来自动对不受欢迎的社会群体进行红线划分，甚至可以用来对不受欢迎的社会群体进行红线划分。不受欢迎的社会群体，甚至将他们作为网络或物理攻击的目标，执行限制性的移民政策，或提供掠夺性贷款。在当前的web3生态系统中，许多这样的可能性并不突出，因为在目前的基础上，它们并不是有意义的概念。启用DeSoc的优势也会造成这些伤害。正如拥有心脏的坏处是心脏可能会被打碎一样，拥有灵魂的坏处是它可能会下地狱，而拥有社会的坏处是社会经常被仇恨、偏见、暴力和恐惧所驱动。人性是一个伟大的、常常是悲剧性的实验。</p><p>当我们思考DeSoc可能的乌托邦时，我们也应该把这些可能性放在其他技术性乌托邦的背景下。在其他技术促成的乌托邦中。Web2是不透明的专制监视和社会控制的架构。虽然web2经常依靠自上而下的艺术官僚机构来授予身份（&quot;驾照&quot;），但它是一个不透明的结构。而DeSoc依靠的是横向（&quot;点对点&quot;）的社会证明。而DeSoc赋予了灵魂对他们自己的关系进行编码并共同创造多元财产，而web2则以社会联系为中介或用不透明的算法将其货币化，这些算法可能会使人分化、分裂和误导。DeSoc避开了自上而下、不透明的社会信用体系。Web2构成了它们的基础。DeSoc将灵魂视为代理人，而web2将灵魂视为对象</p><p>在没有任何身份基础的情况下，DeFi的社会控制风险较小，至少在短期内是如此。但DeFi有它自己的乌托邦。虽然DeFi克服了明确的集中化形式--即特定的行为者在一个系统中拥有超水平的正式权力--但它没有内置的方法来克服通过串通和市场力量的隐性集权。垄断并不总是像过去的 &quot;标准油 &quot;那样出现。勾结甚至可以发生在生态系统的更高和更远的地方，在一个生态系统的更高层次上。我们今天看到了这一点，一类机构资产管理公司的崛起（例如，anguard、BlackRock、State Street、Fidelity等）的崛起，他们是所有大型银行的最大股东。航空公司、汽车公司和其他主要行业的最大股东。由于这类资产管理公司持有一个行业内所有对手的股份（比如持有每家主要航空公司的股份），他们的动机是使他们所持有的公司看起来像一个竞争性的行业，但行动起来却像一个垄断者，使整个行业的利润最大化并以消费者和公众的利益为代价来巩固自己的地位。</p><p>在DeFi中，同样的 &quot;鲸鱼 &quot;和风险投资人在堆栈的每一层都积累了更大的股份，并且在堆栈内的竞争者之间也是如此。在一个堆栈内的竞争者之间积累了更大的份额，也许在通证管理中投票，或将其委托给同一级别的委托人，他们在整个网络中也有类似的相关性。如果没有任何社会基质来抵制强行功能分散化和相关折扣，我们也应该期待看到更多由鲸鱼资助的垄断，因为垄断者日益成为最大的可用投资资本。随着 &quot;金钱阶层 &quot;和用户的分歧，我们应该看到（并且已经看到）越来越多的越来越多的激励错位和榨取租金。如果出现处理私人数据的DeFi应用，我们很可能会看到类似的动态，比如应用鼓励多个 &quot;拥有 &quot;数据的人之间进行竞标，这些人 &quot;拥有 &quot;实际上是人际关系的数据（例如他们的社交图），以建立单一的私有AI来与人类竞争，避免未来出现增强人类的多元人工智能的竞争。</p><p>因此，DeSoc不需要完美地通过可接受的非乌托邦的测试；要成为一个值得探索的范式，它只需要比现有的替代品更好。要成为值得探索的范式，它只需要比现有的替代方案更好。虽然DeSoc有可能出现需要防范的乌托邦情景，但web2和现有的DeFi正在陷入不可避免的乌托邦模式，将权力集中在决定社会结果或拥有大部分权力的精英阶层。不可避免的是，权力集中在决定社会结果或拥有大部分财富的精英阶层。web2的方向是决定性的专制，加速了自上而下的监视和行为操纵的能力。监视和行为操纵的能力。今天的DeFi的方向是名义上的无政府资本主义，但是已经陷入网络效应和垄断的压力中，其中期路径有可能变成同样方式的专制。</p><p>与此相反，DeSoc是随机的社会多元主义--由个人和社区组成的网络，作为彼此的突发属性，共同决定自己的未来。纵观web2，其可以把DESOC的发展比喻为民众参与式政府从几个世纪的君主制中崛起。君主制，参与式政府并不是不可避免地产生了民主；它也导致了共产主义和法西斯主义的兴起。同样地，SBTs并没有使数字基础设施本质上变得民主，而是民主相容性取决于灵魂和社区共同决定的东西。开放这种可能性空间是对web2的独裁主义和DeFi的无政府资本主义的明显改进。</p><h2 id="h-7" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">7 实施挑战</h2><p>隐私对 DeSoc 来说是一个关键挑战。 一方面，太多的公共 SBTs 可能会泄露太多关于灵魂的信息，使他们容易受到社会控制。 另一方面，过多的纯私有 SBTs 也可能导致通过私有沟通渠道避开治理和社会协调的相关性折扣——这提出了重要的激励相容性问题。 与隐私问题密切相关的是欺骗问题：灵魂可能会歪曲他们的社会团结，同时通过私人或辅助渠道进行协调。 我们不能渴望知道所有的可能性和答案，而是在这里探索挑战的本质，并为未来的研究勾勒出一些有希望的路径。</p><h3 id="h-71" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">7.1 私有灵魂</h3><p>基于区块链的系统默认是公开的。 记录在链上的任何关系不仅对参与者，而且对全世界的任何人都是立即可见的。 使用多个假名可以保留一些隐私：家庭灵魂、医疗灵魂、专业灵魂、政治灵魂，每个都携带不同的 SBT。 但是如果用户天真地来操作，很容易将这些灵魂相互关联起来。 这种缺乏隐私的后果是严重的。 事实上，如果没有采取明确的措施来保护隐私，简单地将所有 SBTs 上链的“幼稚”愿景很可能会使许多应用程序公开太多信息。</p><p>为了应对过度的公开化，有许多具有不同技术复杂性和功能级别的解决方案。 最简单的方法是 SBT 可以在链下存储数据，只留下链上数据的哈希值。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">img</figcaption></figure><p>如何存储链下数据的选择由个人决定； 可能的解决方案包括</p><p>（i）他们自己的设备；</p><p>（ii）他们信任的云服务；</p><p>或（iii）去中心化网络，例如星际文件系统（IPFS）。</p><p>将数据存储在链下让我们继续拥有向存储 SBTs 数据的智能合约写入的权限，但同时拥有读取该数据的单独权限。 Bob 可以选择仅在他愿意时透露他的任何 SBTs（或他们允许的数据存储）的内容。 这已经让我们走得很远，并且具有提高技术可扩展性的进一步好处，因为大多数数据只需要由极少数各方处理。 但要完全实现多元隐私等属性，以及更细粒度的披露形式，我们还需要更进一步。 幸运的是，许多加密技术让我们能够做到这一点。</p><p>一个强大的工具能够以新的方式部分揭示数据，它是密码学的一个分支，称为“零知识证明”。 虽然如今零知识证明最常用于保护隐私的资产转移，但它们也可以让人们证明任意陈述，而无需透露陈述本身之外的任何更多信息。 例如，在一个政府文件和其他证明可以通过密码证明的世界中，有人可以证明这样的陈述：“我是加拿大公民，年满 18 岁，拥有大学经济学学位和超过 50,000 名 Twitter 关注者，并且 谁还没有在这个系统中申请账户。”</p><p>零知识证明可以通过 SBT 计算来证明灵魂的特征（例如，它具有某些成员资格）。 该技术可以通过引入多方计算技术（例如乱码电路）进一步扩展，这可以使此类测试具有双重私密性：证明者不会向验证者透露他们是谁，并且验证者不会向证明者透露他们的验证机制。相反，双方一起进行计算，只能拿到输出结果。</p><p>另一种强大的技术是指定验证者证明。总的来说，“数据”具有滑溜溜的特性：如果我向您发送电影，我无法在技术上阻止您录制并将其发送给第三方。数字版权管理 (DRM) 等变通办法的有效性充其量是有限的，并且通常会给用户带来巨大的成本。然而，证明并非以同样的方式滑溜溜的。如果 Amma 想向 Bob 证明一些关于她的 SBT 的属性 X，她可以对“我持有满足属性 X 的 SBTs，或者我拥有 Bob 的灵魂的访问密钥”这一陈述进行零知识证明。 Bob 会认为这个陈述令人信服：他知道他没有做出证明，因此 Amma 实际上必须有满足性质 X 的 SBT。但是如果 Bob 将证明传递给 翠芬，翠芬不会被说服：据他所知， Bob 可以用他自己的密钥来证明。</p><p>这可以通过可验证的延迟函数 (VDF) 变得更加强大：Amma 可以制作并展示目前只能使用所需的 SBT 制作的证明，但其他任何人都可以在五分钟后制作。这意味着尽管不可能对原始数据本身（可能只是简单地复制和粘贴）拥有相同类型的有选择的权限，但可以表示对有关数据的可信证明的访问权限。尽管如此，这可能会让我们走得很远。正如区块链在交易中提供可追溯性以防止某人右键单击复制和粘贴有价值的 NFT（以及女巫攻击原始所有者）一样，SBTs 可以在社会传播中提供可追溯性，这至少可以通过未验证来源来降低复制-粘贴的价值。</p><p>这些示例的重点并不是要准确说明如何使用加密技术来解决 SBT 的所有隐私和数据许可问题。 相反，它是勾勒出几个例子来展示这些技术的力量。 一个重要的未来研究方向是确定不同类型数据许可的确切限制以及最适合实现所需许可级别的技术的特定组合。 另一个问题是需要什么样的多元财产制度来管理数据，以及如何正确地拆分访问（“usus”）、编辑（“abusus”）和获取现金流（“fructus”）权利。</p><h3 id="h-72" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">7.2 作弊的灵魂</h3><p>如果 SBT 是多种财产、网络商品和智能在其上协调的社会基础，人们可能会担心灵魂会试图欺骗或欺骗他们进入社区以获得我们想象 SBTs 允许的治理或财产权。例如，如果许多应用程序依赖于代表会议出席的 SBT，则不道德的会议可能会提供此类 SBTs 以换取贿赂。有了足够的贿赂，人类（和机器人）可以生成一个虚假的社交图谱，使该帐户看起来像一个真实的人类灵魂，并被（假的）SBTs 充分区分。就像 DAO 可以被贿赂一样，Souls 和他们使用的链上投票机制也可以。相反，如果 SBTs 用于降低协调性，灵魂可能会避免 SBTs 以最大化其影响。为什么我们应该相信灵魂拥有的 SBTs 准确地反映了他们真正的社会承诺，而不仅仅是他们选择如何玩这个游戏？</p><p>一个论点是，不同的作弊动机可能会“平衡”。灵魂可能会以适当的规模分类和自我识别到对他们来说很重要的网络中，就像哈伯格税收如何平衡对高估和低估资产的激励以得出大致准确的市场估值一样。 灵魂将希望持有更多的 SBTs 以在其社区内获得影响力，但另一方面，他们会避开他们不太关心的社区中的 SBTs，以在相关性指标上得分较低，并增加他们在更广泛网络治理中的影响力。</p><p>但是，如果假设这两种激励措施——获得访问权和最大化影响力——总是均匀地抵消，甚至接近于抵消，就好像施了魔法一样，那就太天真了。可能有许多社区使用 SBTs 以外的系统来控制访问和治理。或者社区可能——与我们关于公开的主要假设相反——发放私人 SBTs 以反映治理权，但诱使社区成员在更广泛的决策中对这些 SBTs 保密。</p><p>“欺诈”的问题不容小觑。这是一个重要的问题，解决它是未来研究的最重要的焦点之一。事实上，这就是为什么开源许多为人类用户优先或筛选的现有算法非常具有挑战性的一个主要原因。为了减轻和阻止 SBTs 中的欺诈，我们建议了几个规范和加密方向：</p><ul><li><p>SBT 的生态系统可以引导至“厚”的社区渠道，在这些渠道中，SBT 通过强大的社会纽带和重复互动表明真正的链下社区成员身份。 这将使社区更容易过滤和撤销冒充者和机器人的 SBT。 如此密集的渠道——我们经常在教堂、工作场所、学校、聚会团体和民间社会的组织中发现——将为在更“薄”的社交渠道中的监管游戏（例如，通过机器人、贿赂、冒充）提供更具抗女巫攻击的社会基础。</p></li><li><p>嵌套型社区可能需要 SBT 对“下方”的潜在共谋向量施加上下文。 例如，如果一个州正在举行一轮融资或投票，该州可能会要求每个参与的公民也持有一个确定的县和市的 SBT（州&gt;县/市）。</p></li><li><p>SBT 生态系统的开放性和密码学可证明性本身可用于主动检测合谋模式并惩罚不真实的行为——也许打折合谋灵魂的投票权，或迫使灵魂接受代表负面证明的 SBT。 例如，如果一个灵魂证明另一个灵魂是机器人，则案件可以升级并进行公开验证，导致该灵魂有大量负面证明。 这在 GitCoin QF 生态系统中已经在一定程度上发生了，其中使用一系列信号来检测“合谋团体”。</p></li><li><p>ZK 技术（例如 MACI）可以通过密码学的防止灵魂做出的某些证明是可证实的。 这将使出售某些类型的证明的尝试变得不可信，因为贿赂者无法判断受贿者是否遵守了他们的交易。 已经有大量关于使用这种技术进行投票的研究，但最终任何非金融化的社会机制都可能最终受益于类似的想法。</p></li><li><p>我们可以鼓励举报人，以此来使大规模的串通变得不稳定。 我们不是检测和惩罚不正确或不良行为，而是检测和惩罚不良的模式。 由于存在虚假贿赂的可能性，这种技术有过度使用的风险，但它仍然是工具包的一部分。</p></li><li><p>我们可以使用来自同行预测理论的机制来鼓励在所有情况下都诚实报告，除非勾结非常大。 与会议证明与会者的出席不同，与会者可以证明彼此的出席，因此需要贿赂以证明虚假声明的与会者数量变得非常大。 奖励不一定是金钱，可以是 SBTs，这使得奖励对真正的社区成员比对攻击者更有用。</p></li><li><p>如果一群灵魂有共同的兴趣，我们可以使用专注于相关性的相关性分数。 例如，有界成对二次融资中使用的相关评分技术使用二次融资捐赠本身来确定两个参与者的相关性，从而确定他们的交集的折扣程度。 如果两个参与者有许多共同利益，他们向 QF 机制表达这一事实的动机肯定会随着相关性折扣而减少，但它永远不会变成零或负数。</p></li></ul><h2 id="h-8" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">8 比较与局限</h2><p>虽然提出的身份框架的范围几乎是无限的，但在 web3 空间中有四个特别突出和相邻的范式被广泛讨论，值得比较：占主导地位的“传统”身份生态系统、假名经济、人格证明和可验证凭证。 每个范式都突出了我们所倡导的社会认同范式未来发展的重要贡献和挑战，我们将这些限制作为探索未来方向的跳板。 考虑到所有这些，我们还解释了为什么我们相信我们的灵魂和灵魂通证的社会身份原语是隐私制度的一条更有希望的前进道路。</p><h3 id="h-81" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">8.1 传统</h3><p>传统身份系统依赖于由第三方（政府、大学、雇主等）发行和调解的文件或身份证。通过调用第 3 方进行确认来确定出处。虽然遗留系统具有我们应该更深入地理解的一组有趣的属性，但这样的系统非常低效，并且不适合用于快速、高效协调的可组合性或计算。此外，这些系统缺乏社会背景，使灵魂依赖于一个集中的第三方来确认社区的成员身份，而不是嵌入社区。例如，大多数政府颁发的身份证明最终都可以追溯到医生和家庭成员授权签发的出生证明，他们是真相的最终来源，并且遗漏了许多同样有意义的社会联系，这些社会联系合起来提供了更强大的验证。事实上，当权力集中的中心寻求强有力的认同（例如，获得主要政府的安全许可）时，他们很少依赖此类文件，而是转向社交网络中的采访。因此，此类遗留身份系统倾向于将权力集中在发行人和那些能够进行尽职调查以获得更强大的验证的人身上，而这些人反过来又会成为刻板和不可靠的官僚机构。 DeSoc 的一个关键设计目标是确保能够满足和超过政府颁发的 ID 的安全要求，允许横向网络通过一系列社交基础为所有用户提供更高的安全性。</p><h3 id="h-82" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">8.2 假名经济</h3><p>Balaji Srinivasan 极大地推动了基于将声誉系统与零知识证明机制相结合以保护隐私的社会愿景，他创造并推广了“假名经济”一词。 他的早期版本强调使用假名来避免社会暴徒的歧视和“取消文化”（取消文化或呼吁文化是一个当代短语，用于指代一种排斥形式，在这种排斥形式中，某人被排除在社交或专业圈子之外——无论是在线、社交媒体还是面对面。 据说那些受到这种排斥的人已被“取消”），这些暴徒试图损害一个人的声誉并打破他们的社会联系。 它设想人们在他们的钱包中积累可转移的零知识 (ZK) 证明，并通过将证明子集转移到新钱包或将证明拆分到多个钱包中来逃避声誉攻击，这可能是没有可追溯性的。 在挑选要移植的证明时，一个人选择新帐户中所需的假名级别，权衡更多匿名性（移植较少的证明）或更多分布到他们的社交网络（移植更多的证明）之间的权衡。</p><p>典型的匿名经济提案与 DeSoc 之间的实际区别在于，我们不再强调身份分离是保护参与者免受滥用和取消文化的主要方式。 某种程度的分离（例如，家庭、工作、政治等之间的不同灵魂）可能是健康的，但一般而言，依靠建立新身份的能力作为抵御攻击的主要手段存在很大的缺点。 它使贷款和出处的声誉赌注变得更加困难，并且它与试图纠正相关性或 女巫攻击的治理机制的组合很差。</p><p>DeSoc 不会通过允许受害者以新的身份（如果已减少）重新出现在攻击中来保护受害者，而是允许其他方法，例如将攻击者情境化。 “取消”经常出现，因为当一个人或机器人与受害者几乎没有社交联系或背景时，声明和行动是脱离上下文并且病毒信号通过非上下文网络传播的。与 SBTs 提供出处以防止深度伪造的方式相同，SBT 的地图在社交上绘制了“热门作品”的起源。 “热门作品”本质上是在受害者社区之外产生的人工制品（由共享的 SBTs 成员资格反映），或者缺乏来自受害者社区的 SBTs 证明——这应该会让人怀疑该作品的真实性。 SBTs 还使受害者能够发起防御性反应，以抵消从他们的信任网络中策划和传播的打击（此处以共同持有 SBTs 的模式为代表）。通过维护社会背景，人们可以保持信任，即使他们面临取消的威胁，并追究攻击者的责任。改善出处可以改善真理的社会基础。</p><h3 id="h-83" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">8.3 人格证明</h3><p>人格证明协议 (PoP) 旨在提供个人唯一性的通证，以防止女巫攻击，同时允许非金融化应用程序。 为此，他们依赖于社交图谱的全局分析、生物识别、同步的全球关键方或它们的某种组合等方法。 然而，由于 PoP 协议寻求代表个人身份——专注于实现全球唯一性——而不是映射关系和团结的社会身份，所以 PoP 协议仅限于对所有人一视同仁的应用程序。 我们感兴趣的大多数应用程序（例如声誉质押）都是希望每个用户都是独特的、与众不同的人。</p><p>此外，PoP 协议也不能免受女巫攻击。 在几乎所有近期可预见的应用中，PoP 系统可能会遭受女巫攻击，只是成本略高。 除非地球上的大多数人都注册了 PoP 服务并且正在参与特定的验证活动，否则攻击者总是可以招募尚未参与的不感兴趣的人充当女巫。 虽然这样的雇佣兵并不完全是机器人，但区别只是表面的，可能只是增加了一点点费用。</p><p>许多 PoP 协议旨在为构建普遍基本收入或全球民主建立基础。 虽然我们的野心不同，但此类协议仍促使我们考虑如何逐步构建以协调多种网络产品。 与 PoP 的二元、个人主义和全球性质相比，我们的方法旨在为自下而上的声誉、财产和治理构建一个丰富的、上下文相关的和分层的基础，允许参与各种大小的社区和网络。</p><h3 id="h-84" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">8.4 可验证凭证</h3><p>可验证凭证 (VC) 是 W3C 标准，其中凭证（或证明）可根据持有者的判断进行 zk 共享。 VC 强调了我们基础隐私范式的主要局限性，并激发了我们对上述隐私扩展的讨论。 在 SBT 具有缩小宣传范围的隐私扩展之前，VC 和 SBTss 可以被视为自然的补充：特别是，SBTs 最初是公开的，因此它们不适用于政府颁发的身份证明等敏感信息，而 VC 的实施一直在努力寻找一种恢复范式，这可能是由社区恢复解决。 在短期内，这两种方法结合起来可能比单独使用任何一种方法都更强大。 但是 VC 也有一个关键的限制：至少在它们的标准化形式上，VC 不支持我们列举的大多数应用程序，因为它们具有单方面的隐私性。</p><p>在我们的用例中，单方面 zk 共享与激励不兼容，也不反映我们关于隐私的规范。我们的大多数应用程序都依赖于某种程度的宣传。但是在 zk-sharing 下，灵魂无法知道另一个灵魂拥有 SBT，除非它被共享给他们——这使得声誉赌注、可信承诺、抗女巫治理和简单的租赁合同（例如公寓租赁）无法摆脱不一定是可见的其他承诺和产权负担。更深入地说，我们怀疑单方面的可共享性被视为正确的隐私范式。多方关系中的一方很少有未经另一方同意而单方面披露关系的权利。正如单方面可转让的私有财产不是丰富的财产制度一样，简单的单方面可共享性也不是非常丰富的隐私制度。如果两方共同拥有一项资产并选择通过 VC 代表他们的关系，则这种凭证不允许相互同意和相互许可。这个问题涉及到更复杂的多元财产和复杂的组织形式和权限的情况，这是 DeSoc 的一个特点。</p><h2 id="h-9" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">9 灵魂诞生</h2><p>从当前的 web3 生态系统到由 SBTs 介导的增强社交的路径面临着典型的冷启动挑战。 一方面，SBTs 不可转让。 另一方面，今天的钱包组合可能不是 SBTs 的最终归宿，因为它们缺乏社区恢复机制。 但为了让社区恢复钱包发挥作用，他们需要跨不同社区的各种 SBTs 来保证安全。 首先要做是什么：SBTs 还是社区恢复？ 谁是早期接纳SBTs 的社区？ 不同链上的 SBTs 如何互操作？ 我们不能渴望知道所有的可能性和答案，而是勾勒出一些有希望的路径供读者在当前的 web3 甚至 web2 架构中进一步探索。</p><h3 id="h-91-sbts" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">9.1 SBTs 原型</h3><p>尽管 SBT 的标志是不可转让性，但 SBT 可能还具有另一个可能被证明在其启动中更有用的属性：可撤销性。 SBT 有可能首先孕育为可撤销、可转让的通证，然后才发展为不可转让。如果发行者可以销毁令牌并将其重新发行到新钱包，则令牌是可撤销的。例如，当密钥丢失或泄露时，燃烧和重新发行是有意义的，并且发行人有兴趣确保通证不会被金融化并出售给一方 —— 换句话说，当通证表明真正的社区成员身份时，具有重复链下互动的雇主、教堂、聚会团体、俱乐部很容易销毁和重新发行通证，因为它们与人有关系，并且可以通过电话、视频会议或简单的面对面会议。单一的互动，例如参加音乐会或会议，不太适合，因为社区纽带较弱。</p><p>可撤销、可转让的通证是一种原型 SBT——在灵魂出生之前提供支持性的胎盘功能。些通证为钱包争取时间来孕育安全的社区恢复机制，以及让人们积累积累的原始 SBT，这些原始 SBT 最终可以被烧毁并重发为不可转让的 SBT。在这条路径下，问题不是“首先会发生什么：SBT 还是社区恢复？” 相反，SBT 和社区恢复同时实现，产生了一个灵魂。</p><h3 id="h-92" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">9.2 社区恢复钱包</h3><p>尽管今天的钱包缺乏社区恢复能力，但它们在成为 SBT 的家——或者可能是妊娠子宫——方面都有相对的优势和劣势。 人格证明 (PoP) 协议的优势在于已经在尝试社会争议解决机制，这是社区恢复的基础。 此外，许多 DAO 使用 PoP 来促进治理，使其自然成为 SBT 的第一发行者。 然而，尽管 PoP 自然领先，但 PoP 协议尚未赢得广泛信任来存放有价值的通证资产，而托管型钱包则有。</p><p>托管钱包——尽管存在中心化缺陷——可能因此为不太成熟的零散用户提供了一个自然的入口。 此类托管钱包还可以为零售社区构建工具，以发行可撤销的通证，这些通证随后会转换（或销毁和重新发行）为 SBTs，甚至可以为更多“企业”发行人提供工具——其中许多人正在寻找在 web3 中建立忠诚客户群的方法，但 缺乏监管方面的专业知识。 一旦社区恢复机制正式确定并经过实战考验，这些托管钱包可以分散到社区恢复中，而托管人则继续在 DeSoc 中提供其他有价值的服务（如社区管理、SBTs 发行等）。</p><p>对于更成熟的 web3 用户，去中心化的非托管钱包（或像 Argent 和 Loopring 这样的非托管社交恢复钱包）是引导社区恢复机制的自然起点。 非托管钱包具有原生 web3 开源的优势，以及预先宣布和逐步试验机制的灵活性，以向自愿的、成熟的用户子集进行测试激励和混合机制（例如：多签）。 所有这些方法（PoP、托管和非托管）在试验和引导具有不同复杂程度和风险承受能力的用户方面发挥着重要作用。</p><h3 id="h-93" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">9.3 灵魂原型</h3><p>规范也可以引导灵魂存在。 当我们重新考虑通证和钱包时，我们还可以重新定义我们对某些类别的 NFT 和旨在表明会员资格的通证的看法。 特别是，我们可以引入不转移由信誉良好的机构颁发的 NFT 和 POAP 这一规范，这些机构反映了出席会议、工作经验或教育证书。 这种会员通证的转移——如果进行价值交易——可能会降低钱包的声誉，并可能阻止发行人进一步向该钱包发行会员或 POAP 通证。 在非托管生态系统中，大量用户已经获得了显着的财务声誉和钱包中的stake，这可以作为有效的抵押品引导他们不要滥用不可转让的期望。</p><p>虽然所有这些途径都有各自的挑战，但我们希望通过各种方法，经过逐步迭代，在中期收敛到一个准平衡状态。</p><h2 id="h-10" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">10 结论</h2><p>尽管我们一直在想象 DeSoc 可以实现什么，但在许多方面，上述只是第一步。 通往 DeSoc 的道路不止一条，包括许多基于非区块链的框架，例如 Spritely、ACDC 和 Backchannel，它们依赖于与本地机器而不是全球账本（区块链）的数据存储。 这些框架最终可能会在跨社交距离上提供更大的信任，因为它们可以利用信任关系的传递性——比如受信任的介绍——而不是依赖于知名的高地位机构（如大学或 DAO）发布的 SBTs。 此外，我们上面描述的应用程序只是 DeSoc 能够增强能力的开始，而不涉及虚拟世界：它们的物理、社会以及它们与真实世界的复杂交集。 所有这些都表明，即使是我们在上面描绘的广泛野心，也只是 DeSoc 最终可能成为的开始。</p><p>然而，在这条道路上，仍然存在许多挑战和悬而未决的问题。 上述草图需要大量的红队（竞争对手），其中许多比完全规范更像是建议。 DAO 如何在仔细比较 SBTs 中的灵魂模式和相关性，以执行女巫攻击的保护和去中心化的同时保持其状态宣传？ 面对各种相关贴现方案，获得 SBTs 的激励兼容性如何？ 隐私与相关折扣和其他 DeSoc 机制设计有多少冲突？ 我们如何以一种社会性的但又适当的私人方式来衡量不平等？ 继承在社区恢复框架中应该如何工作？ 是否有可以绘制甚至纳入协议的红线以避免反乌托邦情景？ 还是我们应该首先竞相构建最佳场景？ 这些问题只是我们期望的多年研究议程的开始，该议程将与 DeSoc 生态系统共同发展。</p><p>然而，DeSoc 的潜力似乎不仅值得为应对这些棘手的挑战付出代价，而且可能是确保我们生存所必需的。 阿尔伯特·爱因斯坦在 1932 年的会议上说，“人的组织能力”未能跟上“他的技术进步”的步伐，这让“一个 3 岁的孩子手里拿着一把剃刀”。 在一个他的观察似乎比以往任何时候都更有先见之明的世界里，学习如何为可编程社会编写未来——而不是将其写在主观信任之上——似乎是人类在这个星球上生存下去的必修课。</p>]]></content:encoded>
            <author>apecoder@newsletter.paragraph.com (Web3dAppDevCamp)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/9cb5da88fe2456a589702ed1286542b7de436f147792069c1b1bcd03a106a1a6.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[Web3Camp Context Index@NonceGeek]]></title>
            <link>https://paragraph.com/@apecoder/web3camp-context-index-noncegeek</link>
            <guid>iFx2b12JJE9rHfPXQ7tT</guid>
            <pubDate>Sat, 30 Apr 2022 03:35:30 GMT</pubDate>
            <description><![CDATA[国内用户请加微信：19726581 Authors: leeduckgo,msfew0x01 Web3 dApp Dev Camp1.1 Background0x01. Web3.0 is the next-generation Web paradigm, and Web3.0 dApp is the next-generation blockchain application paradigm. There are many new opportunities in both areas 0x02. Currently, there is a degree of disconnection between the Chinese and international software development industry, tech and blockchain community. The purpose of the Web3.0 dApp Dev Camp is to help developers including blockchain developers and...]]></description>
            <content:encoded><![CDATA[<blockquote><p>国内用户请加微信：19726581</p><p>Authors: <code>leeduckgo</code>,<code>msfew</code></p></blockquote><h2 id="h-0x01-web3-dapp-dev-camp" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x01 Web3 dApp Dev Camp</h2><h3 id="h-11-background" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">1.1 Background</h3><p>0x01. Web3.0 is the next-generation Web paradigm, and Web3.0 dApp is the next-generation blockchain application paradigm. There are many new opportunities in both areas</p><p>0x02. Currently, there is a degree of disconnection between the Chinese and international software development industry, tech and blockchain community. The purpose of the Web3.0 dApp Dev Camp is to help developers including blockchain developers and students access the most cutting-edge and coolest blockchain development tools and blockchain development paradigms.</p><h3 id="h-12-mission" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">1.2 Mission</h3><p>Web3 dApp Dev Camp is an online version of the Github Discussion-based, Project-oriented online bootcamp, designed to enable &quot;traditional software developer, college students, and blockchain developers&quot; to quickly learn how to develop on Ethereum-compatible chains (e.g. Moonbeam, Polygon) with Web3.0 dApp development skills.</p><h3 id="h-13-main-tasks" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">1.3 Main Tasks</h3><h4 id="h-131-ethereum-basics-with-ethbuild" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">1.3.1 Ethereum basics with eth.build</h4><ul><li><p>A visual understanding of blockchain fundamentals with eth.build</p><blockquote><p>English: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/0x769699506f972A992fc8950C766F0C7256Df601f/xcUOEKghOqaBJ3jDv7Spec__NjMChsey2y37yQkDoNM">https://mirror.xyz/0x769699506f972A992fc8950C766F0C7256Df601f/xcUOEKghOqaBJ3jDv7Spec__NjMChsey2y37yQkDoNM</a></p><p>Chinese: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mp.weixin.qq.com/s/wAoaFu6ql0HfR-LETGQ2DA">https://mp.weixin.qq.com/s/wAoaFu6ql0HfR-LETGQ2DA</a></p></blockquote></li><li><p>Calling smart contracts with eth.build</p><blockquote><p>Chinese: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/WeLightProject/Web3-dApp-Camp/discussions/6">https://github.com/WeLightProject/Web3-dApp-Camp/discussions/6</a></p></blockquote></li><li><p>Implementing blockchain explorer with eth.build</p><blockquote><p>Video: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ke.qq.com/course/3616174/11969953598483886?tuin=d34bd514">https://ke.qq.com/course/3616174/11969953598483886?tuin=d34bd514</a></p></blockquote></li></ul><h4 id="h-132-intro-to-scaffold-eth-framework" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">1.3.2 Intro to scaffold-eth framework</h4><ul><li><p>Scaffold-eth Quick Intro | Web3.0 dApp Dev 0x03</p><blockquote><p>English: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/0x769699506f972A992fc8950C766F0C7256Df601f/FxjGNBnf6IqPwf9BTObNktCrkkPfwfVo0khHmBui6fU">https://mirror.xyz/0x769699506f972A992fc8950C766F0C7256Df601f/FxjGNBnf6IqPwf9BTObNktCrkkPfwfVo0khHmBui6fU</a></p><p>Chinese: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mp.weixin.qq.com/s/72gzBaLNA0ruHSPsVBPtmQ">https://mp.weixin.qq.com/s/72gzBaLNA0ruHSPsVBPtmQ</a></p></blockquote></li><li><p>Get &amp; Set Value 1.0 | Web3.0 dApp Dev 0x04</p><blockquote><p>English: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/0x769699506f972A992fc8950C766F0C7256Df601f/iqlB8bddq3Rgv7fFc455OfqMNDf6M0hIEo1dWqlkohY">https://mirror.xyz/0x769699506f972A992fc8950C766F0C7256Df601f/iqlB8bddq3Rgv7fFc455OfqMNDf6M0hIEo1dWqlkohY</a></p><p>Chinese: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mp.weixin.qq.com/s/cCWNOvkAiJQQkF9Bvpnz_Q">https://mp.weixin.qq.com/s/cCWNOvkAiJQQkF9Bvpnz_Q</a></p></blockquote></li><li><p>Get &amp; Set Value 2.0 | Web3.0 dApp Dev 0x05</p><blockquote><p>English: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/0x73c7448760517E3E6e416b2c130E3c6dB2026A1d/b2Pz3Cxq3A9bjKWNlkgEqStZaMc6w89Cupgw9CcsPSs">https://mirror.xyz/0x73c7448760517E3E6e416b2c130E3c6dB2026A1d/b2Pz3Cxq3A9bjKWNlkgEqStZaMc6w89Cupgw9CcsPSs</a></p><p>Chinese: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mp.weixin.qq.com/s/gbnGsiBIFZhm1iydBPvBXg">https://mp.weixin.qq.com/s/gbnGsiBIFZhm1iydBPvBXg</a></p></blockquote></li><li><p>Get &amp; Set Value 3.0 | Web3.0 dApp Dev 0x06</p><blockquote><p>English: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/0x73c7448760517E3E6e416b2c130E3c6dB2026A1d/HvS9-pIa1raDuBUCaKGDZUpkFqElUX0fZpMkjoe5HQA">https://mirror.xyz/0x73c7448760517E3E6e416b2c130E3c6dB2026A1d/HvS9-pIa1raDuBUCaKGDZUpkFqElUX0fZpMkjoe5HQA</a></p><p>Chinese: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mp.weixin.qq.com/s/yVUv9CT-rPbPlwZ2g6iqSA">https://mp.weixin.qq.com/s/yVUv9CT-rPbPlwZ2g6iqSA</a></p></blockquote></li></ul><h4 id="h-133-defi" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">1.3.3 DeFi</h4><ul><li><p>Token vendo | Web3.0 dApp Dev 0x08</p><blockquote><p>English: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/0x73c7448760517E3E6e416b2c130E3c6dB2026A1d/_4PIlD_3kjSqx80Fs4n0EGRk2NUEQfL5qFXpMjzy8Bo">https://mirror.xyz/0x73c7448760517E3E6e416b2c130E3c6dB2026A1d/_4PIlD_3kjSqx80Fs4n0EGRk2NUEQfL5qFXpMjzy8Bo</a></p><p>Chinese: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mp.weixin.qq.com/s/FpAQlqWoxXyVVKzDg9vHvQ">https://mp.weixin.qq.com/s/FpAQlqWoxXyVVKzDg9vHvQ</a></p></blockquote></li></ul><h4 id="h-134-nft" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">1.3.4 NFT</h4><p>Work in progress</p><ul><li><p>Build SVG NFT dApp by Scaffold-Eth | Web3.0 dApp Dev 0x07</p><blockquote><p>English: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/0x73c7448760517E3E6e416b2c130E3c6dB2026A1d/kYL1EO8ZlksLdRTUBzoY-aPI6VkgBs-NIoFS8Qmc2rk">https://mirror.xyz/0x73c7448760517E3E6e416b2c130E3c6dB2026A1d/kYL1EO8ZlksLdRTUBzoY-aPI6VkgBs-NIoFS8Qmc2rk</a></p><p>Chinese: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mp.weixin.qq.com/s/WvTFk3E6FjfHtXfp2uHkrw">https://mp.weixin.qq.com/s/WvTFk3E6FjfHtXfp2uHkrw</a></p></blockquote></li><li><p>Voxel Art NFT dApp Development Series</p></li></ul><blockquote><p>Youtube:</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.youtube.com/channel/UCHFdayIAxLY3DEEMOz1142Q">https://www.youtube.com/channel/UCHFdayIAxLY3DEEMOz1142Q</a></p><p>Discussion:</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/WeLightProject/Web3-dApp-Camp/discussions/68">https://github.com/WeLightProject/Web3-dApp-Camp/discussions/68</a></p></blockquote><h3 id="h-14-task-elixir" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">1.4 Task: Elixir</h3><blockquote><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/WeLightProject/Web3-dApp-Camp/discussions/categories/projects-elixir">https://github.com/WeLightProject/Web3-dApp-Camp/discussions/categories/projects-elixir</a></p></blockquote><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">image-20220425103506016</figcaption></figure><h3 id="h-15-focus-area-moonbeam" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">1.5 Focus Area: Moonbeam</h3><p>Moonbeam is a supporting partner for NonceGeek.</p><blockquote><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/WeLightProject/Web3-dApp-Camp/discussions/categories/projects-moonbeam">https://github.com/WeLightProject/Web3-dApp-Camp/discussions/categories/projects-moonbeam</a></p></blockquote><h2 id="h-0x02-materials" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x02 Materials</h2><p>Materials are blockchain-related materials contributed by members.</p><blockquote><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/WeLightProject/Web3-dApp-Camp/discussions/categories/materials">https://github.com/WeLightProject/Web3-dApp-Camp/discussions/categories/materials</a></p></blockquote><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">image-20220425103714540</figcaption></figure><h2 id="h-0x03-workshop" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x03 Workshop</h2><p>Web3 dApp Dev Workshop is an AFK version, which is based on &quot;desktop game concept&quot; and emphasizes &quot;experience&quot;:</p><p>Workshop members are mainly Nonce Geek Studio members, and will also invite few external members to participate (targeted invitations or paid access).</p><ul><li><p>1st Workshop:</p><blockquote><p>[Summary] Generating game maps based on on-chain data @ Workshop 0x01</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mp.weixin.qq.com/s/u8ayW5-SbQSK_Kd5oUySRQ">https://mp.weixin.qq.com/s/u8ayW5-SbQSK_Kd5oUySRQ</a></p></blockquote></li></ul><p>---</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">leeduckgo</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">msfew</figcaption></figure>]]></content:encoded>
            <author>apecoder@newsletter.paragraph.com (Web3dAppDevCamp)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/9cb5da88fe2456a589702ed1286542b7de436f147792069c1b1bcd03a106a1a6.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[Build Simple POW Blockchain with Elixir | Elixir Branch 0x03]]></title>
            <link>https://paragraph.com/@apecoder/build-simple-pow-blockchain-with-elixir-elixir-branch-0x03</link>
            <guid>bnYWSA060RgHxqPd9rCS</guid>
            <pubDate>Wed, 13 Apr 2022 07:31:40 GMT</pubDate>
            <description><![CDATA[中文用户请加微信：197626581 Author: Fenix Translator: Snowyaya, msfewLivebook Version: https://github.com/zhenfeng-zhu/ex_chain Tutorial Video: https://ke.qq.com/course/3616174?tuin=d34bd514&taid=13066085086997934 Histories of this Branch: https://github.com/WeLightProject/Web3-dApp-Camp/discussions/31https://github.com/WeLightProject/Web3-dApp-Camp/discussions/320x01 Why ElixirElixir is a dynamic, functional language for building scalable and maintainable applications. https://elixir-lang.org/1.1 Ama...]]></description>
            <content:encoded><![CDATA[<blockquote><p>中文用户请加微信：197626581</p><p>Author: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="">Fenix</a></p><p>Translator: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/snowyaya">Snowyaya</a>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/fewwwww">msfew</a></p></blockquote><blockquote><p>Livebook Version: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/zhenfeng-zhu/ex_chain">https://github.com/zhenfeng-zhu/ex_chain</a></p><p>Tutorial Video:</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ke.qq.com/course/3616174?tuin=d34bd514&amp;taid=13066085086997934">https://ke.qq.com/course/3616174?tuin=d34bd514&amp;taid=13066085086997934</a></p><p>Histories of this Branch:</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/WeLightProject/Web3-dApp-Camp/discussions/31">https://github.com/WeLightProject/Web3-dApp-Camp/discussions/31</a></p></blockquote><blockquote><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/WeLightProject/Web3-dApp-Camp/discussions/32">https://github.com/WeLightProject/Web3-dApp-Camp/discussions/32</a></p></blockquote><h2 id="h-0x01-why-elixir" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x01 Why Elixir</h2><blockquote><p>Elixir is a dynamic, functional language for building scalable and maintainable applications.</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://elixir-lang.org/">https://elixir-lang.org/</a></p></blockquote><h3 id="h-11-amazing-syntax" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">1.1 Amazing Syntax</h3><p>Elixir&apos;s syntax is a tribute to Ruby with a touch of Erlang. The design of any language syntax is inseparable from the preferences and goals of its authors, and Elixir&apos;s authors were core developers in the Rails community, so the syntax is naturally very Ruby. Of course, Elixir, which is rooted in Erlang, has many of its own features.</p><p>What&apos;s most endearing is the pipe <code>|&gt;</code>, which turns layers of backwards-thinking function calls into a more intuitive representation, for example, we often write code like this:</p><pre data-type="codeBlock" text="IO.puts(format(to_map(Store.get_host(host))))

or

list_data = Store.get_host(host)
map = to_map(list)
formatted_output = format(map)
IO.puts(formatted_output)
"><code>IO.puts(format(to_map(Store.get_host(host))))

or

list_data <span class="hljs-operator">=</span> Store.get_host(host)
map <span class="hljs-operator">=</span> to_map(list)
formatted_output <span class="hljs-operator">=</span> format(map)
IO.puts(formatted_output)
</code></pre><p>Such code could be written in Elixir as:</p><pre data-type="codeBlock" text="host
|&gt; Store.get_host
|&gt; to_map
|&gt; foramt
|&gt; IO.puts
"><code>host
<span class="hljs-operator">|</span><span class="hljs-operator">></span> Store.get_host
<span class="hljs-operator">|</span><span class="hljs-operator">></span> to_map
<span class="hljs-operator">|</span><span class="hljs-operator">></span> foramt
<span class="hljs-operator">|</span><span class="hljs-operator">></span> IO.puts
</code></pre><p>Very clear! Most importantly, it fits more into your mindset and makes it easier to get the code flowing at your fingertips. When we write code, it is basically a process of constant &quot;partitioning&quot;: breaking down big problems into small ones, and small problems into even smaller ones, and finally solving them. And Elixir gives you a high degree of consistency in your code and your thinking.</p><p>pipe is very flexible. You can organize your ideas and combine functions at the same time. This is a bit of like building blocks.</p><h3 id="h-12-pattern-matching" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">1.2 Pattern Matching</h3><p>Anyone who has learned a little bit of programming should know that = is the assignment operator in most programming languages. Even if this is not the case, there is a similar symbol with a variable on its left and a constant assigned to it on its right. Other variables or some operations such as: a = 1 or a = max(number_list).</p><p>However, in Elixir, = is the match operator.</p><pre data-type="codeBlock" text="iex&gt;a = 1
1
iex&gt;1 = a
1
iex&gt;2 = a
** (MatchError) no match of right hand side value: 1
"><code>iex<span class="hljs-operator">></span>a <span class="hljs-operator">=</span> <span class="hljs-number">1</span>
<span class="hljs-number">1</span>
iex<span class="hljs-operator">></span><span class="hljs-number">1</span> <span class="hljs-operator">=</span> a
<span class="hljs-number">1</span>
iex<span class="hljs-operator">></span><span class="hljs-number">2</span> <span class="hljs-operator">=</span> a
<span class="hljs-operator">*</span><span class="hljs-operator">*</span> (MatchError) no match of right hand side <span class="hljs-built_in">value</span>: <span class="hljs-number">1</span>
</code></pre><p>Elixir&apos;s pattern matching and recursion work really well together. There is no need to use the if else flow to determine the boundary values, and the code is expressed quite elegantly.</p><p>I think that recursion can be said to be a very good representation of the First Principle principle. Only by looking at the nature of data processing can we understand recursion. Let&apos;s take a look at one of the best quotes from the book.</p><blockquote><p>L. Peter Deutsch once penned, “To iterate is human, to recurse divine.”</p></blockquote><p>As an example to get a feel for it:</p><pre data-type="codeBlock" text="defmodule Recursion do
  def sum(0), do: 0
  def sum(n), do: n + sum(n - 1)
end

IO.puts Recursion.sum(5)  # =&gt; 15
"><code>defmodule Recursion <span class="hljs-keyword">do</span>
  def <span class="hljs-built_in">sum</span>(0), <span class="hljs-keyword">do</span>: 0
  def <span class="hljs-built_in">sum</span>(n), <span class="hljs-keyword">do</span>: n + <span class="hljs-built_in">sum</span>(n - 1)
end

IO.puts Recursion.<span class="hljs-built_in">sum</span>(5)  <span class="hljs-comment"># => 15</span>
</code></pre><p>This function calculates the sum of all positive integers under a given number. The above example is calculating 5+4+3+2+1+0.</p><p>Replacing most conditional branches with pattern matching is a great thing: the simplicity of the code goes without saying, and its efficiency can be further optimized. If/else is a sequential logic, and because of the flexibility of its syntax (everyone does it to have the if condition as a function), it can be optimized for special cases using jump tables, most of which are O(N) and difficult to handle in parallel. While pattern matching due to its syntactic limitations, many cases can be optimized into a decision tree, the time complexity is O(logN), and there is room for parallel processing optimization in the future.</p><h3 id="h-13-macro" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">1.3 Macro</h3><p>Many people see a macro and think it represents some kind of mysterious power.</p><p>In fact, we can think of a macro as a special function that accepts a syntax tree (one or more) as an argument and then returns a syntax tree.</p><p>Is the defmodule block a syntax? No, it is a macro. is a def block a syntax? No, it is still a macro.</p><pre data-type="codeBlock" text="x in [1, 2, 3] # =&gt; true
"><code>x in [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>] # <span class="hljs-operator">=</span><span class="hljs-operator">></span> <span class="hljs-literal">true</span>
</code></pre><p>This should be a syntax now, right? No, even in is a macro.</p><h3 id="h-14-born-with-concurrent-support" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">1.4 Born with Concurrent Support</h3><p>Elixir is built on top of Erlang and eventually compiles into fully equivalent bytecode modules that can call each other.</p><p>Erlang&apos;s actor-based concurrency model, let it crash idea, supervisory tree, error handling, are the best practices that have been summed up during the struggle with concurrency for more than 20 years, both ideologically and practically. Elixir stands on the shoulders of giants and enjoys its success.</p><h3 id="h-15-full-toolchain" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">1.5 Full Toolchain</h3><p>Since the 21st century, emerging languages have also gone all out on the toolchain, which has (almost) become part of the language rather than an appendage.</p><p>Elixir carries its own mix -- from project creation and scaffolding (mix new), to compilation (mix compile), to testing (mix test), to documentation (mix doc), to dependency management (mix deps), all wrapped up.</p><blockquote><p>Reference: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://zhuanlan.zhihu.com/p/19968376">elixir: panacea? or in vain?</a></p></blockquote><h3 id="h-16-livebook" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">1.6 Livebook</h3><p>Livebook is an interactive and collaborative code notebook for writing for Elixir. It can be compared to Python&apos;s jupyter notebook.</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://livebook.dev/">https://livebook.dev/</a></p><h4 id="h-mixinstall2" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Mix.install/2</h4><p>We can install the dependencies via <code>Mix.install/2</code>.</p><p>:force - if true, removes install cache. This is useful when you want to update your dependencies or your install got into an inconsistent state (Default: false)</p><p>:verbose - if true, prints additional debugging information (Default: false)</p><pre data-type="codeBlock" text="Mix.install(
  [:poison, :req]
  # force: true,
  # verbose: true
)
"><code>Mix.<span class="hljs-title function_ invoke__">install</span>(
  [:poison, :req]
  # <span class="hljs-attr">force</span>: <span class="hljs-literal">true</span>,
  # <span class="hljs-attr">verbose</span>: <span class="hljs-literal">true</span>
)
</code></pre><pre data-type="codeBlock" text=":ok
"><code><span class="hljs-symbol">:ok</span>
</code></pre><pre data-type="codeBlock" text="%{hello: &quot;world&quot;, arr: [1, 2, 3]}
|&gt; Poison.encode!()
|&gt; IO.inspect()

&quot;{\&quot;hello\&quot;: \&quot;world\&quot;,\&quot;arr\&quot;: [1, 2, 3]}&quot;
|&gt; Poison.decode!()
|&gt; IO.inspect()
"><code><span class="hljs-operator">%</span>{hello: <span class="hljs-string">"world"</span>, arr: [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>]}
<span class="hljs-operator">|</span><span class="hljs-operator">></span> Poison.encode!()
<span class="hljs-operator">|</span><span class="hljs-operator">></span> IO.inspect()

<span class="hljs-string">"{\"hello\": \"world\",\"arr\": [1, 2, 3]}"</span>
<span class="hljs-operator">|</span><span class="hljs-operator">></span> Poison.decode!()
<span class="hljs-operator">|</span><span class="hljs-operator">></span> IO.inspect()
</code></pre><pre data-type="codeBlock" text="&quot;{\&quot;hello\&quot;:\&quot;world\&quot;,\&quot;arr\&quot;:[1,2,3]}&quot;
%{&quot;arr&quot; =&gt; [1, 2, 3], &quot;hello&quot; =&gt; &quot;world&quot;}
"><code><span class="hljs-string">"{<span class="hljs-subst">\"</span>hello<span class="hljs-subst">\"</span>:<span class="hljs-subst">\"</span>world<span class="hljs-subst">\"</span>,<span class="hljs-subst">\"</span>arr<span class="hljs-subst">\"</span>:[1,2,3]}"</span>
<span class="hljs-operator">%</span>{<span class="hljs-string">"arr"</span> <span class="hljs-operator">=></span> [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>], <span class="hljs-string">"hello"</span> <span class="hljs-operator">=></span> <span class="hljs-string">"world"</span>}
</code></pre><pre data-type="codeBlock" text="%{&quot;arr&quot; =&gt; [1, 2, 3], &quot;hello&quot; =&gt; &quot;world&quot;}
"><code><span class="hljs-operator">%</span>{<span class="hljs-string">"arr"</span> <span class="hljs-operator">=</span><span class="hljs-operator">></span> [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>], <span class="hljs-string">"hello"</span> <span class="hljs-operator">=</span><span class="hljs-operator">></span> <span class="hljs-string">"world"</span>}
</code></pre><pre data-type="codeBlock" text="Req.get!(&quot;https://api.github.com/repos/elixir-lang/elixir&quot;).body[&quot;description&quot;]
"><code>Req.get!(<span class="hljs-string">"https://api.github.com/repos/elixir-lang/elixir"</span>).body[<span class="hljs-string">"description"</span>]
</code></pre><pre data-type="codeBlock" text="&quot;Elixir is a dynamic, functional language designed for building scalable and maintainable applications&quot;
"><code><span class="hljs-string">"Elixir is a dynamic, functional language designed for building scalable and maintainable applications"</span>
</code></pre><p>More fun examples can be found at: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/wojtekmach/mix_install_examples">https://github.com/wojtekmach/mix_install_examples</a></p><h2 id="h-0x02-blockchain-introduction" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x02 Blockchain Introduction</h2><h3 id="h-21-block" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2.1 Block</h3><p>The easiest and quickest way to understand what a block really is is to analyze its data structure, using the example of block #514095 in Bitcoin:</p><pre data-type="codeBlock" text="{
  &quot;hash&quot;: &quot;00000000000000000018b0a6ae560fa33c469b6528bc9e0fb0c669319a186c33&quot;,
  &quot;confirmations&quot;: 1009,
  &quot;strippedsize&quot;: 956228,
  &quot;size&quot;: 1112639,
  &quot;weight&quot;: 3981323,
  &quot;height&quot;: 514095,
  &quot;version&quot;: 536870912,
  &quot;versionHex&quot;: &quot;20000000&quot;,
  &quot;merkleroot&quot;: &quot;5f8f8e053fd4c0c3175c10ac5189c15e6ba218909319850936fe54934dcbfeac&quot;,
  &quot;tx&quot;: [
    // ...
  ],
  &quot;time&quot;: 1521380124,
  &quot;mediantime&quot;: 1521377506,
  &quot;nonce&quot;: 3001236454,
  &quot;bits&quot;: &quot;17514a49&quot;,
  &quot;difficulty&quot;: 3462542391191.563,
  &quot;chainwork&quot;: &quot;0000000000000000000000000000000000000000014d2b41a340e60b72292430&quot;,
  &quot;previousblockhash&quot;: &quot;000000000000000000481ab128418847dc25db4dafec464baa5a33e66490990b&quot;,
  &quot;nextblockhash&quot;: &quot;0000000000000000000c74966205813839ad1c6d55d75f95c9c5f821db9c3510&quot;
}
"><code><span class="hljs-punctuation">{</span>
  <span class="hljs-attr">"hash"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"00000000000000000018b0a6ae560fa33c469b6528bc9e0fb0c669319a186c33"</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"confirmations"</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1009</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"strippedsize"</span><span class="hljs-punctuation">:</span> <span class="hljs-number">956228</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"size"</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1112639</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"weight"</span><span class="hljs-punctuation">:</span> <span class="hljs-number">3981323</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"height"</span><span class="hljs-punctuation">:</span> <span class="hljs-number">514095</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"version"</span><span class="hljs-punctuation">:</span> <span class="hljs-number">536870912</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"versionHex"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"20000000"</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"merkleroot"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"5f8f8e053fd4c0c3175c10ac5189c15e6ba218909319850936fe54934dcbfeac"</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"tx"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span>
    <span class="hljs-comment">// ...</span>
  <span class="hljs-punctuation">]</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"time"</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1521380124</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"mediantime"</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1521377506</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"nonce"</span><span class="hljs-punctuation">:</span> <span class="hljs-number">3001236454</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"bits"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"17514a49"</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"difficulty"</span><span class="hljs-punctuation">:</span> <span class="hljs-number">3462542391191.563</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"chainwork"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"0000000000000000000000000000000000000000014d2b41a340e60b72292430"</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"previousblockhash"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"000000000000000000481ab128418847dc25db4dafec464baa5a33e66490990b"</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"nextblockhash"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"0000000000000000000c74966205813839ad1c6d55d75f95c9c5f821db9c3510"</span>
<span class="hljs-punctuation">}</span>
</code></pre><p>In the structure of this Block, previousblockhash and merkleroot are the two most important fields. The former is a hash pointer, which is actually a hash of the previous Block, and through the previousblockhash we can recursively find all the Blocks, i.e., the entire chain; The latter is the root of a Merkle tree, which contains all the transactions in the entire Block. By saving the merkleroot, we can ensure that no transaction in the current Block will be modified.</p><p>Ethereum&apos;s blockchain model is very different from Bitcoin&apos;s, but it has similar information in its Block structure.</p><pre data-type="codeBlock" text="{
   &quot;jsonrpc&quot;:&quot;2.0&quot;,
   &quot;result&quot;:{
      &quot;author&quot;:&quot;0x00d8ae40d9a06d0e7a2877b62e32eb959afbe16d&quot;,
      &quot;difficulty&quot;:&quot;0x785042b0&quot;,
      &quot;extraData&quot;:&quot;0x414952412f7630&quot;,
      &quot;gasLimit&quot;:&quot;0x47b784&quot;,
      &quot;gasUsed&quot;:&quot;0x44218a&quot;,
      &quot;hash&quot;:&quot;0x4de91e4af8d135e061d50ddd6d0d6f4119cd0f7062ebe8ff2d79c5af0e8344b9&quot;,
      &quot;logsBloom&quot;:&quot;0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000&quot;,
      &quot;miner&quot;:&quot;0x00d8ae40d9a06d0e7a2877b62e32eb959afbe16d&quot;,
      &quot;mixHash&quot;:&quot;0xb8155224974967443d8b83e484402fb6e1e18ff69a8fc5acdda32f2bcc6dd443&quot;,
      &quot;nonce&quot;:&quot;0xad14fb6803147c7c&quot;,
      &quot;number&quot;:&quot;0x2000f1&quot;,
      &quot;parentHash&quot;:&quot;0x31919e2bf29306778f50bbc376bd490a7d056ddfd5b1f615752e79f32c7f1a38&quot;,
      &quot;receiptsRoot&quot;:&quot;0xa2a7af5e3b9e1bbb6252ba82a09302321b8f0eea7ec8e3bb977401e4f473e672&quot;,
      &quot;sealFields&quot;:[
         &quot;0xa0b8155224974967443d8b83e484402fb6e1e18ff69a8fc5acdda32f2bcc6dd443&quot;,
         &quot;0x88ad14fb6803147c7c&quot;
      ],
      &quot;sha3Uncles&quot;:&quot;0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347&quot;,
      &quot;size&quot;:&quot;0x276&quot;,
      &quot;stateRoot&quot;:&quot;0x87e7e54cf229003014f453d64f0344e2ba4fc7ee3b95c7dd2642cca389fa1efe&quot;,
      &quot;timestamp&quot;:&quot;0x5a10968a&quot;,
      &quot;totalDifficulty&quot;:&quot;0x1804de0c47ffe1&quot;,
      &quot;transactions&quot;:[...],
      &quot;transactionsRoot&quot;:&quot;0xc2091b032961ca23cf8323ea827e8956fe6dda9e68d75bcfaa8b910035397e35&quot;,
      &quot;uncles&quot;:[]
   },
   &quot;id&quot;:1
}
"><code>{
   <span class="hljs-string">"jsonrpc"</span>:<span class="hljs-string">"2.0"</span>,
   <span class="hljs-string">"result"</span>:{
      <span class="hljs-string">"author"</span>:<span class="hljs-string">"0x00d8ae40d9a06d0e7a2877b62e32eb959afbe16d"</span>,
      <span class="hljs-string">"difficulty"</span>:<span class="hljs-string">"0x785042b0"</span>,
      <span class="hljs-string">"extraData"</span>:<span class="hljs-string">"0x414952412f7630"</span>,
      <span class="hljs-string">"gasLimit"</span>:<span class="hljs-string">"0x47b784"</span>,
      <span class="hljs-string">"gasUsed"</span>:<span class="hljs-string">"0x44218a"</span>,
      <span class="hljs-string">"hash"</span>:<span class="hljs-string">"0x4de91e4af8d135e061d50ddd6d0d6f4119cd0f7062ebe8ff2d79c5af0e8344b9"</span>,
      <span class="hljs-string">"logsBloom"</span>:<span class="hljs-string">"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"</span>,
      <span class="hljs-string">"miner"</span>:<span class="hljs-string">"0x00d8ae40d9a06d0e7a2877b62e32eb959afbe16d"</span>,
      <span class="hljs-string">"mixHash"</span>:<span class="hljs-string">"0xb8155224974967443d8b83e484402fb6e1e18ff69a8fc5acdda32f2bcc6dd443"</span>,
      <span class="hljs-string">"nonce"</span>:<span class="hljs-string">"0xad14fb6803147c7c"</span>,
      <span class="hljs-string">"number"</span>:<span class="hljs-string">"0x2000f1"</span>,
      <span class="hljs-string">"parentHash"</span>:<span class="hljs-string">"0x31919e2bf29306778f50bbc376bd490a7d056ddfd5b1f615752e79f32c7f1a38"</span>,
      <span class="hljs-string">"receiptsRoot"</span>:<span class="hljs-string">"0xa2a7af5e3b9e1bbb6252ba82a09302321b8f0eea7ec8e3bb977401e4f473e672"</span>,
      <span class="hljs-string">"sealFields"</span>:[
         <span class="hljs-string">"0xa0b8155224974967443d8b83e484402fb6e1e18ff69a8fc5acdda32f2bcc6dd443"</span>,
         <span class="hljs-string">"0x88ad14fb6803147c7c"</span>
      ],
      <span class="hljs-string">"sha3Uncles"</span>:<span class="hljs-string">"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"</span>,
      <span class="hljs-string">"size"</span>:<span class="hljs-string">"0x276"</span>,
      <span class="hljs-string">"stateRoot"</span>:<span class="hljs-string">"0x87e7e54cf229003014f453d64f0344e2ba4fc7ee3b95c7dd2642cca389fa1efe"</span>,
      <span class="hljs-string">"timestamp"</span>:<span class="hljs-string">"0x5a10968a"</span>,
      <span class="hljs-string">"totalDifficulty"</span>:<span class="hljs-string">"0x1804de0c47ffe1"</span>,
      <span class="hljs-string">"transactions"</span>:[...],
      <span class="hljs-string">"transactionsRoot"</span>:<span class="hljs-string">"0xc2091b032961ca23cf8323ea827e8956fe6dda9e68d75bcfaa8b910035397e35"</span>,
      <span class="hljs-string">"uncles"</span>:[]
   },
   <span class="hljs-string">"id"</span>:<span class="hljs-number">1</span>
}
</code></pre><p>parentHash and transactionsRoot correspond to the previousblockhash and merkleroot in Bitcoin, respectively. These two are very important in the whole blockchain network.</p><h3 id="h-22-hash-pointer" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2.2 Hash Pointer</h3><p>The hash pointer in the Block structure has two roles in the blockchain; it not only connects different blocks, but also validates the Block to ensure that the data in the Block is not tampered with by other malicious nodes.</p><p>!Unsupported embed</p><p>Except for the first Block, the prev_hash in each Block is the hash of the previous Block. If a node wants to modify the transaction of a Block on the main chain, it will change the hash of the current Block. If a node wants to modify the transaction of the Block on the main chain, it will change the hash of the current Block, and the later Block will have no way to find the previous chain through prev_hash. So the current node will be discovered by other nodes if it tampers with the transaction.</p><h3 id="h-23-merkle-tree" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2.3 Merkle Tree</h3><p>Another field merkleroot is actually the root node of a Merkle tree, which is actually a data structure connected using a hash pointer; although Merkle trees have leaf and non-leaf nodes, it only stores data in the leaf nodes. However, only the leaf nodes store data, and all non-leaf nodes are hashes used to verify data integrity.</p><p>!Unsupported embed</p><p>All transactions in each Block are stored in this Merkle tree and the merkleroot is stored in the Block&apos;s structure. This ensures that any transaction tampering in the current Block can be detected immediately.</p><h3 id="h-24-summary" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2.4 Summary</h3><p>prev_hash and merkleroot ensure that all blocks and transactions are connected by means of &quot;pointers&quot; respectively, which ultimately ensures that blocks and transactions are not tampered with by malicious nodes or attackers, and almost all blockchain projects use similar methods to connect different blocks and transactions. This can be said to be the infrastructure and standard for blockchain projects.</p><blockquote><p>Reference: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://draveness.me/utxo-account-models/">Draveness&apos;s blog</a></p></blockquote><h2 id="h-0x03-create-a-block" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x03 Create a block</h2><h3 id="h-31-block" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">3.1 Block</h3><p>A basic block structure is as follows:</p><pre data-type="codeBlock" text="%{
  :index =&gt; 0,
  :timestamp =&gt; &quot;&quot;,
  :name =&gt; &quot;&quot;,
  :previous_hash =&gt; &quot;&quot;,
  :current_transactions =&gt; []
}
"><code><span class="hljs-operator">%</span>{
  :index <span class="hljs-operator">=</span><span class="hljs-operator">></span> <span class="hljs-number">0</span>,
  :timestamp <span class="hljs-operator">=</span><span class="hljs-operator">></span> <span class="hljs-string">""</span>,
  :name <span class="hljs-operator">=</span><span class="hljs-operator">></span> <span class="hljs-string">""</span>,
  :previous_hash <span class="hljs-operator">=</span><span class="hljs-operator">></span> <span class="hljs-string">""</span>,
  :current_transactions <span class="hljs-operator">=</span><span class="hljs-operator">></span> []
}
</code></pre><ul><li><p>index: index of the current block</p></li><li><p>timestamp: the time when the block was generated</p></li><li><p>name: the name of the block</p></li><li><p>previous_hash: hash of the previous block</p></li><li><p>current_transactions: the transactions of the current block</p></li></ul><p>At this point, the concept of a blockchain should be obvious: each new block contains a hash of the previous block within it.</p><p>This is critical because it is the reason why the blockchain is immutable. If an attacker corrupts an earlier block in the blockchain, all subsequent blocks will contain incorrect hashes. Does this make sense? If you haven&apos;t figured it out yet, take some time to think about it carefully.</p><p>This is the core idea behind the blockchain.</p><p>The basic structure of the program is as follows:</p><pre data-type="codeBlock" text="defmodule Blockchain do
  defstruct chain: [], current_transactions: []

  def new_block(c, name) do
  end

  def zero() do
  end

  def last_block(c) do
  end

  def hash(block) do
  end
end
"><code>defmodule <span class="hljs-title class_">Blockchain</span> <span class="hljs-keyword">do</span>
  defstruct <span class="hljs-symbol">chain:</span> [], <span class="hljs-symbol">current_transactions:</span> []

  <span class="hljs-keyword">def</span> <span class="hljs-title function_">new_block</span>(<span class="hljs-params">c, name</span>) <span class="hljs-keyword">do</span>
  <span class="hljs-keyword">end</span>

  <span class="hljs-keyword">def</span> <span class="hljs-title function_">zero</span>() <span class="hljs-keyword">do</span>
  <span class="hljs-keyword">end</span>

  <span class="hljs-keyword">def</span> <span class="hljs-title function_">last_block</span>(<span class="hljs-params">c</span>) <span class="hljs-keyword">do</span>
  <span class="hljs-keyword">end</span>

  <span class="hljs-keyword">def</span> <span class="hljs-title function_">hash</span>(<span class="hljs-params">block</span>) <span class="hljs-keyword">do</span>
  <span class="hljs-keyword">end</span>
<span class="hljs-keyword">end</span>
</code></pre><pre data-type="codeBlock" text="warning: variable &quot;c&quot; is unused (if the variable is not meant to be used, prefix it with an underscore)
  share.livemd#cell:4: Blockchain.new_block/2

warning: variable &quot;name&quot; is unused (if the variable is not meant to be used, prefix it with an underscore)
  share.livemd#cell:4: Blockchain.new_block/2

warning: variable &quot;c&quot; is unused (if the variable is not meant to be used, prefix it with an underscore)
  share.livemd#cell:10: Blockchain.last_block/1

warning: variable &quot;block&quot; is unused (if the variable is not meant to be used, prefix it with an underscore)
  share.livemd#cell:13: Blockchain.hash/1
"><code>warning: variable <span class="hljs-string">"c"</span> <span class="hljs-keyword">is</span> unused (<span class="hljs-keyword">if</span> the variable <span class="hljs-keyword">is</span> not meant to be used, prefix it with an underscore)
  share.livemd#cell:<span class="hljs-number">4</span>: Blockchain.new_block/<span class="hljs-number">2</span>

warning: variable <span class="hljs-string">"name"</span> <span class="hljs-keyword">is</span> unused (<span class="hljs-keyword">if</span> the variable <span class="hljs-keyword">is</span> not meant to be used, prefix it with an underscore)
  share.livemd#cell:<span class="hljs-number">4</span>: Blockchain.new_block/<span class="hljs-number">2</span>

warning: variable <span class="hljs-string">"c"</span> <span class="hljs-keyword">is</span> unused (<span class="hljs-keyword">if</span> the variable <span class="hljs-keyword">is</span> not meant to be used, prefix it with an underscore)
  share.livemd#cell:<span class="hljs-number">10</span>: Blockchain.last_block/<span class="hljs-number">1</span>

warning: variable <span class="hljs-string">"block"</span> <span class="hljs-keyword">is</span> unused (<span class="hljs-keyword">if</span> the variable <span class="hljs-keyword">is</span> not meant to be used, prefix it with an underscore)
  share.livemd#cell:<span class="hljs-number">13</span>: Blockchain.hash/<span class="hljs-number">1</span>
</code></pre><pre data-type="codeBlock" text="{:module, Blockchain, &lt;&lt;70, 79, 82, 49, 0, 0, 9, ...&gt;&gt;, {:hash, 1}}
"><code>{:module, Blockchain, <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">&#x3C;</span><span class="hljs-number">70</span>, <span class="hljs-number">79</span>, <span class="hljs-number">82</span>, <span class="hljs-number">49</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">9</span>, ...><span class="hljs-operator">></span>, {:hash, <span class="hljs-number">1</span>}}
</code></pre><h3 id="h-32-complete-the-program" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">3.2 Complete the Program</h3><p>Completes the new_block function:</p><pre data-type="codeBlock" text="def new_block(c, name) do
    b = %{
      :index =&gt; length(c.chain),
      :timestamp =&gt; NaiveDateTime.utc_now(),
      :name =&gt; name,
      :previous_hash =&gt; c |&gt; last_block() |&gt; hash(),
      :current_transactions =&gt; c.current_transactions
    }

    %{c | chain: c.chain ++ [b], current_transactions: []}
end
"><code>def new_block(c, name) do
    b <span class="hljs-operator">=</span> <span class="hljs-operator">%</span>{
      :index <span class="hljs-operator">=</span><span class="hljs-operator">></span> length(c.chain),
      :timestamp <span class="hljs-operator">=</span><span class="hljs-operator">></span> NaiveDateTime.utc_now(),
      :name <span class="hljs-operator">=</span><span class="hljs-operator">></span> name,
      :previous_hash <span class="hljs-operator">=</span><span class="hljs-operator">></span> c <span class="hljs-operator">|</span><span class="hljs-operator">></span> last_block() <span class="hljs-operator">|</span><span class="hljs-operator">></span> hash(),
      :current_transactions <span class="hljs-operator">=</span><span class="hljs-operator">></span> c.current_transactions
    }

    <span class="hljs-operator">%</span>{c <span class="hljs-operator">|</span> chain: c.chain <span class="hljs-operator">+</span><span class="hljs-operator">+</span> [b], current_transactions: []}
end
</code></pre><ul><li><p>Compute the hash of the previous block and write it to the previous_hash</p></li><li><p>%{c | chain: c.chain ++ [b], current_transactions: []} is a syntax sugar that appends the current block to the chain.</p></li></ul><p>Elixir hash to be done with the <code>:crypto.hash</code> function like:</p><pre data-type="codeBlock" text="value = &quot;fenix&quot;

:crypto.hash(:sha256, value)
|&gt; Base.encode16()
|&gt; String.downcase()
"><code>value <span class="hljs-operator">=</span> <span class="hljs-string">"fenix"</span>

:crypto.hash(:<span class="hljs-built_in">sha256</span>, value)
<span class="hljs-operator">|</span><span class="hljs-operator">></span> Base.encode16()
<span class="hljs-operator">|</span><span class="hljs-operator">></span> String.downcase()
</code></pre><pre data-type="codeBlock" text="&quot;b170f30d201da73b7637e94391f22a4642f8c396f9c1c9f8b2799919ced46d78&quot;
"><code><span class="hljs-string">"b170f30d201da73b7637e94391f22a4642f8c396f9c1c9f8b2799919ced46d78"</span>
</code></pre><p>The complete program is as follows:</p><pre data-type="codeBlock" text="defmodule Blockchain do
  defstruct chain: [], current_transactions: []

  def new_block(c, name) do
    b = %{
      :index =&gt; length(c.chain),
      :timestamp =&gt; NaiveDateTime.utc_now(),
      :name =&gt; name,
      :previous_hash =&gt; c |&gt; last_block() |&gt; hash(),
      :current_transactions =&gt; c.current_transactions
    }

    %{c | chain: c.chain ++ [b], current_transactions: []}
  end

  def zero() do
    b = %{
      :index =&gt; 0,
      :timestamp =&gt; NaiveDateTime.utc_now(),
      :name =&gt; &quot;ZERO&quot;,
      :previous_hash =&gt; &quot;&quot;,
      :current_transactions =&gt; []
    }

    %Blockchain{
      chain: [b],
      current_transactions: []
    }
  end

  def last_block(c) do
    c.chain |&gt; Enum.reverse() |&gt; hd()
  end

  def hash(block) do
    value = block |&gt; Poison.encode!()

    :crypto.hash(:sha256, value)
    |&gt; Base.encode16()
    |&gt; String.downcase()
  end
end
"><code>defmodule Blockchain do
  defstruct chain: [], current_transactions: []

  def new_block(c, name) do
    b <span class="hljs-operator">=</span> <span class="hljs-operator">%</span>{
      :index <span class="hljs-operator">=</span><span class="hljs-operator">></span> length(c.chain),
      :timestamp <span class="hljs-operator">=</span><span class="hljs-operator">></span> NaiveDateTime.utc_now(),
      :name <span class="hljs-operator">=</span><span class="hljs-operator">></span> name,
      :previous_hash <span class="hljs-operator">=</span><span class="hljs-operator">></span> c <span class="hljs-operator">|</span><span class="hljs-operator">></span> last_block() <span class="hljs-operator">|</span><span class="hljs-operator">></span> hash(),
      :current_transactions <span class="hljs-operator">=</span><span class="hljs-operator">></span> c.current_transactions
    }

    <span class="hljs-operator">%</span>{c <span class="hljs-operator">|</span> chain: c.chain <span class="hljs-operator">+</span><span class="hljs-operator">+</span> [b], current_transactions: []}
  end

  def zero() do
    b <span class="hljs-operator">=</span> <span class="hljs-operator">%</span>{
      :index <span class="hljs-operator">=</span><span class="hljs-operator">></span> <span class="hljs-number">0</span>,
      :timestamp <span class="hljs-operator">=</span><span class="hljs-operator">></span> NaiveDateTime.utc_now(),
      :name <span class="hljs-operator">=</span><span class="hljs-operator">></span> <span class="hljs-string">"ZERO"</span>,
      :previous_hash <span class="hljs-operator">=</span><span class="hljs-operator">></span> <span class="hljs-string">""</span>,
      :current_transactions <span class="hljs-operator">=</span><span class="hljs-operator">></span> []
    }

    <span class="hljs-operator">%</span>Blockchain{
      chain: [b],
      current_transactions: []
    }
  end

  def last_block(c) do
    c.chain <span class="hljs-operator">|</span><span class="hljs-operator">></span> Enum.reverse() <span class="hljs-operator">|</span><span class="hljs-operator">></span> hd()
  end

  def hash(<span class="hljs-built_in">block</span>) do
    value <span class="hljs-operator">=</span> <span class="hljs-built_in">block</span> <span class="hljs-operator">|</span><span class="hljs-operator">></span> Poison.encode!()

    :crypto.hash(:<span class="hljs-built_in">sha256</span>, value)
    <span class="hljs-operator">|</span><span class="hljs-operator">></span> Base.encode16()
    <span class="hljs-operator">|</span><span class="hljs-operator">></span> String.downcase()
  end
end
</code></pre><pre data-type="codeBlock" text="{:module, Blockchain, &lt;&lt;70, 79, 82, 49, 0, 0, 14, ...&gt;&gt;, {:hash, 1}}
"><code>{:module, Blockchain, <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">&#x3C;</span><span class="hljs-number">70</span>, <span class="hljs-number">79</span>, <span class="hljs-number">82</span>, <span class="hljs-number">49</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">14</span>, ...><span class="hljs-operator">></span>, {:hash, <span class="hljs-number">1</span>}}
</code></pre><h3 id="h-33-try-and-generate-genesis-block" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">3.3 Try and Generate Genesis Block</h3><p>Genesis Block</p><pre data-type="codeBlock" text="zero = Blockchain.zero()
"><code>zero <span class="hljs-operator">=</span> Blockchain.zero()
</code></pre><pre data-type="codeBlock" text="%Blockchain{
  chain: [
    %{
      current_transactions: [],
      index: 0,
      name: &quot;ZERO&quot;,
      previous_hash: &quot;&quot;,
      timestamp: ~N[2022-04-01 12:17:21.126190]
    }
  ],
  current_transactions: []
}
"><code><span class="hljs-string">%Blockchain{</span>
  <span class="hljs-attr">chain:</span> [
    <span class="hljs-string">%</span>{
      <span class="hljs-attr">current_transactions:</span> [],
      <span class="hljs-attr">index:</span> <span class="hljs-number">0</span>,
      <span class="hljs-attr">name:</span> <span class="hljs-string">"ZERO"</span>,
      <span class="hljs-attr">previous_hash:</span> <span class="hljs-string">""</span>,
      <span class="hljs-attr">timestamp:</span> <span class="hljs-string">~N</span>[<span class="hljs-number">2022-04-01 12:17:21.126190</span>]
    }
  ]<span class="hljs-string">,</span>
  <span class="hljs-attr">current_transactions:</span> []
<span class="hljs-string">}</span>
</code></pre><p>Create more blocks</p><pre data-type="codeBlock" text="zero
|&gt; Blockchain.new_block(&quot;first&quot;)
|&gt; Blockchain.new_block(&quot;second&quot;)
|&gt; Blockchain.new_block(&quot;third&quot;)
"><code>zero
<span class="hljs-operator">|</span><span class="hljs-operator">></span> Blockchain.new_block(<span class="hljs-string">"first"</span>)
<span class="hljs-operator">|</span><span class="hljs-operator">></span> Blockchain.new_block(<span class="hljs-string">"second"</span>)
<span class="hljs-operator">|</span><span class="hljs-operator">></span> Blockchain.new_block(<span class="hljs-string">"third"</span>)
</code></pre><pre data-type="codeBlock" text="%Blockchain{
  chain: [
    %{
      current_transactions: [],
      index: 0,
      name: &quot;ZERO&quot;,
      previous_hash: &quot;&quot;,
      timestamp: ~N[2022-04-01 12:17:21.126190]
    },
    %{
      current_transactions: [],
      index: 1,
      name: &quot;first&quot;,
      previous_hash: &quot;dd9a0b7a81ba060c2d1cd7e581ad0bda35c7019831049b39dbcc1c35a8f3f131&quot;,
      timestamp: ~N[2022-04-01 12:17:35.067392]
    },
    %{
      current_transactions: [],
      index: 2,
      name: &quot;second&quot;,
      previous_hash: &quot;f93e075bef13d86514a77d407e36ac9d3b2636769bfe483a3ecc4a2afd5b88ac&quot;,
      timestamp: ~N[2022-04-01 12:17:35.067467]
    },
    %{
      current_transactions: [],
      index: 3,
      name: &quot;third&quot;,
      previous_hash: &quot;0ac2d3ec623b955ef6781ff130f6aa8f65b1dd1022f9c7f6a60d40ee03ed3c8a&quot;,
      timestamp: ~N[2022-04-01 12:17:35.067551]
    }
  ],
  current_transactions: []
}
"><code><span class="hljs-string">%Blockchain{</span>
  <span class="hljs-attr">chain:</span> [
    <span class="hljs-string">%</span>{
      <span class="hljs-attr">current_transactions:</span> [],
      <span class="hljs-attr">index:</span> <span class="hljs-number">0</span>,
      <span class="hljs-attr">name:</span> <span class="hljs-string">"ZERO"</span>,
      <span class="hljs-attr">previous_hash:</span> <span class="hljs-string">""</span>,
      <span class="hljs-attr">timestamp:</span> <span class="hljs-string">~N</span>[<span class="hljs-number">2022-04-01 12:17:21.126190</span>]
    },
    <span class="hljs-string">%</span>{
      <span class="hljs-attr">current_transactions:</span> [],
      <span class="hljs-attr">index:</span> <span class="hljs-number">1</span>,
      <span class="hljs-attr">name:</span> <span class="hljs-string">"first"</span>,
      <span class="hljs-attr">previous_hash:</span> <span class="hljs-string">"dd9a0b7a81ba060c2d1cd7e581ad0bda35c7019831049b39dbcc1c35a8f3f131"</span>,
      <span class="hljs-attr">timestamp:</span> <span class="hljs-string">~N</span>[<span class="hljs-number">2022-04-01 12:17:35.067392</span>]
    },
    <span class="hljs-string">%</span>{
      <span class="hljs-attr">current_transactions:</span> [],
      <span class="hljs-attr">index:</span> <span class="hljs-number">2</span>,
      <span class="hljs-attr">name:</span> <span class="hljs-string">"second"</span>,
      <span class="hljs-attr">previous_hash:</span> <span class="hljs-string">"f93e075bef13d86514a77d407e36ac9d3b2636769bfe483a3ecc4a2afd5b88ac"</span>,
      <span class="hljs-attr">timestamp:</span> <span class="hljs-string">~N</span>[<span class="hljs-number">2022-04-01 12:17:35.067467</span>]
    },
    <span class="hljs-string">%</span>{
      <span class="hljs-attr">current_transactions:</span> [],
      <span class="hljs-attr">index:</span> <span class="hljs-number">3</span>,
      <span class="hljs-attr">name:</span> <span class="hljs-string">"third"</span>,
      <span class="hljs-attr">previous_hash:</span> <span class="hljs-string">"0ac2d3ec623b955ef6781ff130f6aa8f65b1dd1022f9c7f6a60d40ee03ed3c8a"</span>,
      <span class="hljs-attr">timestamp:</span> <span class="hljs-string">~N</span>[<span class="hljs-number">2022-04-01 12:17:35.067551</span>]
    }
  ]<span class="hljs-string">,</span>
  <span class="hljs-attr">current_transactions:</span> []
<span class="hljs-string">}</span>
</code></pre><h2 id="h-0x04-realization-of-transactions" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x04 Realization of Transactions</h2><p>The word &apos;transaction&apos; in blockchain is confusing and seems to represent a conversion that necessarily involves money.</p><p>In reality, we should abstract transactions to the following abstract model:</p><pre data-type="codeBlock" text="{
    from: from_addr,
    to: to_addr,
    amount: amount, # Only for public blockchains
    gas: gas, # transaction service fee
    op: operation # Operations done with the transaction
}
"><code>{
    <span class="hljs-attr">from:</span> <span class="hljs-string">from_addr</span>,
    <span class="hljs-attr">to:</span> <span class="hljs-string">to_addr</span>,
    <span class="hljs-attr">amount:</span> <span class="hljs-string">amount</span>, <span class="hljs-comment"># Only for public blockchains</span>
    <span class="hljs-attr">gas:</span> <span class="hljs-string">gas</span>, <span class="hljs-comment"># transaction service fee</span>
    <span class="hljs-attr">op:</span> <span class="hljs-string">operation</span> <span class="hljs-comment"># Operations done with the transaction</span>
}
</code></pre><p>In a public blockchain, each transaction will contain an amount (the amount may be 0) and gas. Some transactions are simply user-to-user transfers, and some transactions are keyed to operation. In this case, to is usually a contract address, and operation tells the &quot;blockchain computer&quot; what to do - for example, to store a value in the blockchain database, or to perform some computation on the blockchain - and we think of the blockchain as a &quot;distributed computer&quot;.</p><p>In federated chains, the concept of amount is deprecated, and there are no more transactions for native token transfers (note that smart contract-based tokens like ERC20 are supported, though they are often referred to as credits). However, gas still exists and is used to measure the consumption of computational resources.</p><p>The format of a transaction in Elixir can be abstracted as follows:</p><pre data-type="codeBlock" text="%{
  :sender =&gt; sender,
  :recipient =&gt; recipient,
  :amount =&gt; amount
}
"><code><span class="hljs-operator">%</span>{
  :sender <span class="hljs-operator">=</span><span class="hljs-operator">></span> sender,
  :recipient <span class="hljs-operator">=</span><span class="hljs-operator">></span> recipient,
  :amount <span class="hljs-operator">=</span><span class="hljs-operator">></span> amount
}
</code></pre><p>Completes the new_transaction function:</p><pre data-type="codeBlock" text="def new_transaction(c, sender, recipient, amount) do
    tx = %{
      :sender =&gt; sender,
      :recipient =&gt; recipient,
      :amount =&gt; amount
    }

    %Blockchain{c | current_transactions: c.current_transactions ++ [tx]}
end
"><code>def new_transaction(c, sender, recipient, amount) do
    <span class="hljs-built_in">tx</span> <span class="hljs-operator">=</span> <span class="hljs-operator">%</span>{
      :sender <span class="hljs-operator">=</span><span class="hljs-operator">></span> sender,
      :recipient <span class="hljs-operator">=</span><span class="hljs-operator">></span> recipient,
      :amount <span class="hljs-operator">=</span><span class="hljs-operator">></span> amount
    }

    <span class="hljs-operator">%</span>Blockchain{c <span class="hljs-operator">|</span> current_transactions: c.current_transactions <span class="hljs-operator">+</span><span class="hljs-operator">+</span> [<span class="hljs-built_in">tx</span>]}
end
</code></pre><p>The complete code for our transactions is as follows:</p><pre data-type="codeBlock" text="defmodule Blockchain do
  defstruct chain: [], current_transactions: []

  def new_block(c, name) do
    b = %{
      :index =&gt; length(c.chain),
      :timestamp =&gt; NaiveDateTime.utc_now(),
      :name =&gt; name,
      :previous_hash =&gt; c |&gt; last_block() |&gt; hash(),
      :current_transactions =&gt; c.current_transactions
    }

    %{c | chain: c.chain ++ [b], current_transactions: []}
  end

  def zero() do
    b = %{
      :index =&gt; 0,
      :timestamp =&gt; NaiveDateTime.utc_now(),
      :name =&gt; &quot;ZERO&quot;,
      :previous_hash =&gt; &quot;&quot;,
      :current_transactions =&gt; []
    }

    %Blockchain{
      chain: [b],
      current_transactions: []
    }
  end

  def new_transaction(c, sender, recipient, amount) do
    tx = %{
      :sender =&gt; sender,
      :recipient =&gt; recipient,
      :amount =&gt; amount
    }

    %Blockchain{c | current_transactions: c.current_transactions ++ [tx]}
  end

  def last_block(c) do
    c.chain |&gt; Enum.reverse() |&gt; hd()
  end

  def hash(block) do
    value = block |&gt; Poison.encode!()

    :crypto.hash(:sha256, value)
    |&gt; Base.encode16()
    |&gt; String.downcase()
  end
end
"><code>defmodule Blockchain do
  defstruct chain: [], current_transactions: []

  def new_block(c, name) do
    b <span class="hljs-operator">=</span> <span class="hljs-operator">%</span>{
      :index <span class="hljs-operator">=</span><span class="hljs-operator">></span> length(c.chain),
      :timestamp <span class="hljs-operator">=</span><span class="hljs-operator">></span> NaiveDateTime.utc_now(),
      :name <span class="hljs-operator">=</span><span class="hljs-operator">></span> name,
      :previous_hash <span class="hljs-operator">=</span><span class="hljs-operator">></span> c <span class="hljs-operator">|</span><span class="hljs-operator">></span> last_block() <span class="hljs-operator">|</span><span class="hljs-operator">></span> hash(),
      :current_transactions <span class="hljs-operator">=</span><span class="hljs-operator">></span> c.current_transactions
    }

    <span class="hljs-operator">%</span>{c <span class="hljs-operator">|</span> chain: c.chain <span class="hljs-operator">+</span><span class="hljs-operator">+</span> [b], current_transactions: []}
  end

  def zero() do
    b <span class="hljs-operator">=</span> <span class="hljs-operator">%</span>{
      :index <span class="hljs-operator">=</span><span class="hljs-operator">></span> <span class="hljs-number">0</span>,
      :timestamp <span class="hljs-operator">=</span><span class="hljs-operator">></span> NaiveDateTime.utc_now(),
      :name <span class="hljs-operator">=</span><span class="hljs-operator">></span> <span class="hljs-string">"ZERO"</span>,
      :previous_hash <span class="hljs-operator">=</span><span class="hljs-operator">></span> <span class="hljs-string">""</span>,
      :current_transactions <span class="hljs-operator">=</span><span class="hljs-operator">></span> []
    }

    <span class="hljs-operator">%</span>Blockchain{
      chain: [b],
      current_transactions: []
    }
  end

  def new_transaction(c, sender, recipient, amount) do
    <span class="hljs-built_in">tx</span> <span class="hljs-operator">=</span> <span class="hljs-operator">%</span>{
      :sender <span class="hljs-operator">=</span><span class="hljs-operator">></span> sender,
      :recipient <span class="hljs-operator">=</span><span class="hljs-operator">></span> recipient,
      :amount <span class="hljs-operator">=</span><span class="hljs-operator">></span> amount
    }

    <span class="hljs-operator">%</span>Blockchain{c <span class="hljs-operator">|</span> current_transactions: c.current_transactions <span class="hljs-operator">+</span><span class="hljs-operator">+</span> [<span class="hljs-built_in">tx</span>]}
  end

  def last_block(c) do
    c.chain <span class="hljs-operator">|</span><span class="hljs-operator">></span> Enum.reverse() <span class="hljs-operator">|</span><span class="hljs-operator">></span> hd()
  end

  def hash(<span class="hljs-built_in">block</span>) do
    value <span class="hljs-operator">=</span> <span class="hljs-built_in">block</span> <span class="hljs-operator">|</span><span class="hljs-operator">></span> Poison.encode!()

    :crypto.hash(:<span class="hljs-built_in">sha256</span>, value)
    <span class="hljs-operator">|</span><span class="hljs-operator">></span> Base.encode16()
    <span class="hljs-operator">|</span><span class="hljs-operator">></span> String.downcase()
  end
end
</code></pre><pre data-type="codeBlock" text="{:module, Blockchain, &lt;&lt;70, 79, 82, 49, 0, 0, 16, ...&gt;&gt;, {:hash, 1}}
"><code>{:module, Blockchain, <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">&#x3C;</span><span class="hljs-number">70</span>, <span class="hljs-number">79</span>, <span class="hljs-number">82</span>, <span class="hljs-number">49</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">16</span>, ...><span class="hljs-operator">></span>, {:hash, <span class="hljs-number">1</span>}}
</code></pre><h3 id="h-41-try-and-create-transaction" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">4.1 Try and create transaction</h3><p>Genesis block</p><pre data-type="codeBlock" text="zero = Blockchain.zero()
"><code>zero <span class="hljs-operator">=</span> Blockchain.zero()
</code></pre><pre data-type="codeBlock" text="%Blockchain{
  chain: [
    %{
      current_transactions: [],
      index: 0,
      name: &quot;ZERO&quot;,
      previous_hash: &quot;&quot;,
      timestamp: ~N[2022-04-01 12:20:26.788775]
    }
  ],
  current_transactions: []
}
"><code><span class="hljs-string">%Blockchain{</span>
  <span class="hljs-attr">chain:</span> [
    <span class="hljs-string">%</span>{
      <span class="hljs-attr">current_transactions:</span> [],
      <span class="hljs-attr">index:</span> <span class="hljs-number">0</span>,
      <span class="hljs-attr">name:</span> <span class="hljs-string">"ZERO"</span>,
      <span class="hljs-attr">previous_hash:</span> <span class="hljs-string">""</span>,
      <span class="hljs-attr">timestamp:</span> <span class="hljs-string">~N</span>[<span class="hljs-number">2022-04-01 12:20:26.788775</span>]
    }
  ]<span class="hljs-string">,</span>
  <span class="hljs-attr">current_transactions:</span> []
<span class="hljs-string">}</span>
</code></pre><p>Execute a few transactions and pack into a new block</p><pre data-type="codeBlock" text="zero
|&gt; Blockchain.new_transaction(&quot;alice&quot;, &quot;bob&quot;, 100)
|&gt; Blockchain.new_transaction(&quot;alice&quot;, &quot;bob&quot;, 20)
|&gt; Blockchain.new_block(&quot;first&quot;)
"><code>zero
<span class="hljs-operator">|</span><span class="hljs-operator">></span> Blockchain.new_transaction(<span class="hljs-string">"alice"</span>, <span class="hljs-string">"bob"</span>, <span class="hljs-number">100</span>)
<span class="hljs-operator">|</span><span class="hljs-operator">></span> Blockchain.new_transaction(<span class="hljs-string">"alice"</span>, <span class="hljs-string">"bob"</span>, <span class="hljs-number">20</span>)
<span class="hljs-operator">|</span><span class="hljs-operator">></span> Blockchain.new_block(<span class="hljs-string">"first"</span>)
</code></pre><pre data-type="codeBlock" text="%Blockchain{
  chain: [
    %{
      current_transactions: [],
      index: 0,
      name: &quot;ZERO&quot;,
      previous_hash: &quot;&quot;,
      timestamp: ~N[2022-04-01 12:20:26.788775]
    },
    %{
      current_transactions: [
        %{amount: 100, recipient: &quot;bob&quot;, sender: &quot;alice&quot;},
        %{amount: 20, recipient: &quot;bob&quot;, sender: &quot;alice&quot;}
      ],
      index: 1,
      name: &quot;first&quot;,
      previous_hash: &quot;56881bced4dd4b52f76cc75e0b7f217fe4696e3e15974d4c174d84fb4205b92a&quot;,
      timestamp: ~N[2022-04-01 12:20:39.174474]
    }
  ],
  current_transactions: []
}
"><code><span class="hljs-string">%Blockchain{</span>
  <span class="hljs-attr">chain:</span> [
    <span class="hljs-string">%</span>{
      <span class="hljs-attr">current_transactions:</span> [],
      <span class="hljs-attr">index:</span> <span class="hljs-number">0</span>,
      <span class="hljs-attr">name:</span> <span class="hljs-string">"ZERO"</span>,
      <span class="hljs-attr">previous_hash:</span> <span class="hljs-string">""</span>,
      <span class="hljs-attr">timestamp:</span> <span class="hljs-string">~N</span>[<span class="hljs-number">2022-04-01 12:20:26.788775</span>]
    },
    <span class="hljs-string">%</span>{
      <span class="hljs-attr">current_transactions:</span> [
        <span class="hljs-string">%</span>{<span class="hljs-attr">amount:</span> <span class="hljs-number">100</span>, <span class="hljs-attr">recipient:</span> <span class="hljs-string">"bob"</span>, <span class="hljs-attr">sender:</span> <span class="hljs-string">"alice"</span>},
        <span class="hljs-string">%</span>{<span class="hljs-attr">amount:</span> <span class="hljs-number">20</span>, <span class="hljs-attr">recipient:</span> <span class="hljs-string">"bob"</span>, <span class="hljs-attr">sender:</span> <span class="hljs-string">"alice"</span>}
      ],
      <span class="hljs-attr">index:</span> <span class="hljs-number">1</span>,
      <span class="hljs-attr">name:</span> <span class="hljs-string">"first"</span>,
      <span class="hljs-attr">previous_hash:</span> <span class="hljs-string">"56881bced4dd4b52f76cc75e0b7f217fe4696e3e15974d4c174d84fb4205b92a"</span>,
      <span class="hljs-attr">timestamp:</span> <span class="hljs-string">~N</span>[<span class="hljs-number">2022-04-01 12:20:39.174474</span>]
    }
  ]<span class="hljs-string">,</span>
  <span class="hljs-attr">current_transactions:</span> []
<span class="hljs-string">}</span>
</code></pre><p>The transaction now is in the first block.</p><h2 id="h-0x05-proof-of-work-pow" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x05 Proof of Work (PoW)</h2><p>The concept was widely spread because Bitcoin adopted the PoW consensus mechanism. The full name of PoW is Proof of Work. The PoW consensus mechanism is actually a design idea rather than a specific implementation.</p><p>The PoW mechanism was first proposed as early as 1997, and it was mostly used in the scenario of resisting abuse of software services in the early days such asanti-spam (that&apos;s why PoW is involved in the mail service system).</p><p>We&apos;ll use a Wikipedia diagram to explain how the PoW mechanism is used in this scenario.</p><p>In order to prevent the spread of spam messages, the receiver does not directly accept the message from any sender. Therefore, in a valid conversation, the sender needs to calculate an answer to the problem according to the rules, and send it to the receiver at the same time. The answer needs to be verified with it. If the answer is verified as valid, then the recipient will accept the message.</p><p>!Unsupported embed</p><p>可以看出 PoW 的核心设计思路是提出一个计算难题，但是这个难题答案的验证过程是非常容易的，这种特性我们称之为计算不对称特性</p><h3 id="h-51-how-to-understand-pow-in-blockchain" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">5.1 How to understand PoW in blockchain</h3><p>As an example, let&apos;s say we are given a string &quot;Fenix&quot; and the problem we pose is, to compute a number, concatenated with the given string, so that the first 4 bits of the SHA256 result of this string are 0. We call this number nonce, such as the string &quot;Fenix1234&quot;, nonce is 1234 and we want to find the nonce that meets the criteria.</p><p>An Example in Python</p><pre data-type="codeBlock" text="#!/usr/bin/env python
import hashlib

def main():
    base_string = &quot;Fenix&quot;
    nonce = 10000
    count = 0
    while True:
        target_string = base_string + str(nonce)
        pow_hash = hashlib.sha256(target_string).hexdigest()
        count = count + 1
        if pow_hash.startswith(&quot;0000&quot;):
            print pow_hash
            print &quot;nonce: %s  scan times: %s&quot; % (nonce, count)
            break
        nonce = nonce + 1

if __name__ == &apos;__main__&apos;:
    main()
"><code>#<span class="hljs-operator">!</span><span class="hljs-operator">/</span>usr<span class="hljs-operator">/</span>bin<span class="hljs-operator">/</span>env python
<span class="hljs-keyword">import</span> <span class="hljs-title">hashlib</span>

<span class="hljs-title">def</span> <span class="hljs-title">main</span>():
    <span class="hljs-title">base_string</span> <span class="hljs-operator">=</span> <span class="hljs-string">"Fenix"</span>
    <span class="hljs-title">nonce</span> <span class="hljs-operator">=</span> 10000
    <span class="hljs-title">count</span> <span class="hljs-operator">=</span> 0
    <span class="hljs-title"><span class="hljs-keyword">while</span></span> <span class="hljs-title">True</span>:
        <span class="hljs-title">target_string</span> <span class="hljs-operator">=</span> <span class="hljs-title">base_string</span> <span class="hljs-operator">+</span> <span class="hljs-title">str</span>(<span class="hljs-title">nonce</span>)
        <span class="hljs-title">pow_hash</span> <span class="hljs-operator">=</span> <span class="hljs-title">hashlib</span>.<span class="hljs-title"><span class="hljs-built_in">sha256</span></span>(<span class="hljs-title">target_string</span>).<span class="hljs-title">hexdigest</span>()
        <span class="hljs-title">count</span> <span class="hljs-operator">=</span> <span class="hljs-title">count</span> <span class="hljs-operator">+</span> 1
        <span class="hljs-title"><span class="hljs-keyword">if</span></span> <span class="hljs-title">pow_hash</span>.<span class="hljs-title">startswith</span>(<span class="hljs-string">"0000"</span>):
            <span class="hljs-title">print</span> <span class="hljs-title">pow_hash</span>
            <span class="hljs-title">print</span> <span class="hljs-string">"nonce: %s  scan times: %s"</span> <span class="hljs-operator">%</span> (<span class="hljs-title">nonce</span>, <span class="hljs-title">count</span>)
            <span class="hljs-title"><span class="hljs-keyword">break</span></span>
        <span class="hljs-title">nonce</span> <span class="hljs-operator">=</span> <span class="hljs-title">nonce</span> <span class="hljs-operator">+</span> 1

<span class="hljs-title"><span class="hljs-keyword">if</span></span> <span class="hljs-title">__name__</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-string">'__main__'</span>:
    <span class="hljs-title">main</span>()
</code></pre><p>The base string is specified as &quot;Fenix&quot;, and the nonce starts to search up from 10000, until a matching nonce value is found.</p><pre data-type="codeBlock" text="# The first 4 digits are 0000
0000250248f805c558bc28864a6bb6bf0c244d836a6b1a0c5078987aa219a404
nonce: 68828  scan times: 58829
# The first 5 digits are 00000
0000067fc247325064f685c32f8a079584b19106c5228b533f10c775638d454c
nonce: 1241205  scan times: 1231206
The first 7 digits are 0000000
00000003f41b126ec689b1a2da9e7d46d13d0fd1bece47983d53c5d32eb4ac90
nonce: 165744821  scan times: 165734822
"><code># The <span class="hljs-keyword">first</span> <span class="hljs-number">4</span> digits <span class="hljs-keyword">are</span> <span class="hljs-number">0000</span>
<span class="hljs-number">0000250248</span>f805c558bc28864a6bb6bf0c244d836a6b1a0c5078987aa219a404
nonce: <span class="hljs-number">68828</span>  scan times: <span class="hljs-number">58829</span>
# The <span class="hljs-keyword">first</span> <span class="hljs-number">5</span> digits <span class="hljs-keyword">are</span> <span class="hljs-number">00000</span>
<span class="hljs-number">0000067</span>fc247325064f685c32f8a079584b19106c5228b533f10c775638d454c
nonce: <span class="hljs-number">1241205</span>  scan times: <span class="hljs-number">1231206</span>
The <span class="hljs-keyword">first</span> <span class="hljs-number">7</span> digits <span class="hljs-keyword">are</span> <span class="hljs-number">0000000</span>
<span class="hljs-number">00000003</span>f41b126ec689b1a2da9e7d46d13d0fd1bece47983d53c5d32eb4ac90
nonce: <span class="hljs-number">165744821</span>  scan times: <span class="hljs-number">165734822</span>
</code></pre><p>Each time the first N bits of the hash result are required to have one more 0, the number of calculations is many times more. When the first 7 bits are required to be 0, the number of computations reaches 160 million.</p><blockquote><p>Reference: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://time.geekbang.org/column/article/5963">《深入浅出区块链》</a></p></blockquote><h3 id="h-52-other-languages" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">5.2 Other languages</h3><h4 id="h-521-go" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">5.2.1 Go</h4><pre data-type="codeBlock" text="package main

import (
    &quot;crypto/sha256&quot;
    &quot;encoding/hex&quot;
    &quot;fmt&quot;
    &quot;strconv&quot;
    &quot;strings&quot;
)

func main() {
    pow(&quot;0000&quot;)
}

func pow(diff string) {
    baseStr := &quot;fenix&quot;
    nonce := 0
    count := 0
    for {
        targetStr := baseStr + strconv.Itoa(nonce)
        h := sha256.New()
        h.Write([]byte(targetStr))
        powHash := hex.EncodeToString(h.Sum(nil))
        fmt.Printf(&quot;\r%s&quot;, powHash)
        count += 1
        if strings.HasPrefix(string(powHash), diff) {
            fmt.Println()
            fmt.Println(&quot;nonce: &quot;, nonce, &quot;scan times: &quot;, count)
            break
        }
        nonce += 1
    }
}
"><code><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"crypto/sha256"</span>
    <span class="hljs-string">"encoding/hex"</span>
    <span class="hljs-string">"fmt"</span>
    <span class="hljs-string">"strconv"</span>
    <span class="hljs-string">"strings"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    pow(<span class="hljs-string">"0000"</span>)
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">pow</span><span class="hljs-params">(diff <span class="hljs-type">string</span>)</span></span> {
    baseStr := <span class="hljs-string">"fenix"</span>
    nonce := <span class="hljs-number">0</span>
    count := <span class="hljs-number">0</span>
    <span class="hljs-keyword">for</span> {
        targetStr := baseStr + strconv.Itoa(nonce)
        h := sha256.New()
        h.Write([]<span class="hljs-type">byte</span>(targetStr))
        powHash := hex.EncodeToString(h.Sum(<span class="hljs-literal">nil</span>))
        fmt.Printf(<span class="hljs-string">"\r%s"</span>, powHash)
        count += <span class="hljs-number">1</span>
        <span class="hljs-keyword">if</span> strings.HasPrefix(<span class="hljs-type">string</span>(powHash), diff) {
            fmt.Println()
            fmt.Println(<span class="hljs-string">"nonce: "</span>, nonce, <span class="hljs-string">"scan times: "</span>, count)
            <span class="hljs-keyword">break</span>
        }
        nonce += <span class="hljs-number">1</span>
    }
}
</code></pre><h4 id="h-522-rust" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">5.2.2 Rust</h4><pre data-type="codeBlock" text="use sha256::digest;

fn main() {
    pow(String::from(&quot;0000&quot;));
}

fn pow(diff: String) {
    println!(&quot;{}&quot;, diff);
    let mut count = 0;
    let mut nonce = 0;
    let base_str = String::from(&quot;fenix&quot;);
    loop {
        count += 1;
        let target_str = base_str.clone() + &amp;nonce.to_string();
        let pow_hash = digest(target_str);
        print!(&quot;\r{}&quot;, pow_hash);
        if pow_hash.starts_with(&amp;diff) {
            println!(&quot;&quot;);
            println!(&quot;nonce: {}, scan times: {}&quot;, nonce, count);
            break;
        }
        nonce += 1;
    }
}
"><code>use <span class="hljs-built_in">sha256</span>::digest;

fn main() {
    pow(String::<span class="hljs-keyword">from</span>(<span class="hljs-string">"0000"</span>));
}

fn pow(diff: String) {
    println<span class="hljs-operator">!</span>(<span class="hljs-string">"{}"</span>, diff);
    let mut count <span class="hljs-operator">=</span> <span class="hljs-number">0</span>;
    let mut nonce <span class="hljs-operator">=</span> <span class="hljs-number">0</span>;
    let base_str <span class="hljs-operator">=</span> String::<span class="hljs-keyword">from</span>(<span class="hljs-string">"fenix"</span>);
    loop {
        count <span class="hljs-operator">+</span><span class="hljs-operator">=</span> <span class="hljs-number">1</span>;
        let target_str <span class="hljs-operator">=</span> base_str.clone() <span class="hljs-operator">+</span> <span class="hljs-operator">&#x26;</span>nonce.to_string();
        let pow_hash <span class="hljs-operator">=</span> digest(target_str);
        print<span class="hljs-operator">!</span>(<span class="hljs-string">"\r{}"</span>, pow_hash);
        <span class="hljs-keyword">if</span> pow_hash.starts_with(<span class="hljs-operator">&#x26;</span>diff) {
            println<span class="hljs-operator">!</span>(<span class="hljs-string">""</span>);
            println<span class="hljs-operator">!</span>(<span class="hljs-string">"nonce: {}, scan times: {}"</span>, nonce, count);
            <span class="hljs-keyword">break</span>;
        }
        nonce <span class="hljs-operator">+</span><span class="hljs-operator">=</span> <span class="hljs-number">1</span>;
    }
}
</code></pre><p>When using mainstream programming languages ​​implement it, then tend to choose to use loop.</p><p>Elixir&apos;s variables are immutable, so conventional looping methods are not possible. Therefore we may use recursion to implement as follows:</p><pre data-type="codeBlock" text="defmodule Pow do
  def work(value, nonce, count, difficulty) do
    if String.starts_with?(value, difficulty) do
      IO.puts(value)
      IO.puts(&quot;nonce: #{nonce}, scan times: #{count}&quot;)
    else
      digest(&quot;#{value}#{nonce}&quot;) |&gt; work(nonce + 1, count + 1, difficulty)
    end
  end

  def digest(value) do
    IO.write(&quot;\rhash: #{value}&quot;)

    :crypto.hash(:sha256, value)
    |&gt; Base.encode16()
    |&gt; String.downcase()
  end
end
"><code>defmodule Pow do
  def work(value, nonce, count, difficulty) do
    <span class="hljs-keyword">if</span> String.starts_with?(value, difficulty) do
      IO.puts(value)
      IO.puts(<span class="hljs-string">"nonce: #{nonce}, scan times: #{count}"</span>)
    <span class="hljs-keyword">else</span>
      digest(<span class="hljs-string">"#{value}#{nonce}"</span>) <span class="hljs-operator">|</span><span class="hljs-operator">></span> work(nonce <span class="hljs-operator">+</span> <span class="hljs-number">1</span>, count <span class="hljs-operator">+</span> <span class="hljs-number">1</span>, difficulty)
    end
  end

  def digest(value) do
    IO.write(<span class="hljs-string">"\rhash: #{value}"</span>)

    :crypto.hash(:<span class="hljs-built_in">sha256</span>, value)
    <span class="hljs-operator">|</span><span class="hljs-operator">></span> Base.encode16()
    <span class="hljs-operator">|</span><span class="hljs-operator">></span> String.downcase()
  end
end
</code></pre><pre data-type="codeBlock" text="{:module, Pow, &lt;&lt;70, 79, 82, 49, 0, 0, 10, ...&gt;&gt;, {:digest, 1}}
"><code>{:module, Pow, <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">&#x3C;</span><span class="hljs-number">70</span>, <span class="hljs-number">79</span>, <span class="hljs-number">82</span>, <span class="hljs-number">49</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">10</span>, ...><span class="hljs-operator">></span>, {:digest, <span class="hljs-number">1</span>}}
</code></pre><pre data-type="codeBlock" text="Pow.work(&quot;Fenix&quot;, 0, 0, &quot;0000&quot;)
Pow.work(&quot;Fenix&quot;, 0, 0, &quot;00000&quot;)
"><code>Pow.work(<span class="hljs-string">"Fenix"</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-string">"0000"</span>)
Pow.work(<span class="hljs-string">"Fenix"</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-string">"00000"</span>)
</code></pre><pre data-type="codeBlock" text="hash: a9d1ee2ad4586af4acc3b3dbd97d85355fbd4f8634a2062b38f4f878d350eb7e1770240000303ab87561a134d5ba70ff0dc96f59df2cb2c76a12418363a7065d7021e5
nonce: 177025, scan times: 177025
hash: 78ba29b80a1a9a0dbd363f00119a1822aad18cf999b93b732ff6fe7c42d4ee6b1468816000002fc5a2268fc4e118f4a221e1e76991c3f9a20d683f489e8466e26fcde54
nonce: 1468817, scan times: 1468817
"><code><span class="hljs-attr">hash:</span> <span class="hljs-string">a9d1ee2ad4586af4acc3b3dbd97d85355fbd4f8634a2062b38f4f878d350eb7e1770240000303ab87561a134d5ba70ff0dc96f59df2cb2c76a12418363a7065d7021e5</span>
<span class="hljs-attr">nonce:</span> <span class="hljs-number">177025</span><span class="hljs-string">,</span> <span class="hljs-attr">scan times:</span> <span class="hljs-number">177025</span>
<span class="hljs-attr">hash:</span> <span class="hljs-string">78ba29b80a1a9a0dbd363f00119a1822aad18cf999b93b732ff6fe7c42d4ee6b1468816000002fc5a2268fc4e118f4a221e1e76991c3f9a20d683f489e8466e26fcde54</span>
<span class="hljs-attr">nonce:</span> <span class="hljs-number">1468817</span><span class="hljs-string">,</span> <span class="hljs-attr">scan times:</span> <span class="hljs-number">1468817</span>
</code></pre><pre data-type="codeBlock" text=":ok
"><code><span class="hljs-symbol">:ok</span>
</code></pre><p>The higher the difficulty, the more calculations are required.</p><h2 id="h-0x06-final-state" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x06 Final State</h2><p>Now, we&apos;ll add proof-of-work to the blockchain. The complete program is as follows:</p><pre data-type="codeBlock" text="defmodule Blockchain do
  defstruct chain: [], current_transactions: [], last_nonce: 0

  def new_block(c, name, nonce) do
    if valid_proof?(c.last_nonce, nonce) do
      b = %{
        :index =&gt; length(c.chain),
        :timestamp =&gt; NaiveDateTime.utc_now(),
        :name =&gt; name,
        :previous_hash =&gt; c |&gt; last_block() |&gt; hash(),
        :current_transactions =&gt; c.current_transactions
      }

      %{c | chain: c.chain ++ [b], current_transactions: [], last_nonce: nonce}
    else
      IO.puts(&quot;\nnonce: #{nonce} is invalid&quot;)
    end
  end

  def zero() do
    b = %{
      :index =&gt; 0,
      :timestamp =&gt; NaiveDateTime.utc_now(),
      :name =&gt; &quot;ZERO&quot;,
      :previous_hash =&gt; &quot;&quot;,
      :current_transactions =&gt; []
    }

    %Blockchain{
      chain: [b],
      current_transactions: [],
      last_nonce: 0
    }
  end

  def new_transaction(c, sender, recipient, amount) do
    tx = %{
      :sender =&gt; sender,
      :recipient =&gt; recipient,
      :amount =&gt; amount
    }

    %Blockchain{c | current_transactions: c.current_transactions ++ [tx]}
  end

  def last_block(c) do
    c.chain |&gt; Enum.reverse() |&gt; hd()
  end

  def hash(block) do
    value = block |&gt; Poison.encode!()

    :crypto.hash(:sha256, value)
    |&gt; Base.encode16()
    |&gt; String.downcase()
  end

  def proof_of_work(last_nonce, nonce \\ 0) do
    case valid_proof?(last_nonce, nonce) do
      true -&gt;
        nonce

      _ -&gt;
        proof_of_work(last_nonce, nonce + 1)
    end
  end

  def valid_proof?(last_nonce, nonce, difficulty \\ &quot;0000&quot;) do
    guess = &quot;#{last_nonce}#{nonce}&quot;

    guess_hash =
      :crypto.hash(:sha256, guess)
      |&gt; Base.encode16()
      |&gt; String.downcase()

    IO.write(&quot;\rdifficulty: #{difficulty}, attempt: #{nonce}, hash: #{guess_hash}&quot;)
    guess_hash |&gt; String.starts_with?(difficulty)
  end
end
"><code>defmodule Blockchain do
  defstruct chain: [], current_transactions: [], last_nonce: <span class="hljs-number">0</span>

  def new_block(c, name, nonce) do
    <span class="hljs-keyword">if</span> valid_proof?(c.last_nonce, nonce) do
      b <span class="hljs-operator">=</span> <span class="hljs-operator">%</span>{
        :index <span class="hljs-operator">=</span><span class="hljs-operator">></span> length(c.chain),
        :timestamp <span class="hljs-operator">=</span><span class="hljs-operator">></span> NaiveDateTime.utc_now(),
        :name <span class="hljs-operator">=</span><span class="hljs-operator">></span> name,
        :previous_hash <span class="hljs-operator">=</span><span class="hljs-operator">></span> c <span class="hljs-operator">|</span><span class="hljs-operator">></span> last_block() <span class="hljs-operator">|</span><span class="hljs-operator">></span> hash(),
        :current_transactions <span class="hljs-operator">=</span><span class="hljs-operator">></span> c.current_transactions
      }

      <span class="hljs-operator">%</span>{c <span class="hljs-operator">|</span> chain: c.chain <span class="hljs-operator">+</span><span class="hljs-operator">+</span> [b], current_transactions: [], last_nonce: nonce}
    <span class="hljs-keyword">else</span>
      IO.puts(<span class="hljs-string">"\nnonce: #{nonce} is invalid"</span>)
    end
  end

  def zero() do
    b <span class="hljs-operator">=</span> <span class="hljs-operator">%</span>{
      :index <span class="hljs-operator">=</span><span class="hljs-operator">></span> <span class="hljs-number">0</span>,
      :timestamp <span class="hljs-operator">=</span><span class="hljs-operator">></span> NaiveDateTime.utc_now(),
      :name <span class="hljs-operator">=</span><span class="hljs-operator">></span> <span class="hljs-string">"ZERO"</span>,
      :previous_hash <span class="hljs-operator">=</span><span class="hljs-operator">></span> <span class="hljs-string">""</span>,
      :current_transactions <span class="hljs-operator">=</span><span class="hljs-operator">></span> []
    }

    <span class="hljs-operator">%</span>Blockchain{
      chain: [b],
      current_transactions: [],
      last_nonce: <span class="hljs-number">0</span>
    }
  end

  def new_transaction(c, sender, recipient, amount) do
    <span class="hljs-built_in">tx</span> <span class="hljs-operator">=</span> <span class="hljs-operator">%</span>{
      :sender <span class="hljs-operator">=</span><span class="hljs-operator">></span> sender,
      :recipient <span class="hljs-operator">=</span><span class="hljs-operator">></span> recipient,
      :amount <span class="hljs-operator">=</span><span class="hljs-operator">></span> amount
    }

    <span class="hljs-operator">%</span>Blockchain{c <span class="hljs-operator">|</span> current_transactions: c.current_transactions <span class="hljs-operator">+</span><span class="hljs-operator">+</span> [<span class="hljs-built_in">tx</span>]}
  end

  def last_block(c) do
    c.chain <span class="hljs-operator">|</span><span class="hljs-operator">></span> Enum.reverse() <span class="hljs-operator">|</span><span class="hljs-operator">></span> hd()
  end

  def hash(<span class="hljs-built_in">block</span>) do
    value <span class="hljs-operator">=</span> <span class="hljs-built_in">block</span> <span class="hljs-operator">|</span><span class="hljs-operator">></span> Poison.encode!()

    :crypto.hash(:<span class="hljs-built_in">sha256</span>, value)
    <span class="hljs-operator">|</span><span class="hljs-operator">></span> Base.encode16()
    <span class="hljs-operator">|</span><span class="hljs-operator">></span> String.downcase()
  end

  def proof_of_work(last_nonce, nonce \\ <span class="hljs-number">0</span>) do
    case valid_proof?(last_nonce, nonce) do
      <span class="hljs-literal">true</span> <span class="hljs-operator">-</span><span class="hljs-operator">></span>
        nonce

      <span class="hljs-keyword">_</span> <span class="hljs-operator">-</span><span class="hljs-operator">></span>
        proof_of_work(last_nonce, nonce <span class="hljs-operator">+</span> <span class="hljs-number">1</span>)
    end
  end

  def valid_proof?(last_nonce, nonce, difficulty \\ <span class="hljs-string">"0000"</span>) do
    guess <span class="hljs-operator">=</span> <span class="hljs-string">"#{last_nonce}#{nonce}"</span>

    guess_hash <span class="hljs-operator">=</span>
      :crypto.hash(:<span class="hljs-built_in">sha256</span>, guess)
      <span class="hljs-operator">|</span><span class="hljs-operator">></span> Base.encode16()
      <span class="hljs-operator">|</span><span class="hljs-operator">></span> String.downcase()

    IO.write(<span class="hljs-string">"\rdifficulty: #{difficulty}, attempt: #{nonce}, hash: #{guess_hash}"</span>)
    guess_hash <span class="hljs-operator">|</span><span class="hljs-operator">></span> String.starts_with?(difficulty)
  end
end
</code></pre><pre data-type="codeBlock" text="{:module, Blockchain, &lt;&lt;70, 79, 82, 49, 0, 0, 24, ...&gt;&gt;, {:valid_proof?, 3}}
"><code>{:module, Blockchain, <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">&#x3C;</span><span class="hljs-number">70</span>, <span class="hljs-number">79</span>, <span class="hljs-number">82</span>, <span class="hljs-number">49</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">24</span>, ...><span class="hljs-operator">></span>, {:valid_proof?, <span class="hljs-number">3</span>}}
</code></pre><p>Genesis Block</p><pre data-type="codeBlock" text="zero = Blockchain.zero()
"><code>zero <span class="hljs-operator">=</span> Blockchain.zero()
</code></pre><pre data-type="codeBlock" text="%Blockchain{
  chain: [
    %{
      current_transactions: [],
      index: 0,
      name: &quot;ZERO&quot;,
      previous_hash: &quot;&quot;,
      timestamp: ~N[2022-04-01 12:27:28.717693]
    }
  ],
  current_transactions: [],
  last_nonce: 0
}
"><code><span class="hljs-string">%Blockchain{</span>
  <span class="hljs-attr">chain:</span> [
    <span class="hljs-string">%</span>{
      <span class="hljs-attr">current_transactions:</span> [],
      <span class="hljs-attr">index:</span> <span class="hljs-number">0</span>,
      <span class="hljs-attr">name:</span> <span class="hljs-string">"ZERO"</span>,
      <span class="hljs-attr">previous_hash:</span> <span class="hljs-string">""</span>,
      <span class="hljs-attr">timestamp:</span> <span class="hljs-string">~N</span>[<span class="hljs-number">2022-04-01 12:27:28.717693</span>]
    }
  ]<span class="hljs-string">,</span>
  <span class="hljs-attr">current_transactions:</span> []<span class="hljs-string">,</span>
  <span class="hljs-attr">last_nonce:</span> <span class="hljs-number">0</span>
<span class="hljs-string">}</span>
</code></pre><p>If you want to generate a new block, you must calculate the nonce and use the calculated nonce to create the block. If the nonce is not calculated, an error will be reported. For example, I randomly gave a nonce of 333 here and let&apos;s try to execute it:</p><pre data-type="codeBlock" text="first = zero |&gt; Blockchain.new_block(&quot;first&quot;, 333)
"><code>first <span class="hljs-operator">=</span> zero <span class="hljs-operator">|</span><span class="hljs-operator">></span> Blockchain.new_block(<span class="hljs-string">"first"</span>, <span class="hljs-number">333</span>)
</code></pre><pre data-type="codeBlock" text="difficulty: 0000, attempt: 333, hash: e73a36f8264731f64049b86564604e671d4bb1cfc0f6ab26803a5ad18040fee2
nonce: 333 is invalid
"><code><span class="hljs-attr">difficulty:</span> <span class="hljs-number">0000</span><span class="hljs-string">,</span> <span class="hljs-attr">attempt:</span> <span class="hljs-number">333</span><span class="hljs-string">,</span> <span class="hljs-attr">hash:</span> <span class="hljs-string">e73a36f8264731f64049b86564604e671d4bb1cfc0f6ab26803a5ad18040fee2</span>
<span class="hljs-attr">nonce:</span> <span class="hljs-number">333</span> <span class="hljs-string">is</span> <span class="hljs-string">invalid</span>
</code></pre><pre data-type="codeBlock" text=":ok
"><code><span class="hljs-symbol">:ok</span>
</code></pre><p>Call proof_of_work to compute the nonce:</p><pre data-type="codeBlock" text="nonce = Blockchain.proof_of_work(zero.last_nonce)
"><code>nonce <span class="hljs-operator">=</span> Blockchain.proof_of_work(zero.last_nonce)
</code></pre><pre data-type="codeBlock" text="difficulty: 0000, attempt: 69732, hash: 0000e326186933fa83f0efd581d09409022ec07b73a10f549bbaa6472e8a1175
"><code><span class="hljs-attr">difficulty:</span> <span class="hljs-number">0000</span><span class="hljs-string">,</span> <span class="hljs-attr">attempt:</span> <span class="hljs-number">69732</span><span class="hljs-string">,</span> <span class="hljs-attr">hash:</span> <span class="hljs-string">0000e326186933fa83f0efd581d09409022ec07b73a10f549bbaa6472e8a1175</span>
</code></pre><pre data-type="codeBlock" text="69732
"><code></code></pre><p>Use the calculated nonce to generate blocks:</p><pre data-type="codeBlock" text="first = zero |&gt; Blockchain.new_block(&quot;first&quot;, nonce)
"><code>first <span class="hljs-operator">=</span> zero <span class="hljs-operator">|</span><span class="hljs-operator">></span> Blockchain.new_block(<span class="hljs-string">"first"</span>, nonce)
</code></pre><pre data-type="codeBlock" text="difficulty: 0000, attempt: 69732, hash: 0000e326186933fa83f0efd581d09409022ec07b73a10f549bbaa6472e8a1175
"><code><span class="hljs-attr">difficulty:</span> <span class="hljs-number">0000</span><span class="hljs-string">,</span> <span class="hljs-attr">attempt:</span> <span class="hljs-number">69732</span><span class="hljs-string">,</span> <span class="hljs-attr">hash:</span> <span class="hljs-string">0000e326186933fa83f0efd581d09409022ec07b73a10f549bbaa6472e8a1175</span>
</code></pre><pre data-type="codeBlock" text="%Blockchain{
  chain: [
    %{
      current_transactions: [],
      index: 0,
      name: &quot;ZERO&quot;,
      previous_hash: &quot;&quot;,
      timestamp: ~N[2022-04-01 12:27:28.717693]
    },
    %{
      current_transactions: [],
      index: 1,
      name: &quot;first&quot;,
      previous_hash: &quot;d530c9090258905de8009fe933f8e4686916adc3e803b89600615a2fb817392d&quot;,
      timestamp: ~N[2022-04-01 12:28:33.450247]
    }
  ],
  current_transactions: [],
  last_nonce: 69732
}
"><code><span class="hljs-string">%Blockchain{</span>
  <span class="hljs-attr">chain:</span> [
    <span class="hljs-string">%</span>{
      <span class="hljs-attr">current_transactions:</span> [],
      <span class="hljs-attr">index:</span> <span class="hljs-number">0</span>,
      <span class="hljs-attr">name:</span> <span class="hljs-string">"ZERO"</span>,
      <span class="hljs-attr">previous_hash:</span> <span class="hljs-string">""</span>,
      <span class="hljs-attr">timestamp:</span> <span class="hljs-string">~N</span>[<span class="hljs-number">2022-04-01 12:27:28.717693</span>]
    },
    <span class="hljs-string">%</span>{
      <span class="hljs-attr">current_transactions:</span> [],
      <span class="hljs-attr">index:</span> <span class="hljs-number">1</span>,
      <span class="hljs-attr">name:</span> <span class="hljs-string">"first"</span>,
      <span class="hljs-attr">previous_hash:</span> <span class="hljs-string">"d530c9090258905de8009fe933f8e4686916adc3e803b89600615a2fb817392d"</span>,
      <span class="hljs-attr">timestamp:</span> <span class="hljs-string">~N</span>[<span class="hljs-number">2022-04-01 12:28:33.450247</span>]
    }
  ]<span class="hljs-string">,</span>
  <span class="hljs-attr">current_transactions:</span> []<span class="hljs-string">,</span>
  <span class="hljs-attr">last_nonce:</span> <span class="hljs-number">69732</span>
<span class="hljs-string">}</span>
</code></pre><p>Done!</p><p>Complete the following steps:</p><ul><li><p>Build the genesis block</p></li><li><p>Calculate the nonce, create the first block</p></li><li><p>Calculate new nonce</p></li><li><p>Execute a few transactions to generate a new block</p></li></ul><pre data-type="codeBlock" text="zero = Blockchain.zero()

nonce = Blockchain.proof_of_work(zero.last_nonce)
IO.inspect(nonce)
first = zero |&gt; Blockchain.new_block(&quot;first&quot;, nonce)
IO.inspect(first)

nonce = Blockchain.proof_of_work(first.last_nonce)

second =
  first
  |&gt; Blockchain.new_transaction(&quot;alice&quot;, &quot;bob&quot;, 100)
  |&gt; Blockchain.new_block(&quot;second&quot;, nonce)

IO.inspect(second)
"><code>zero <span class="hljs-operator">=</span> Blockchain.zero()

nonce <span class="hljs-operator">=</span> Blockchain.proof_of_work(zero.last_nonce)
IO.inspect(nonce)
first <span class="hljs-operator">=</span> zero <span class="hljs-operator">|</span><span class="hljs-operator">></span> Blockchain.new_block(<span class="hljs-string">"first"</span>, nonce)
IO.inspect(first)

nonce <span class="hljs-operator">=</span> Blockchain.proof_of_work(first.last_nonce)

second <span class="hljs-operator">=</span>
  first
  <span class="hljs-operator">|</span><span class="hljs-operator">></span> Blockchain.new_transaction(<span class="hljs-string">"alice"</span>, <span class="hljs-string">"bob"</span>, <span class="hljs-number">100</span>)
  <span class="hljs-operator">|</span><span class="hljs-operator">></span> Blockchain.new_block(<span class="hljs-string">"second"</span>, nonce)

IO.inspect(second)
</code></pre><pre data-type="codeBlock" text="difficulty: 0000, attempt: 69732, hash: 0000e326186933fa83f0efd581d09409022ec07b73a10f549bbaa6472e8a117569732
difficulty: 0000, attempt: 69732, hash: 0000e326186933fa83f0efd581d09409022ec07b73a10f549bbaa6472e8a1175%Blockchain{
  chain: [
    %{
      current_transactions: [],
      index: 0,
      name: &quot;ZERO&quot;,
      previous_hash: &quot;&quot;,
      timestamp: ~N[2022-04-01 12:29:06.201828]
    },
    %{
      current_transactions: [],
      index: 1,
      name: &quot;first&quot;,
      previous_hash: &quot;b8099550bfe6931ad0eccb7a18d1d638d33177fe6ecc7621dcb593bdc406cf00&quot;,
      timestamp: ~N[2022-04-01 12:29:06.916490]
    }
  ],
  current_transactions: [],
  last_nonce: 69732
}
difficulty: 0000, attempt: 23263, hash: 0000ffc4b3bdbd6d46a4649d48944700b204fe59883f915fe1030f05c16a5492%Blockchain{
  chain: [
    %{
      current_transactions: [],
      index: 0,
      name: &quot;ZERO&quot;,
      previous_hash: &quot;&quot;,
      timestamp: ~N[2022-04-01 12:29:06.201828]
    },
    %{
      current_transactions: [],
      index: 1,
      name: &quot;first&quot;,
      previous_hash: &quot;b8099550bfe6931ad0eccb7a18d1d638d33177fe6ecc7621dcb593bdc406cf00&quot;,
      timestamp: ~N[2022-04-01 12:29:06.916490]
    },
    %{
      current_transactions: [%{amount: 100, recipient: &quot;bob&quot;, sender: &quot;alice&quot;}],
      index: 2,
      name: &quot;second&quot;,
      previous_hash: &quot;5e1e75f4822ac949e20944175a39d9301ad278611eb74043cb761ba83742df8c&quot;,
      timestamp: ~N[2022-04-01 12:29:07.222425]
    }
  ],
  current_transactions: [],
  last_nonce: 23263
}
"><code><span class="hljs-attr">difficulty:</span> <span class="hljs-number">0000</span><span class="hljs-string">,</span> <span class="hljs-attr">attempt:</span> <span class="hljs-number">69732</span><span class="hljs-string">,</span> <span class="hljs-attr">hash:</span> <span class="hljs-string">0000e326186933fa83f0efd581d09409022ec07b73a10f549bbaa6472e8a117569732</span>
<span class="hljs-attr">difficulty:</span> <span class="hljs-number">0000</span><span class="hljs-string">,</span> <span class="hljs-attr">attempt:</span> <span class="hljs-number">69732</span><span class="hljs-string">,</span> <span class="hljs-attr">hash:</span> <span class="hljs-string">0000e326186933fa83f0efd581d09409022ec07b73a10f549bbaa6472e8a1175%Blockchain{</span>
  <span class="hljs-attr">chain:</span> [
    <span class="hljs-string">%</span>{
      <span class="hljs-attr">current_transactions:</span> [],
      <span class="hljs-attr">index:</span> <span class="hljs-number">0</span>,
      <span class="hljs-attr">name:</span> <span class="hljs-string">"ZERO"</span>,
      <span class="hljs-attr">previous_hash:</span> <span class="hljs-string">""</span>,
      <span class="hljs-attr">timestamp:</span> <span class="hljs-string">~N</span>[<span class="hljs-number">2022-04-01 12:29:06.201828</span>]
    },
    <span class="hljs-string">%</span>{
      <span class="hljs-attr">current_transactions:</span> [],
      <span class="hljs-attr">index:</span> <span class="hljs-number">1</span>,
      <span class="hljs-attr">name:</span> <span class="hljs-string">"first"</span>,
      <span class="hljs-attr">previous_hash:</span> <span class="hljs-string">"b8099550bfe6931ad0eccb7a18d1d638d33177fe6ecc7621dcb593bdc406cf00"</span>,
      <span class="hljs-attr">timestamp:</span> <span class="hljs-string">~N</span>[<span class="hljs-number">2022-04-01 12:29:06.916490</span>]
    }
  ]<span class="hljs-string">,</span>
  <span class="hljs-attr">current_transactions:</span> []<span class="hljs-string">,</span>
  <span class="hljs-attr">last_nonce:</span> <span class="hljs-number">69732</span>
<span class="hljs-string">}</span>
<span class="hljs-attr">difficulty:</span> <span class="hljs-number">0000</span><span class="hljs-string">,</span> <span class="hljs-attr">attempt:</span> <span class="hljs-number">23263</span><span class="hljs-string">,</span> <span class="hljs-attr">hash:</span> <span class="hljs-string">0000ffc4b3bdbd6d46a4649d48944700b204fe59883f915fe1030f05c16a5492%Blockchain{</span>
  <span class="hljs-attr">chain:</span> [
    <span class="hljs-string">%</span>{
      <span class="hljs-attr">current_transactions:</span> [],
      <span class="hljs-attr">index:</span> <span class="hljs-number">0</span>,
      <span class="hljs-attr">name:</span> <span class="hljs-string">"ZERO"</span>,
      <span class="hljs-attr">previous_hash:</span> <span class="hljs-string">""</span>,
      <span class="hljs-attr">timestamp:</span> <span class="hljs-string">~N</span>[<span class="hljs-number">2022-04-01 12:29:06.201828</span>]
    },
    <span class="hljs-string">%</span>{
      <span class="hljs-attr">current_transactions:</span> [],
      <span class="hljs-attr">index:</span> <span class="hljs-number">1</span>,
      <span class="hljs-attr">name:</span> <span class="hljs-string">"first"</span>,
      <span class="hljs-attr">previous_hash:</span> <span class="hljs-string">"b8099550bfe6931ad0eccb7a18d1d638d33177fe6ecc7621dcb593bdc406cf00"</span>,
      <span class="hljs-attr">timestamp:</span> <span class="hljs-string">~N</span>[<span class="hljs-number">2022-04-01 12:29:06.916490</span>]
    },
    <span class="hljs-string">%</span>{
      <span class="hljs-attr">current_transactions:</span> [<span class="hljs-string">%</span>{<span class="hljs-attr">amount:</span> <span class="hljs-number">100</span>, <span class="hljs-attr">recipient:</span> <span class="hljs-string">"bob"</span>, <span class="hljs-attr">sender:</span> <span class="hljs-string">"alice"</span>}],
      <span class="hljs-attr">index:</span> <span class="hljs-number">2</span>,
      <span class="hljs-attr">name:</span> <span class="hljs-string">"second"</span>,
      <span class="hljs-attr">previous_hash:</span> <span class="hljs-string">"5e1e75f4822ac949e20944175a39d9301ad278611eb74043cb761ba83742df8c"</span>,
      <span class="hljs-attr">timestamp:</span> <span class="hljs-string">~N</span>[<span class="hljs-number">2022-04-01 12:29:07.222425</span>]
    }
  ]<span class="hljs-string">,</span>
  <span class="hljs-attr">current_transactions:</span> []<span class="hljs-string">,</span>
  <span class="hljs-attr">last_nonce:</span> <span class="hljs-number">23263</span>
<span class="hljs-string">}</span>
</code></pre><pre data-type="codeBlock" text="%Blockchain{
  chain: [
    %{
      current_transactions: [],
      index: 0,
      name: &quot;ZERO&quot;,
      previous_hash: &quot;&quot;,
      timestamp: ~N[2022-04-01 12:29:06.201828]
    },
    %{
      current_transactions: [],
      index: 1,
      name: &quot;first&quot;,
      previous_hash: &quot;b8099550bfe6931ad0eccb7a18d1d638d33177fe6ecc7621dcb593bdc406cf00&quot;,
      timestamp: ~N[2022-04-01 12:29:06.916490]
    },
    %{
      current_transactions: [%{amount: 100, recipient: &quot;bob&quot;, sender: &quot;alice&quot;}],
      index: 2,
      name: &quot;second&quot;,
      previous_hash: &quot;5e1e75f4822ac949e20944175a39d9301ad278611eb74043cb761ba83742df8c&quot;,
      timestamp: ~N[2022-04-01 12:29:07.222425]
    }
  ],
  current_transactions: [],
  last_nonce: 23263
}
"><code><span class="hljs-string">%Blockchain{</span>
  <span class="hljs-attr">chain:</span> [
    <span class="hljs-string">%</span>{
      <span class="hljs-attr">current_transactions:</span> [],
      <span class="hljs-attr">index:</span> <span class="hljs-number">0</span>,
      <span class="hljs-attr">name:</span> <span class="hljs-string">"ZERO"</span>,
      <span class="hljs-attr">previous_hash:</span> <span class="hljs-string">""</span>,
      <span class="hljs-attr">timestamp:</span> <span class="hljs-string">~N</span>[<span class="hljs-number">2022-04-01 12:29:06.201828</span>]
    },
    <span class="hljs-string">%</span>{
      <span class="hljs-attr">current_transactions:</span> [],
      <span class="hljs-attr">index:</span> <span class="hljs-number">1</span>,
      <span class="hljs-attr">name:</span> <span class="hljs-string">"first"</span>,
      <span class="hljs-attr">previous_hash:</span> <span class="hljs-string">"b8099550bfe6931ad0eccb7a18d1d638d33177fe6ecc7621dcb593bdc406cf00"</span>,
      <span class="hljs-attr">timestamp:</span> <span class="hljs-string">~N</span>[<span class="hljs-number">2022-04-01 12:29:06.916490</span>]
    },
    <span class="hljs-string">%</span>{
      <span class="hljs-attr">current_transactions:</span> [<span class="hljs-string">%</span>{<span class="hljs-attr">amount:</span> <span class="hljs-number">100</span>, <span class="hljs-attr">recipient:</span> <span class="hljs-string">"bob"</span>, <span class="hljs-attr">sender:</span> <span class="hljs-string">"alice"</span>}],
      <span class="hljs-attr">index:</span> <span class="hljs-number">2</span>,
      <span class="hljs-attr">name:</span> <span class="hljs-string">"second"</span>,
      <span class="hljs-attr">previous_hash:</span> <span class="hljs-string">"5e1e75f4822ac949e20944175a39d9301ad278611eb74043cb761ba83742df8c"</span>,
      <span class="hljs-attr">timestamp:</span> <span class="hljs-string">~N</span>[<span class="hljs-number">2022-04-01 12:29:07.222425</span>]
    }
  ]<span class="hljs-string">,</span>
  <span class="hljs-attr">current_transactions:</span> []<span class="hljs-string">,</span>
  <span class="hljs-attr">last_nonce:</span> <span class="hljs-number">23263</span>
<span class="hljs-string">}</span>
</code></pre><h2 id="h-0x07-the-sages-time" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x07 The sage&apos;s time</h2><p>Programming is about Data Transformation</p><blockquote><p>Programming Should Be About Transforming Data.</p></blockquote><p>If you deeply understand this quote, the ETL (Extract - Transform - Load) of data analysis is so natural, and Map/Reduce the dividing &amp; conquering is also well understood.</p><p>There is no single correct way to write code, so we may change the way of thinking:</p><ul><li><p>Object-orientated programming is not the only way to design code</p></li><li><p>Functional programming does not have to be complex and purely mathematical</p></li><li><p>Programming is not based on assignments, if statements and loops</p></li><li><p>Concurrency doesn&apos;t necessarily require locks, semaphores, monitors, etc.</p></li><li><p>Processes don&apos;t have to consume a lot of resources</p></li><li><p>Metaprogramming is not just an add-on to languages</p></li><li><p>Even if programming is your job, it should be fun</p></li></ul><p>Mastering Elixir may not yet add luster to your resume, allowing you to get a higher premium in the workplace. But learning Elixir can give you a different perspective on functions, mutability, concurrency, and high availability.</p><p>Elixir is very different from mainstream programming languages, and it will enrich your perspective and open your eyes to new programming thinking.</p><p>Finally, Why Elixir &amp; Blockchain? Make sure Web3 happens in Elixir!</p><h2 id="h-reference" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Reference</h2><ul><li><p>Create a Pow Blockchain with Python</p><ul><li><p>Reading：<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://r8jmm3f9xe.feishu.cn/docs/doccnJ78y2G5KEXHObTnkpCrHwh">https://r8jmm3f9xe.feishu.cn/docs/doccnJ78y2G5KEXHObTnkpCrHwh</a></p></li><li><p>Video：<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ke.qq.com/course/3616174?tuin=d34bd514&amp;taid=12533264329158062">https://ke.qq.com/course/3616174?tuin=d34bd514&amp;taid=12533264329158062</a></p></li></ul></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://draveness.me/utxo-account-models/">UTXO and model with account balance</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://time.geekbang.org/column/article/5963">Geek Time: Explaining the Blockchain</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://zhuanlan.zhihu.com/p/19968376">elixir：A panacea? or just have a name</a></p></li></ul><hr><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">snowyaya</figcaption></figure>]]></content:encoded>
            <author>apecoder@newsletter.paragraph.com (Web3dAppDevCamp)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/9cb5da88fe2456a589702ed1286542b7de436f147792069c1b1bcd03a106a1a6.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[Token Vendor | Web3.0 dApp Dev 0x08]]></title>
            <link>https://paragraph.com/@apecoder/token-vendor-web3-0-dapp-dev-0x08</link>
            <guid>M54pwYQth39Iy9MhGCHF</guid>
            <pubDate>Mon, 21 Mar 2022 02:22:40 GMT</pubDate>
            <description><![CDATA[Authors: ken, msfew, SnowyayaToken Vendor is a vending machine that&apos;s combined of scaffold-eth and BuidlGuidl. This tutorial will walk you through how the project is implemented. To do that, we split the entire project to five smaller parts and it&apos;s verrifiable whether each part functions successfully after it&apos;s implemented.0x01 Installation and Local ConfigurationStep1. Open the terminal window and clone scaffold-eth base codegit clone https://github.com/scaffold-eth/scaffold-...]]></description>
            <content:encoded><![CDATA[<blockquote><p>Authors: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/kenspirit">ken</a>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/fewwwww">msfew</a>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/Snowyaya">Snowyaya</a></p></blockquote><p>Token Vendor is a vending machine that&apos;s combined of scaffold-eth and BuidlGuidl. This tutorial will walk you through how the project is implemented. To do that, we split the entire project to five smaller parts and it&apos;s verrifiable whether each part functions successfully after it&apos;s implemented.</p><h2 id="h-0x01-installation-and-local-configuration" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x01 Installation and Local Configuration</h2><p><strong>Step1. Open the terminal window and clone scaffold-eth base code</strong></p><pre data-type="codeBlock" text="git clone https://github.com/scaffold-eth/scaffold-eth-typescript-challenges.git challenge-2-token-vendor

cd challenge-2-token-vendor

git checkout challenge-2-token-vendor
"><code>git clone https:<span class="hljs-comment">//github.com/scaffold-eth/scaffold-eth-typescript-challenges.git challenge-2-token-vendor</span>

cd challenge<span class="hljs-number">-2</span><span class="hljs-operator">-</span>token<span class="hljs-operator">-</span>vendor

git checkout challenge<span class="hljs-number">-2</span><span class="hljs-operator">-</span>token<span class="hljs-operator">-</span>vendor
</code></pre><p><strong>Step2. Install dependencies</strong></p><pre data-type="codeBlock" text="yarn install
"><code></code></pre><p><strong>Step3. Prepare the enviroment</strong> We need three terminal windows for this step, and each will execute their own command consecutively. The three commands will be used to:</p><pre data-type="codeBlock" text="yarn chain (start the `hardhat` backend and local nodes)

yarn deploy (compile, deploy the smart contract and push to the front-ended project reference)

yarn start (React front-ended App)
"><code>yarn <span class="hljs-title function_">chain</span> <span class="hljs-params">(start the `hardhat` backend and local nodes)</span>

yarn <span class="hljs-title function_">deploy</span> <span class="hljs-params">(compile, deploy the smart contract and push to the front-ended project reference)</span>

yarn <span class="hljs-title function_">start</span> <span class="hljs-params">(React front-ended App)</span>
</code></pre><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">Terminal</figcaption></figure><p>After commands executed</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">Command Completed</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">App UI</figcaption></figure><h2 id="h-0x02-prepare-metamask-account" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x02 Prepare MetaMask Account</h2><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">Generate Account</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">View Account</figcaption></figure><p>Change the <code>DEBUG</code> statement in <code>packages/hardhat-ts/hardhat.config.ts</code> to <code>const DEBUG = true;</code>; When viewing the account information, the private key of the wallet will aso be displayed, which can be imported to MetaMask.</p><p><strong>Configure MetaMask:</strong> If you do not have MetaMask local network, configure by doing so:</p><ul><li><p>network name: <code>Localhost 8545</code></p></li><li><p>new RPC URL: <code>http://localhost:8545</code></p></li><li><p>chain ID: <code>31337</code></p></li><li><p>currency symbol： <code>ETH</code></p></li></ul><p>Remember to check the value of chain ID. It should be <code>1337</code> normally, but for <code>hardhat</code>, it is <code>31337</code>. If it&apos;s not changed, you might end up having <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://hardhat.org/metamask-issue.html">this issue</a>, which couldn&apos;t send transactions.</p><h2 id="h-0x03-launch-your-own-token" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x03 Launch your own token</h2><h3 id="h-31-token-smart-contract" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">3.1 Token smart contract</h3><p>The Token in Ethereum is actually smart contract. The location of the contract file we need to customize is: <code>packages/hardhat-ts/contracts/YourToken.sol</code>.</p><pre data-type="codeBlock" text="pragma solidity &gt;=0.8.0 &lt;0.9.0;
// SPDX-License-Identifier: MIT

// inherited from OpenZeppelin&apos;s ERC20 Token standard
import &apos;@openzeppelin/contracts/token/ERC20/ERC20.sol&apos;;

// learn more: https://docs.openzeppelin.com/contracts/3.x/erc20

contract YourToken is ERC20 {
  // ToDo: add constructor and mint tokens for deployer,
  //       you can use the above import for ERC20.sol. Read the docs ^^^

  // constructor
  constructor() public ERC20(&apos;Gold&apos;, &apos;GLD&apos;) {
    // _mint() 1000 * 10 ** 18 to msg.sender
    _mint(msg.sender, 1000 * 10**18);
  }
}
"><code><span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> >=0.8.0 &#x3C;0.9.0;</span>
<span class="hljs-comment">// SPDX-License-Identifier: MIT</span>

<span class="hljs-comment">// inherited from OpenZeppelin's ERC20 Token standard</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">'@openzeppelin/contracts/token/ERC20/ERC20.sol'</span>;

<span class="hljs-comment">// learn more: https://docs.openzeppelin.com/contracts/3.x/erc20</span>

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">YourToken</span> <span class="hljs-keyword">is</span> <span class="hljs-title">ERC20</span> </span>{
  <span class="hljs-comment">// ToDo: add constructor and mint tokens for deployer,</span>
  <span class="hljs-comment">//       you can use the above import for ERC20.sol. Read the docs ^^^</span>

  <span class="hljs-comment">// constructor</span>
  <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title">ERC20</span>(<span class="hljs-params"><span class="hljs-string">'Gold'</span>, <span class="hljs-string">'GLD'</span></span>) </span>{
    <span class="hljs-comment">// _mint() 1000 * 10 ** 18 to msg.sender</span>
    _mint(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, <span class="hljs-number">1000</span> <span class="hljs-operator">*</span> <span class="hljs-number">10</span><span class="hljs-operator">*</span><span class="hljs-operator">*</span><span class="hljs-number">18</span>);
  }
}
</code></pre><p>By inheriting the ERC20 standard (<code>is ERC20</code>), this Token has basic functions such as basic transfer, querying the balance of the Token held by the account. We only need to name the Token and specify its initial total amount to use.</p><ul><li><p>token symbol: <code>GLD</code></p></li><li><p>token name: <code>Gold</code></p></li><li><p>initial amount: <code>1000 * 10**18</code> (1000 Token)</p></li></ul><p><code>10**18</code> means 10 to the 18th degree, where there are 18 zeroes. Why use such a large number, <code>1000000000000000000</code>, to represent a Token? The reason is the same as we use <strong>penny</strong> in calculating <strong>dollar</strong>. The language EVM and Solidity can only handle integers, so in order to facilitate the Token to be cut into small units for circulation, we need a smaller unit, and the inherited ERC20 defines the length of this decimal place to be 18.</p><h3 id="h-32-deploy-and-transfer-token" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">3.2 Deploy and transfer Token</h3><p>After the contract is written, change the statement in <code>packages/hardhat-ts/deploy/00_deploy_your_token.ts</code>, fill in the prepared account, and test whether the transfer can be done successfully:</p><pre data-type="codeBlock" text="  // Todo: transfer tokens to frontend address
  const result = await yourToken.transfer(
    &quot;0xC0802222dB0F31d63dc85d9C8CAa00485715A13c&quot;, ethers.utils.parseEther(&quot;1000&quot;));
"><code>  <span class="hljs-comment">// Todo: transfer tokens to frontend address</span>
  const result <span class="hljs-operator">=</span> await yourToken.<span class="hljs-built_in">transfer</span>(
    <span class="hljs-string">"0xC0802222dB0F31d63dc85d9C8CAa00485715A13c"</span>, ethers.utils.parseEther(<span class="hljs-string">"1000"</span>));
</code></pre><p>Note that if we want to transfer 1000 Token, we do not directly pass 1000 to the <code>transfer</code> function, but need to go through <code>ethers.utils.parseEther</code> to convert it into the number that is handleable by the contract.</p><p>After modification, deploy by command <code>yarn deploy --reset</code>.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">Deploy Token</figcaption></figure><p>If deployed successfully, call the <code>balanceOf</code> function through the <code>Debug</code> page in the browser to check whether the address after the transfer has the corresponding number of Tokens.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">Account Balance</figcaption></figure><p>You can also try to transfer tokens from the current account to another account. However, before that, the wallet of the current account needs to have few ETH.</p><p>Press the button <strong>Grab funds from the faucet</strong> on the current page to get some.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">Grab ETH</figcaption></figure><p>Another way to get more ETH is through the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://faucet.paradigm.xyz/">faucet.paradigm.xyz</a> page to authorize Twitter to log in and fill in the address to request.</p><p>Through the <code>transfer</code> function on the Debug page, we can transfer Token. The amount to be filled in needs to be converted. In the meantime, you can also click the <strong>Send</strong> button and modify it again in the confirmation box that pops up in MetaMask.</p><p><strong>Note</strong>: Due to the contract changes or the time constraints, you may need to deploy multiple times and cannot complete the test at one time. Changes to the local network will cause the number of transactions in the account to be different from the number of transactions on MetaMask. When initiating a transaction, MetaMask is likely to alert you to the errors like <strong>Nonce too high. Expected nonce to be 0 but got x.</strong>. If so, you need to prepare a new account, or delete the account from MetaMask and try importing it again.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">Transfer Another</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">Confirm Transfer</figcaption></figure><h2 id="h-0x04-build-a-vending-machine-vendor" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x04 Build a vending machine Vendor</h2><p>Now we start to implement the smart contract of the vending machine Vendor. It&apos;s framework is in the file <code>packages/hardhat-ts/contracts/Vendor.sol</code>.</p><h3 id="h-41-define-the-token-price" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">4.1 Define the Token price</h3><p>Token trading requires first determining the exchange rate between Token and ETH.</p><p>In the contract, we can define how many tokens an ETH can buy through the constant <code>tokensPerEth</code>. Remember that 1 Token means 1 * 10**18. Since the free ETH that the test account can get may be very few, this number may be set larger.</p><pre data-type="codeBlock" text="uint256 public constant tokensPerEth = 10000;
"><code><span class="hljs-keyword">uint256</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">constant</span> tokensPerEth <span class="hljs-operator">=</span> <span class="hljs-number">10000</span>;
</code></pre><h3 id="h-42-buytokens-function" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">4.2 buyTokens function</h3><p>The logic of buying Token is very simple. It is to calculate how many Tokens the sender of the transaction can get from the vending machine according to the amount of ETH in the transaction. The complete contract after implementing the <code>buyTokens</code> function is as follows:</p><pre data-type="codeBlock" text="pragma solidity &gt;=0.8.0 &lt;0.9.0;
// SPDX-License-Identifier: MIT

import &apos;@openzeppelin/contracts/access/Ownable.sol&apos;;
import &apos;./YourToken.sol&apos;;

contract Vendor is Ownable {
  YourToken yourToken;

  uint256 public constant tokensPerEth = 10000;

  event BuyTokens(address buyer, uint256 amountOfEth, uint256 amountOfTokens);

  constructor(address tokenAddress) public {
    yourToken = YourToken(tokenAddress);
  }

  // ToDo: create a payable buyTokens() function:
  function buyTokens() public payable returns (uint256 tokenAmount) {
    require(msg.value &gt; 0, &apos;ETH used to buy token must be greater than 0&apos;);

    uint256 tokenToBuy = msg.value * tokensPerEth;

    // check if the Vendor Contract has enough amount of tokens for the transaction
    uint256 vendorBalance = yourToken.balanceOf(address(this));
    require(vendorBalance &gt;= tokenToBuy, &apos;Vendor has not enough tokens to sell&apos;);

    // Transfer token to the msg.sender
    bool success = yourToken.transfer(msg.sender, tokenToBuy);
    require(success, &apos;Failed to transfer token to user&apos;);

    emit BuyTokens(msg.sender, msg.value, tokenToBuy);

    return tokenToBuy;
  }
}
"><code><span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> >=0.8.0 &#x3C;0.9.0;</span>
<span class="hljs-comment">// SPDX-License-Identifier: MIT</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">'@openzeppelin/contracts/access/Ownable.sol'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'./YourToken.sol'</span>;

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Vendor</span> <span class="hljs-keyword">is</span> <span class="hljs-title">Ownable</span> </span>{
  YourToken yourToken;

  <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">constant</span> tokensPerEth <span class="hljs-operator">=</span> <span class="hljs-number">10000</span>;

  <span class="hljs-function"><span class="hljs-keyword">event</span> <span class="hljs-title">BuyTokens</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> buyer, <span class="hljs-keyword">uint256</span> amountOfEth, <span class="hljs-keyword">uint256</span> amountOfTokens</span>)</span>;

  <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> tokenAddress</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
    yourToken <span class="hljs-operator">=</span> YourToken(tokenAddress);
  }

  <span class="hljs-comment">// ToDo: create a payable buyTokens() function:</span>
  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">buyTokens</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span> tokenAmount</span>) </span>{
    <span class="hljs-built_in">require</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span> <span class="hljs-operator">></span> <span class="hljs-number">0</span>, <span class="hljs-string">'ETH used to buy token must be greater than 0'</span>);

    <span class="hljs-keyword">uint256</span> tokenToBuy <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span> <span class="hljs-operator">*</span> tokensPerEth;

    <span class="hljs-comment">// check if the Vendor Contract has enough amount of tokens for the transaction</span>
    <span class="hljs-keyword">uint256</span> vendorBalance <span class="hljs-operator">=</span> yourToken.balanceOf(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>));
    <span class="hljs-built_in">require</span>(vendorBalance <span class="hljs-operator">></span><span class="hljs-operator">=</span> tokenToBuy, <span class="hljs-string">'Vendor has not enough tokens to sell'</span>);

    <span class="hljs-comment">// Transfer token to the msg.sender</span>
    <span class="hljs-keyword">bool</span> success <span class="hljs-operator">=</span> yourToken.<span class="hljs-built_in">transfer</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, tokenToBuy);
    <span class="hljs-built_in">require</span>(success, <span class="hljs-string">'Failed to transfer token to user'</span>);

    <span class="hljs-keyword">emit</span> BuyTokens(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span>, tokenToBuy);

    <span class="hljs-keyword">return</span> tokenToBuy;
  }
}
</code></pre><p>Key parts of the contract:</p><ol><li><p><code>payable</code> modifier:</p><blockquote><p>indicates that this function can receive ETH. It is necessary to mark this function as payable because buying Token requires transferring ETH to Vendor.</p></blockquote></li><li><p>the statement <code>require(msg.value &gt; 0, &apos;ETH used to buy token must be greater than 0&apos;);</code></p><blockquote><p>constraint checking. Obviously, to buy Token, the amount of incoming ETH must be greater than 0. The value of <code>msg.value</code> is the amount of ETH.</p></blockquote></li><li><p><code>address(this)</code> function call:</p><blockquote><p>get the address of this contract</p></blockquote></li><li><p><code>emit BuyTokens(msg.sender, msg.value, tokenToBuy)</code>：</p><blockquote><p>trigger the <code>BuyTokens</code> event to record the address, cost, and purchase quantity of the purchased Token. Evens are available as EVM logging.</p></blockquote></li></ol><h3 id="h-43-withdraw-function" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">4.3 withdraw function</h3><p>After the vending machine Vendor sells the Token, the buyer&apos;s ETH slowly accumulates into the Vendor account. So how do you get the ETH out of the contract? At this point we need to implement the <code>withdraw</code> function:</p><pre data-type="codeBlock" text="// ToDo: create a withdraw() function that lets the owner withdraw ETH
function withdraw() public onlyOwner {
  uint256 ethToWithdraw = address(this).balance;
  require(ethToWithdraw &gt; 0, &apos;No ETH to withdraw&apos;);

  payable(msg.sender).transfer(ethToWithdraw);
}
"><code><span class="hljs-comment">// ToDo: create a withdraw() function that lets the owner withdraw ETH</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">withdraw</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title">onlyOwner</span> </span>{
  <span class="hljs-keyword">uint256</span> ethToWithdraw <span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>).<span class="hljs-built_in">balance</span>;
  <span class="hljs-built_in">require</span>(ethToWithdraw <span class="hljs-operator">></span> <span class="hljs-number">0</span>, <span class="hljs-string">'No ETH to withdraw'</span>);

  <span class="hljs-keyword">payable</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>).<span class="hljs-built_in">transfer</span>(ethToWithdraw);
}
</code></pre><p>Key parts of the contract:</p><ol><li><p><code>onlyOwner</code> midifier:</p><blockquote><p>Indicates that this function can only be called by the contract owner. This modifier is inherited from the <code>Ownable.sol</code> contract.</p></blockquote></li><li><p>statement <code>payable(msg.sender).transfer(ethToWithdraw)</code>:</p><blockquote><p>When calling the <code>transfer</code> function, the payable address must be used, not the ordinary address. So, you need to use <code>payable()</code> to convert instead of <code>address()</code> as in the previous sentence.</p></blockquote></li></ol><h3 id="h-44-deploy-vendor-contract" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">4.4 Deploy Vendor contract</h3><p><code>withdraw</code> function is ready. Who are allowed to withdraw funds from the contract? Of course the owner of the vendor, which is the owner of the vendor contract. The initial owner is the address that deploys the contract. If the address you connected with MetaMask is not the address for deployment, then you need to transfer the ownership to the address you use to log in the App.</p><p>Uncomment <code>packages/hardhat-ts/deploy/01_deploy_vendor.ts</code>&apos;s commented lines, then modify the Token amount transferring from YourToken to Vendor. If needed, assign new owner to Vendor contract.</p><pre data-type="codeBlock" text="// Todo: deploy the vendor

await deploy(&apos;Vendor&apos;, {
  // Learn more about args here: https://www.npmjs.com/package/hardhat-deploy#deploymentsdeploy
  from: deployer,
  args: [yourToken.address],
  log: true,
});

const vendor = await ethers.getContract(&quot;Vendor&quot;, deployer);

// Todo: transfer the tokens to the vendor
console.log(&quot;\n 🏵  Sending all 1000 tokens to the vendor...\n&quot;);

await yourToken.transfer(
  vendor.address,
  ethers.utils.parseEther(&quot;500&quot;) // Specify the amount of Token transferred to the Vendor.
);

// Assign new owner of Vendor contract
await vendor.transferOwnership(&quot;0xC0802222dB0F31d63dc85d9C8CAa00485715A13c&quot;);
"><code><span class="hljs-comment">// Todo: deploy the vendor</span>

await deploy(<span class="hljs-string">'Vendor'</span>, {
  <span class="hljs-comment">// Learn more about args here: https://www.npmjs.com/package/hardhat-deploy#deploymentsdeploy</span>
  <span class="hljs-keyword">from</span>: deployer,
  args: [yourToken.<span class="hljs-built_in">address</span>],
  log: <span class="hljs-literal">true</span>,
});

const vendor <span class="hljs-operator">=</span> await ethers.getContract(<span class="hljs-string">"Vendor"</span>, deployer);

<span class="hljs-comment">// Todo: transfer the tokens to the vendor</span>
console.log(<span class="hljs-string">"\n 🏵  Sending all 1000 tokens to the vendor...\n"</span>);

await yourToken.<span class="hljs-built_in">transfer</span>(
  vendor.<span class="hljs-built_in">address</span>,
  ethers.utils.parseEther(<span class="hljs-string">"500"</span>) <span class="hljs-comment">// Specify the amount of Token transferred to the Vendor.</span>
);

<span class="hljs-comment">// Assign new owner of Vendor contract</span>
await vendor.transferOwnership(<span class="hljs-string">"0xC0802222dB0F31d63dc85d9C8CAa00485715A13c"</span>);
</code></pre><p><strong>Note:</strong> You also need to uncomment the lines that transfers Token to your address in <code>packages/hardhat-ts/deploy/00_deploy_your_token.ts</code> or make the value smaller, like modifying it into 500.</p><p>After the change, run <code>yarn deploy --reset</code> to deploy the contract again.</p><p>Below is the output for successful deployment:</p><p>Vendor will initially have 500 tokens, and I am going to buy 10 tokens.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">Vendor Balance</figcaption></figure><p>It will need about 0.001 ETH.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">Buy Token</figcaption></figure><p>After the purchase, Vendor will have 490 tokens left, and ETH balanced is increased by 0.001. We can also see the event for Buy Token:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">New Balance</figcaption></figure><p>Withdraw ETH (Now the account has 0.0089 ETH)</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">Withdraw</figcaption></figure><p>Withdraw successfully (Now the account has 0.0098 ETH)</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">Withdraw Success</figcaption></figure><h2 id="h-0x05-vendor-buy-back" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x05 Vendor buy back</h2><p>Sometimes, we need to sell our Token and get ETH back. It will be great if Vendor can have this kind of operation.</p><p>Suppose here is the buy back steps:</p><ol><li><p>Token owner takes out some of the Token, call YourToken&apos;s <code>approve</code> function with Vendor&apos;s contract address and Token amount, means user allows Vendor to sell this amount of Token.</p></li><li><p>Then, user can call Vendor contract&apos;s <code>sellTokens</code> function based on the approved amount, and get back ETH to user&apos;s address.</p></li></ol><h3 id="h-51-yourtokens-approve-function" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">5.1 YourToken&apos;s <code>approve</code> function</h3><p>This funciton does not need to be implemented in YourToken&apos;s contract since it is inherited from <code>ERC20.sol</code>. (Codes below do not need to be copied to YourToken contract)</p><ul><li><p><code>_approve</code> is the main part of the logic. When user calls the method, <code>spender</code> will be the Vendor contract&apos;s address.</p></li><li><p>核心部分 <code>_allowances[owner][spender] = amount;</code> 负责在 YourToken 合约地址里面记录下用户允许 Vendor 获取的 Token 数量。</p></li><li><p>The core is <code>_allowances[owner][spender] = amount;</code> that records in the YourToken&apos;s address the amount of users&apos; Token amount that allows Vendor to get.</p><pre data-type="codeBlock" text=" function approve(address spender, uint256 amount) public virtual override returns (bool) {
    address owner = _msgSender();
    _approve(owner, spender, amount);
    return true;
}

function _approve(
    address owner,
    address spender,
    uint256 amount
) internal virtual {
    require(owner != address(0), &quot;ERC20: approve from the zero address&quot;);
    require(spender != address(0), &quot;ERC20: approve to the zero address&quot;);

    _allowances[owner][spender] = amount;
    emit Approval(owner, spender, amount);
}
"><code> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">approve</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> spender, <span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">virtual</span></span> <span class="hljs-title"><span class="hljs-keyword">override</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bool</span></span>) </span>{
    <span class="hljs-keyword">address</span> owner <span class="hljs-operator">=</span> _msgSender();
    _approve(owner, spender, amount);
    <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_approve</span>(<span class="hljs-params">
    <span class="hljs-keyword">address</span> owner,
    <span class="hljs-keyword">address</span> spender,
    <span class="hljs-keyword">uint256</span> amount
</span>) <span class="hljs-title"><span class="hljs-keyword">internal</span></span> <span class="hljs-title"><span class="hljs-keyword">virtual</span></span> </span>{
    <span class="hljs-built_in">require</span>(owner <span class="hljs-operator">!</span><span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>), <span class="hljs-string">"ERC20: approve from the zero address"</span>);
    <span class="hljs-built_in">require</span>(spender <span class="hljs-operator">!</span><span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>), <span class="hljs-string">"ERC20: approve to the zero address"</span>);

    _allowances[owner][spender] <span class="hljs-operator">=</span> amount;
    <span class="hljs-keyword">emit</span> Approval(owner, spender, amount);
}
</code></pre></li></ul><h3 id="h-52-vendors-selltokens-function" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">5.2 Vendor&apos;s <code>sellTokens</code> function:</h3><p>Copy the <code>SoldTokens</code> event and <code>sellTokens</code> function into Vendor.sol:</p><pre data-type="codeBlock" text="```solidity
// ToDo: create a sellTokens() function:
event SoldTokens(uint256 amountOfEth, uint256 amountOfTokens);

function sellTokens(uint256 tokenToSell) public {
  require(tokenToSell &gt; 0, &apos;You need to sell at least some tokens&apos;);

  // Calculate the needed ETH amount
  uint256 ethSold = tokenToSell / tokensPerEth;
  require(address(this).balance &gt; ethSold, &apos;Not enough ETH to buy from Vendor&apos;);

  // Transfer Token from user to Vendor contract
  yourToken.transferFrom(msg.sender, address(this), tokenToSell);

  payable(msg.sender).transfer(ethSold);

  emit SoldTokens(ethSold, tokenToSell);
}
"><code>```solidity
<span class="hljs-comment">// ToDo: create a sellTokens() function:</span>
<span class="hljs-function"><span class="hljs-keyword">event</span> <span class="hljs-title">SoldTokens</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> amountOfEth, <span class="hljs-keyword">uint256</span> amountOfTokens</span>)</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sellTokens</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> tokenToSell</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
  <span class="hljs-built_in">require</span>(tokenToSell <span class="hljs-operator">></span> <span class="hljs-number">0</span>, <span class="hljs-string">'You need to sell at least some tokens'</span>);

  <span class="hljs-comment">// Calculate the needed ETH amount</span>
  <span class="hljs-keyword">uint256</span> ethSold <span class="hljs-operator">=</span> tokenToSell <span class="hljs-operator">/</span> tokensPerEth;
  <span class="hljs-built_in">require</span>(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>).<span class="hljs-built_in">balance</span> <span class="hljs-operator">></span> ethSold, <span class="hljs-string">'Not enough ETH to buy from Vendor'</span>);

  <span class="hljs-comment">// Transfer Token from user to Vendor contract</span>
  yourToken.transferFrom(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>), tokenToSell);

  <span class="hljs-keyword">payable</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>).<span class="hljs-built_in">transfer</span>(ethSold);

  <span class="hljs-keyword">emit</span> SoldTokens(ethSold, tokenToSell);
}
</code></pre><pre data-type="codeBlock" text="
With the previous experience about `buyTokens`, we can easily understand `sellToken`. But the function of `yourToken.transferFrom` called within it needs to be looked at. `transferFrom`&apos;s implementation in `ERC20.sol` is like that (you do not need to copy them into YourToken.sol or Vendor.sol):
"><code>
<span class="hljs-type">With</span> the previous experience about `buyTokens`, we can easily understand `sellToken`. <span class="hljs-type">But</span> the function of `yourToken.transferFrom` called within it needs to be looked at. `transferFrom`'s implementation <span class="hljs-keyword">in</span> `<span class="hljs-type">ERC20</span>.sol` <span class="hljs-keyword">is</span> like that (you <span class="hljs-keyword">do</span> not need to <span class="hljs-keyword">copy</span> them into <span class="hljs-type">YourToken</span>.sol or <span class="hljs-type">Vendor</span>.sol):
</code></pre><pre data-type="codeBlock" text="function transferFrom(
    address from,
    address to,
    uint256 amount
) public virtual override returns (bool) {
    address spender = _msgSender();
    _spendAllowance(from, spender, amount);
    _transfer(from, to, amount);
    return true;
}

// check whether owner (Vendor contract) can get `msg.sender`&apos;s needed amount of Token.
function _spendAllowance(
    address owner,
    address spender,
    uint256 amount
) internal virtual {
    uint256 currentAllowance = allowance(owner, spender);
    if (currentAllowance != type(uint256).max) {
        require(currentAllowance &gt;= amount, &quot;ERC20: insufficient allowance&quot;);
        unchecked {
            _approve(owner, spender, currentAllowance - amount);
        }
    }
}

function _transfer(
    address from,
    address to,
    uint256 amount
) internal virtual {
    require(from != address(0), &quot;ERC20: transfer from the zero address&quot;);
    require(to != address(0), &quot;ERC20: transfer to the zero address&quot;);

    _beforeTokenTransfer(from, to, amount);

    uint256 fromBalance = _balances[from];
    require(fromBalance &gt;= amount, &quot;ERC20: transfer amount exceeds balance&quot;);
    unchecked {
        _balances[from] = fromBalance - amount;
    }
    _balances[to] += amount;

    emit Transfer(from, to, amount);

    _afterTokenTransfer(from, to, amount);
}
"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">transferFrom</span>(<span class="hljs-params">
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">from</span>,
    <span class="hljs-keyword">address</span> to,
    <span class="hljs-keyword">uint256</span> amount
</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">virtual</span></span> <span class="hljs-title"><span class="hljs-keyword">override</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bool</span></span>) </span>{
    <span class="hljs-keyword">address</span> spender <span class="hljs-operator">=</span> _msgSender();
    _spendAllowance(<span class="hljs-keyword">from</span>, spender, amount);
    _transfer(<span class="hljs-keyword">from</span>, to, amount);
    <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
}

<span class="hljs-comment">// check whether owner (Vendor contract) can get `msg.sender`'s needed amount of Token.</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_spendAllowance</span>(<span class="hljs-params">
    <span class="hljs-keyword">address</span> owner,
    <span class="hljs-keyword">address</span> spender,
    <span class="hljs-keyword">uint256</span> amount
</span>) <span class="hljs-title"><span class="hljs-keyword">internal</span></span> <span class="hljs-title"><span class="hljs-keyword">virtual</span></span> </span>{
    <span class="hljs-keyword">uint256</span> currentAllowance <span class="hljs-operator">=</span> allowance(owner, spender);
    <span class="hljs-keyword">if</span> (currentAllowance <span class="hljs-operator">!</span><span class="hljs-operator">=</span> <span class="hljs-keyword">type</span>(<span class="hljs-keyword">uint256</span>).<span class="hljs-built_in">max</span>) {
        <span class="hljs-built_in">require</span>(currentAllowance <span class="hljs-operator">></span><span class="hljs-operator">=</span> amount, <span class="hljs-string">"ERC20: insufficient allowance"</span>);
        <span class="hljs-keyword">unchecked</span> {
            _approve(owner, spender, currentAllowance <span class="hljs-operator">-</span> amount);
        }
    }
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_transfer</span>(<span class="hljs-params">
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">from</span>,
    <span class="hljs-keyword">address</span> to,
    <span class="hljs-keyword">uint256</span> amount
</span>) <span class="hljs-title"><span class="hljs-keyword">internal</span></span> <span class="hljs-title"><span class="hljs-keyword">virtual</span></span> </span>{
    <span class="hljs-built_in">require</span>(<span class="hljs-keyword">from</span> <span class="hljs-operator">!</span><span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>), <span class="hljs-string">"ERC20: transfer from the zero address"</span>);
    <span class="hljs-built_in">require</span>(to <span class="hljs-operator">!</span><span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>), <span class="hljs-string">"ERC20: transfer to the zero address"</span>);

    _beforeTokenTransfer(<span class="hljs-keyword">from</span>, to, amount);

    <span class="hljs-keyword">uint256</span> fromBalance <span class="hljs-operator">=</span> _balances[<span class="hljs-keyword">from</span>];
    <span class="hljs-built_in">require</span>(fromBalance <span class="hljs-operator">></span><span class="hljs-operator">=</span> amount, <span class="hljs-string">"ERC20: transfer amount exceeds balance"</span>);
    <span class="hljs-keyword">unchecked</span> {
        _balances[<span class="hljs-keyword">from</span>] <span class="hljs-operator">=</span> fromBalance <span class="hljs-operator">-</span> amount;
    }
    _balances[to] <span class="hljs-operator">+</span><span class="hljs-operator">=</span> amount;

    <span class="hljs-keyword">emit</span> Transfer(<span class="hljs-keyword">from</span>, to, amount);

    _afterTokenTransfer(<span class="hljs-keyword">from</span>, to, amount);
}
</code></pre><pre data-type="codeBlock" text="
Some key parts:

1. `internal` functions can only be called inside the contract or the child.
2. `virtual` functions means the method can be overwritten by the child.
3. ERC20 contract is to use a `_balances` mapping variable to store the amount of Token a address has. Transfer Token from one address to another, is to modify the value of the field in `_balances`.

   Let&apos;s see what sellTokens page works.

   Approve Vendor can sell this amount of Token:

   Sell Token to Vendor:

   Successfully with ETH (Now we have 0.0098 ETH)

## 0x06 Deploy contract to test networks

Now, `YourToken` and `Vendor`&apos;s contracts are all done, and tested in the local test network. Now we can deploy the contract to the public testnet or mainnet.

File `packages/hardhat-ts/hardhat.config.ts`

```typescript
// const defaultNetwork = &apos;localhost&apos;;
const defaultNetwork = &apos;ropsten&apos;;
"><code>
Some <span class="hljs-keyword">key</span> parts:

<span class="hljs-number">1</span>. `internal` functions can only be called inside the contract <span class="hljs-built_in">or</span> the child.
<span class="hljs-number">2</span>. `virtual` functions means the method can be overwritten <span class="hljs-keyword">by</span> the child.
<span class="hljs-number">3</span>. ERC20 contract <span class="hljs-built_in">is</span> <span class="hljs-keyword">to</span> use a `_balances` mapping variable <span class="hljs-keyword">to</span> store the amount <span class="hljs-keyword">of</span> Token a address has. Transfer Token <span class="hljs-keyword">from</span> one address <span class="hljs-keyword">to</span> another, <span class="hljs-built_in">is</span> <span class="hljs-keyword">to</span> modify the value <span class="hljs-keyword">of</span> the field <span class="hljs-keyword">in</span> `_balances`.

   <span class="hljs-keyword">Let</span><span class="hljs-comment">'s see what sellTokens page works.</span>

   Approve Vendor can sell this amount <span class="hljs-keyword">of</span> Token:

   Sell Token <span class="hljs-keyword">to</span> Vendor:

   Successfully <span class="hljs-keyword">with</span> ETH (Now we have <span class="hljs-number">0.0098</span> ETH)

## <span class="hljs-number">0</span>x06 Deploy contract <span class="hljs-keyword">to</span> test networks

Now, `YourToken` <span class="hljs-built_in">and</span> `Vendor`<span class="hljs-comment">'s contracts are all done, and tested in the local test network. Now we can deploy the contract to the public testnet or mainnet.</span>

File `packages/hardhat-ts/hardhat.config.ts`

```typescript
// <span class="hljs-keyword">const</span> defaultNetwork = <span class="hljs-comment">'localhost';</span>
<span class="hljs-keyword">const</span> defaultNetwork = <span class="hljs-comment">'ropsten';</span>
</code></pre><p>File <code>packages/vite-app-ts/src/config/providersConfig.ts</code></p><pre data-type="codeBlock" text="// export const targetNetworkInfo: TNetworkInfo = NETWORKS.local;
export const targetNetworkInfo: TNetworkInfo = NETWORKS.ropsten;
"><code>// export const targetNetworkInfo: <span class="hljs-attr">TNetworkInfo</span> = NETWORKS.local<span class="hljs-comment">;</span>
export const targetNetworkInfo: <span class="hljs-attr">TNetworkInfo</span> = NETWORKS.ropsten<span class="hljs-comment">;</span>
</code></pre><p>After modifying the previous files, you can deploy the contract to Ropsten with <code>yarn deploy</code> (you need to have ETH on Ropsten network). The following error may be threwed when deploying:</p><pre data-type="codeBlock" text="deploying &quot;Vendor&quot;replacement fee too low (error={&quot;name&quot;:&quot;ProviderError&quot;,&quot;code&quot;:-32000,&quot;_isProviderError&quot;:true}
"><code>deploying <span class="hljs-string">"Vendor"</span>replacement fee too low (<span class="hljs-type">error</span>={<span class="hljs-string">"name"</span>:<span class="hljs-string">"ProviderError"</span>,<span class="hljs-string">"code"</span>:<span class="hljs-number">-32000</span>,<span class="hljs-string">"_isProviderError"</span>:<span class="hljs-literal">true</span>}
</code></pre><p>This means the deployment operation is too fast, so that the transaction is sent too early and blocked. To solve this, you can seperate two deploy config files under <code>packages/hardhat-ts/deploy</code> into different folders.</p><p>Finally, run <code>yarn build</code> and <code>yarn surge</code> to build the front-end page, and deploy to Surge static file. Now we are all set!</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">thinkingincrowd</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">msfew</figcaption></figure>]]></content:encoded>
            <author>apecoder@newsletter.paragraph.com (Web3dAppDevCamp)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/9cb5da88fe2456a589702ed1286542b7de436f147792069c1b1bcd03a106a1a6.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[Using Github Pages to Serve Voxel as HTML by Using Template]]></title>
            <link>https://paragraph.com/@apecoder/using-github-pages-to-serve-voxel-as-html-by-using-template</link>
            <guid>Vu9Z8cThTpbMhBTjs0jU</guid>
            <pubDate>Sat, 05 Mar 2022 15:27:59 GMT</pubDate>
            <description><![CDATA[Author: qiwihuiIn this articles, we will show how to use Github pages to serve Voxel as HTML by using template. This HTML file will be used to mint our NFT. In the previous article, we have upload the voxel file to Arweave with Permaweb Dropper. And we got the permanent link of the voxel file, for example https://5ywn6daenz6poefpjkgs3c2vdgtzsk2vevam6aozkfzzzwrmgi.arweave.net/nFF3J4VB0BP9eHt35gdffGuwCXaHfXwtJl2K6u4GyA0. Now Let&apos;s use Github pages to serve the voxel file as HTML.0x01 Clone...]]></description>
            <content:encoded><![CDATA[<blockquote><p><strong>Author:</strong> <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/qiwihui">qiwihui</a></p></blockquote><p>In this articles, we will show how to use Github pages to serve Voxel as HTML by using template. This HTML file will be used to mint our NFT.</p><p>In the previous article, we have upload the voxel file to Arweave with Permaweb Dropper. And we got the permanent link of the voxel file, for example <code>https://5ywn6daenz6poefpjkgs3c2vdgtzsk2vevam6aozkfzzzwrmgi.arweave.net/nFF3J4VB0BP9eHt35gdffGuwCXaHfXwtJl2K6u4GyA0</code>. Now Let&apos;s use Github pages to serve the voxel file as HTML.</p><h2 id="h-0x01-clone-the-repository" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x01 Clone the repository</h2><p>First, we can navigate to the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/WeLightProject/voxel-viewer-page">WeLightProject/voxel-viewer-page</a> project. This is a template repository. We will use this template to create our own project.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/0181cacd6ce7dbdff4a58c932a01885e13f0590805c19aae9ba98e24e3588616.png" alt="use-this-template" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">use-this-template</figcaption></figure><p>Click the <code>use this template</code> button, and you will see the following page. We need to fill the repository name and description. Then just click the <code>Create repository from template</code> button. Then the repository will be created in a few seconds.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/d572168bca3f6cc95c96a767c3b35ee33ee24ffe6a0735c2089f30fc3bb03a87.png" alt="repository-info" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">repository-info</figcaption></figure><h2 id="h-0x02-replace-the-voxel-link-and-commit" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x02 Replace the voxel link and commit</h2><p>Second, we need to clone the repository. We can click the &quot;Clone&quot; button. Then wen can copy the link of the repository. For example, <code>https://github.com/qiwihui/MyDeerVoxel.git</code>.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/9f59114531497636d89220b164c61fbf8334ad1c04916026d2ab5be45dff7eba.png" alt="clone" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">clone</figcaption></figure><p>Then we can open a terminal and run the following command to clone the repository.</p><pre data-type="codeBlock" text="git clone https://github.com/qiwihui/MyDeerVoxel.git
cd MyDeerVoxel
"><code>git <span class="hljs-built_in">clone</span> https://github.com/qiwihui/MyDeerVoxel.git
<span class="hljs-built_in">cd</span> MyDeerVoxel
</code></pre><p>We need to replace the voxel link in the <code>handler.js</code> file. We can open the <code>handler.js</code> file in your IDE, and in the 19th line, we need to replace the link in <code>src</code> tag to the permanent link of the voxel file, which is <code>https://5ywn6daenz6poefpjkgs3c2vdgtzsk2vevam6aozkfzzzwrmgi.arweave.net/nFF3J4VB0BP9eHt35gdffGuwCXaHfXwtJl2K6u4GyA0</code>.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/1ce5f56db3d81cf536525da07e61dd016314482e666454e88e270a878fe121ab.png" alt="replace-link" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">replace-link</figcaption></figure><p>Then we need to commit the changes and push it to Github. We can run the following command to commit the changes.</p><pre data-type="codeBlock" text="git add .
git commit -m &quot;Add voxel file link&quot;
git push origin master
"><code>git add .
git commit <span class="hljs-operator">-</span>m <span class="hljs-string">"Add voxel file link"</span>
git push origin master
</code></pre><h2 id="h-0x03-deploy-to-github-pages" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x03 Deploy to Github Pages</h2><p>Finally, we need to setup the Github pages. We navigate to repository url and click <code>Settings</code>. Then we can click the <code>Pages</code> tab. We should choose the <code>main</code> branch. And then click <code>Save</code>.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/5ab7801a9ac03593607ff08f3e3343b83f6f4f6b80a8565ea7f4e7add050a83a.png" alt="choose-branch" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">choose-branch</figcaption></figure><p>The Github Pages will deploy your project automatically and you can see the website link when it is ready. For example, <code>https://qiwihui.github.io/MyDeerVoxel</code>.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/eb83dc48881c23bdcf35b3636ca026581d79cd5f2d536fe887f13b15433a610e.png" alt="view-the-link" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">view-the-link</figcaption></figure><p>We can now open the website in your browser. The website will show the voxel file.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/6be90993179021210f854109445c10c15b8eaa126a5fa11db8bc865c0770d772.png" alt="website-ready" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">website-ready</figcaption></figure><p>Cool! Now we can mint our NFT using deployed url.</p><p>we need three items:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/472d608dd5df38ee8a5d1e75e2549958db17613fcbadbd7683c6b317c93a1b00.png" alt="Index of dApp" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">Index of dApp</figcaption></figure><ul><li><p><strong>Voxel URI</strong> -- Uploaded by Permaweb Dropper</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://arweave.net/7izfDARufPcQr0qNLYtVGaeZK1UlQM8B_2VFznNosMs">https://arweave.net/7izfDARufPcQr0qNLYtVGaeZK1UlQM8B_2VFznNosMs</a></p></li><li><p>Github Pages URL -- You just generated</p></li><li><p>Commit Hash -- to make sure the github pages is not changed after NFT minted.</p></li></ul><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/2113a1b6fa3ab4c492f12d65877c3632bba72a387cd14f8be389c345d413f7c8.png" alt="How to find latest commit hash" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">How to find latest commit hash</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/b4e335b66a3220fbc3c3d41f536e384978eb731967fef830976f227521ca794a.png" alt="How to find latest commit hash" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">How to find latest commit hash</figcaption></figure>]]></content:encoded>
            <author>apecoder@newsletter.paragraph.com (Web3dAppDevCamp)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/826488d1b7bbe1af00038c966b0027bbb4d2570c6bb72fc0092e9915b3cdd0fe.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[RSS in Crypto@NonceGeekLab]]></title>
            <link>https://paragraph.com/@apecoder/rss-in-crypto-noncegeeklab</link>
            <guid>wMl7xvC8dNJICvuD4vj0</guid>
            <pubDate>Sun, 27 Feb 2022 05:52:02 GMT</pubDate>
            <description><![CDATA[Supported by NonceGeekLab <> PlayerLinkAttention: All articles by NonceGeekLab do not constitute any investment advice.PlayerLink: A Trustless Decentralized Web3-Oriented Service Aggregation Protocol. Through reliable, secure, and scalable technology, PlayerLink empowers billions to create and get a new service experience.NonceGeekLab: Focus on Crypto, the most interesting track in the world! https://github.com/WeLightProject/NonceGeekLabAuthors: msfew、leeduckgo、Erqi0x00 Key questionsGood que...]]></description>
            <content:encoded><![CDATA[<p><strong><em>Supported by NonceGeekLab &lt;&gt; PlayerLink</em></strong></p><blockquote><p><strong>Attention:</strong> <strong>All articles by NonceGeekLab do not constitute any investment advice.</strong></p></blockquote><blockquote><p><strong>PlayerLink:</strong></p><p>A Trustless Decentralized Web3-Oriented Service Aggregation Protocol. Through reliable, secure, and scalable technology, PlayerLink empowers billions to create and get a new service experience.</p></blockquote><blockquote><p><strong>NonceGeekLab:</strong></p><p>Focus on Crypto, the most interesting track in the world!</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/WeLightProject/NonceGeekLab">https://github.com/WeLightProject/NonceGeekLab</a></p></blockquote><blockquote><p><strong>Authors:</strong> msfew、leeduckgo、Erqi</p></blockquote><h2 id="h-0x00-key-questions" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x00 Key questions</h2><blockquote><p><strong>Good questions are the key for research</strong></p></blockquote><ul><li><p>Does Web3 need RSS?</p></li><li><p>What kind of economic model will Web3&apos;s RSS have?</p></li><li><p>What benefits can be given to users of Web3&apos;s RSS?</p></li></ul><h2 id="h-0x01-area-introduction" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x01 Area introduction</h2><blockquote><p>These are some objective analysis. The research is completed at January 2022, so some of the contents may not be updated.</p></blockquote><h3 id="h-11-introduction" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">1.1 Introduction</h3><p>In the Web3 era, user data is open source, and developers can go to a public database like the blockchain for free and quick retrieval of data such as NFTs, footprints, DAO members, etc. owned by users.</p><p>Web2 social media, such as Twitter, are also actively embracing Web3 NFT artwork as a new way to interact and socialize. And in the context of high blockchain transaction fees and a more limited environment for smart contracts to operate, it is difficult for us to have a complete decentralized social application on Ethereum or other chains at this stage.</p><p>OpenSea only provides a personal space for NFT display, Twitter only provides a personal space for Web2 tweets, Mirror only provides a display of articles, and even no native subscription function. Because of this, developers started with feed streams and created aggregators for Web3 content, bringing each platform together in one place, bringing secondary interactions to the blockchain, and gradually exploring the possibilities of decentralized social.</p><p>In our article, we will focus on the following Web3 feed projects: RSS3, CyberConnect, Project Galaxy, and Showme.</p><h3 id="h-12-questions" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">1.2 Questions</h3><p>For each project we can ask the following questions:</p><ol><li><p>is the project sufficiently Web3 (decentralized, open source, open data)?</p></li><li><p>the existing ecosystem and progress of the project?</p></li></ol><h3 id="h-13-rss3" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">1.3 RSS3</h3><blockquote><p>&quot;The feed of Web3&quot;</p></blockquote><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://rss3.io/RSS3-Whitepaper.pdf">Whitepaper</a></p><p>Let&apos;s know about RSS first before introducing RSS3.</p><h4 id="h-131-rss" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">1.3.1 RSS</h4><p>RSS is an information aggregating protocol that unifies the format of information distribution and content synchronization. Users can subscribe to a website&apos;s RSS feed to receive content updates sorted by timeline, thus aggregating content from all websites.</p><p>RSS is characterized by openness and neutrality. In the Web2 era, RSS lost its appeal to the average user with the creation of centralized platforms. A centralized platform began to do evil in the &quot;rodeo&quot; of user data, leading to privacy violations, algorithmic abuses, and data monopolies.</p><h4 id="h-132-rss3-introduction" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">1.3.2 RSS3 Introduction</h4><p>RSS3 is an underlying indexing and syndication protocol that aggregates both Web2 and Web3 content on top of RSS, enabling efficient and centralized content distribution. It is also redundance-tolerant and fault-tolerant, under the control of the user.</p><p>The difference between RSS3 and traditional social media, such as Facebook, is that it gives users control of their feeds back to them. Users have the autonomy to decide what content they receive, rather than being &quot;brainwashed&quot; by a recommendation system.</p><p>The RSS3 team members have a strong belief in decentralization, and many of them have blogged about it. In addition, DIYgod, the developer of the well-known open source project RSSHub, is also on the RSS3 team, providing a strong endorsement of the indexing and syndication technology used by RSS3.</p><h4 id="h-133-rss3-products" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">1.3.3 RSS3 Products</h4><ul><li><p><strong>rss3.bio（renamed to </strong><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://cheers.io"><strong>cheers.io</strong></a><strong> in 2022/02）</strong></p></li></ul><p>rss3.bio is the first application of RSS3. rss3.bio is similar to QQ space in the Web3 era, showing a user&apos;s entire on-chain footprint, including NFT records, Gitcoin donation records, and Twitter and Mirror posting records. Users can get their own RNS with $PASS tokens to create personalized domains like leeduckgo.rss3.bio.</p><p>rss3.bio is a very small and compact Web3 personal business card that shows users&apos; engagement with Web3 under one page. rss3.bio is relatively simple and currently only allows sharing business cards and following by domain name.</p><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://revery.so"><strong>revery.so</strong></a></p></li></ul><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://revery.so">revery.so</a> is a more complete application based on rss3.bio. <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://revery.so">revery.so</a> provides full RSS3 feed aggregation, and each user can bring social connections from rss3.bio to <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://revery.so">revery.so</a> to get their own feed stream.</p><h4 id="h-134-rss3-technical-architecture" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">1.3.4 RSS3 technical architecture</h4><p>The technical implementation of RSS3 includes the implementation of the protocol and the implementation of the applications implemented using the protocol.</p><ul><li><p><strong>RSS3 protocol</strong></p></li></ul><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/NaturalSelectionLabs/RSS3">RSS3 protocol</a> has interfaces and data structures for each address, and on-chain data such as personal information and NFT assets owned by the address are indexed to facilitate fast data acquisition and interface adaptation in the network.</p><p>Each of these addresses will have attributes such as id, profile avatar, personal link, etc.</p><ul><li><p><strong>RSS3 network</strong></p></li></ul><p>Based on separate RSS3 files for each address, the entire data network parses the RSS3 files for each address and organizes the network of relationships, and finally indexes accounts that are said to be encrypted or non-encrypted, storing this data on a blockchain network. the blockchain network for RSS3 is overseen by a DAO as well as distributed nodes.</p><p>Users interact with the application and receive feed streams from RSS3&apos;s network, while the application interacts directly with the RSS3 network to submit user data that needs to be updated to the network.</p><ul><li><p><strong>rss3.bio and </strong><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://revery.so"><strong>revery.so</strong></a></p></li></ul><p>The source code of rss3.bio and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://revery.so">revery.so</a> are both in the RSS3 development group&apos;s GitHub account, and both are front-end applications that use the TypeScript language and the Vue or NextJS frameworks. The structure of the application is not complicated, in short, it consists of two main parts: taking data and styling it.</p><p>Since the RSS3 protocol has already organized the data very neatly, the front-end application can quickly build a Web3 social application with this same set of data. We can get the user data from the RSS3 network very easily and quickly by using a function like this.</p><pre data-type="codeBlock" text="async function getRecommendGroupMembers(type: string) {
  try {
    const res: RecommendationUsersResponse = (
      await axios.get(&apos;/recommendation/list&apos;, {
        baseURL: config.recommendations.endpoint,
        params: {
          type,
          limit: config.recommendations.userLimit,
        },
      })
    ).data;
    return &lt;RSS3Index[]&gt;res.response.filter((member) =&gt; member !== null); // What&apos;s wrong with you dude?
  } catch (e) {
    console.log(e);
  }
  return [];
}
"><code>async <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getRecommendGroupMembers</span>(<span class="hljs-params"><span class="hljs-keyword">type</span>: <span class="hljs-keyword">string</span></span>) </span>{
  <span class="hljs-keyword">try</span> {
    const res: RecommendationUsersResponse <span class="hljs-operator">=</span> (
      await axios.get(<span class="hljs-string">'/recommendation/list'</span>, {
        baseURL: config.recommendations.endpoint,
        params: {
          <span class="hljs-keyword">type</span>,
          limit: config.recommendations.userLimit,
        },
      })
    ).data;
    <span class="hljs-keyword">return</span> <span class="hljs-operator">&#x3C;</span>RSS3Index[]<span class="hljs-operator">></span>res.response.filter((member) <span class="hljs-operator">=</span><span class="hljs-operator">></span> member <span class="hljs-operator">!</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span> null); <span class="hljs-comment">// What's wrong with you dude?</span>
  } <span class="hljs-keyword">catch</span> (e) {
    console.log(e);
  }
  <span class="hljs-keyword">return</span> [];
}
</code></pre><p>Then, once you have the data, just render it in the page component:</p><pre data-type="codeBlock" text="    const getRecommendationGroups = async (type: string) =&gt; {
        setIsLoadingRecommendGroupMembers(true);
        const recommendGroupMemberIndexes = await RSS3.getRecommendGroupMembers(type);
...
"><code>    const getRecommendationGroups <span class="hljs-operator">=</span> async (<span class="hljs-keyword">type</span>: <span class="hljs-keyword">string</span>) <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
        setIsLoadingRecommendGroupMembers(<span class="hljs-literal">true</span>);
        const recommendGroupMemberIndexes <span class="hljs-operator">=</span> await RSS3.getRecommendGroupMembers(<span class="hljs-keyword">type</span>);
...
</code></pre><p>It is very easy to develop social applications under the provisions of the open and neutral RSS3 protocol.</p><h4 id="h-135-answers" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">1.3.5 Answers</h4><ol><li><p>Is the project sufficiently Web3 (decentralized, open source, open data)?</p></li></ol><p>RSS itself is a very neutral and open protocol, but in the current web culture, the survival space of RSS is getting smaller and smaller. RSS3 has been strengthened and reborn in the Web3 era, and as an open and unified protocol, RSS3 can help applications to get unified data very well, and will promote the development of the whole ecosystem as well as the ERC standard of Ethereumw.</p><p>For the decentralized property of RSS3, I think the team&apos;s concept and the architecture of the blockchain network are very good. However, I did not have access to specific information about the DAO architecture and nodes of the blockchain network. If this information can also be published, then it will reach the true decentralized network properties.</p><p>For open source, RSS3 members are active contributors on GitHub, and almost all projects are open source for developers to learn and view, which is something that is very much in the DNA of Web3.</p><p>For open data, I don&apos;t currently have access to developer documentation or an open interface to use. I think a better approach is to open up the data for developers to use and build applications first, rather than constructing applications by using the data first. Of course, in the future, when RSS3 develops its own projects that use its protocols to gain a foothold in Web3, RSS3 will certainly make the data public, which is a very good thing.</p><ol><li><p>The current ecosystem and progress of the project?</p></li></ol><p>Web3Pass, which went live in September 2021, currently(January 2022) has 35,000 individual pages. In January 2022, the official RSS3 white paper was released.</p><h3 id="h-14-cyberconnect" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">1.4 CyberConnect</h3><blockquote><p>&quot;Connect everyone on Web3&quot;</p></blockquote><h4 id="h-141-cyberconnect-introduction" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">1.4.1 CyberConnect introduction</h4><p>CyberConnect is also a content aggregation and indexing protocol. CyberConnect&apos;s mission is to build a social relationship graph infrastructure for Web3, returning ownership of social data to users while providing an infrastructure for all Web3 developers to integrate and build.</p><p>CyberConnect&apos;s emphasis is not only on aggregating data on the chain together, but more importantly, on empowering users with the Web3 social relationships through decentralized storage. It&apos;s as much about the on-chain interactions that the user has at their address as it is about the data they have that they can take with them through the Web3 world. For example, Twitter followers and followers can be brought directly into the CyberConnect application, and interactions in CyberConnect can be brought into other social applications.</p><p>CyberConnect believes that Web3 will be developer-driven, so what they are doing is aggregating and indexing decentralized social relationships, and then handing them off to different projects to be presented on the front end.</p><h4 id="h-142-cyberconnect-projects" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">1.4.2 Cyberconnect projects</h4><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://Cyberconnect.me"><strong>Cyberconnect.me</strong></a></p></li></ul><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://Cyberconnect.me">Cyberconnect.me</a> is similar to RSS3&apos;s two products in that it aggregates data and presents social connections on the chain.</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://Cyberconnect.me">Cyberconnect.me</a> uses a recommendation engine to better recommend potential user interactions, which is more in line with most users&apos; habits. It also provides the ability to comment on users&apos; homepages, allowing secondary interactions to be truly reflected in the Web3 Feed product.</p><ul><li><p><strong>CyberChat</strong></p></li></ul><p>CyberChat is a real-time communication application based on CyberConnect&apos;s social graphs and is still in development.</p><h4 id="h-143-cyberconnect-architecture" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">1.4.3 CyberConnect architecture</h4><ul><li><p><strong>CyberConnect Indexer</strong></p></li></ul><p>The open source code of this project is available at <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/cyberconnecthq/indexer">this repository</a>. Indexer open-sources the method of aggregating and indexing data from various social networks. We can access the data we need through the contract addresses and APIs of each different platform:.</p><pre data-type="codeBlock" text="const (
    SuperrareContractAddress  = &quot;0x41a322b28d0ff354040e2cbc676f0320d8c8850d&quot;
    OpenSeaContractAddress    = &quot;0x495f947276749ce646f68ac8c248420045cb7b5e&quot;
    RaribleContractAddress    = &quot;0xd07dc4262bcdbf85190c01c996b4c06a461d2430&quot;
    FoundationContractAddress = &quot;0x3b3ee1931dc30c1957379fac9aba94d1c48a5405&quot;
    ZoraContractAddress       = &quot;0xabefbc9fd2f806065b4f3c237d4b59d9a97bcac7&quot;
    ContextContractAddress    = &quot;ctx&quot;
)

const (
    ContextUrl          = &quot;https://context.app/api/profile/%s&quot;
    SuperrareUrl        = &quot;https://superrare.com/api/v2/user?address=%s&quot;
    RaribleFollowingUrl = &quot;https://api-mainnet.rarible.com/marketplace/api/v4/followings?owner=%s&quot;
    RaribleFollowerUrl  = &quot;https://api-mainnet.rarible.com/marketplace/api/v4/followers?user=%s&quot;
)
"><code>const (
    <span class="hljs-attr">SuperrareContractAddress</span>  = <span class="hljs-string">"0x41a322b28d0ff354040e2cbc676f0320d8c8850d"</span>
    <span class="hljs-attr">OpenSeaContractAddress</span>    = <span class="hljs-string">"0x495f947276749ce646f68ac8c248420045cb7b5e"</span>
    <span class="hljs-attr">RaribleContractAddress</span>    = <span class="hljs-string">"0xd07dc4262bcdbf85190c01c996b4c06a461d2430"</span>
    <span class="hljs-attr">FoundationContractAddress</span> = <span class="hljs-string">"0x3b3ee1931dc30c1957379fac9aba94d1c48a5405"</span>
    <span class="hljs-attr">ZoraContractAddress</span>       = <span class="hljs-string">"0xabefbc9fd2f806065b4f3c237d4b59d9a97bcac7"</span>
    <span class="hljs-attr">ContextContractAddress</span>    = <span class="hljs-string">"ctx"</span>
)

const (
    <span class="hljs-attr">ContextUrl</span>          = <span class="hljs-string">"https://context.app/api/profile/%s"</span>
    <span class="hljs-attr">SuperrareUrl</span>        = <span class="hljs-string">"https://superrare.com/api/v2/user?address=%s"</span>
    <span class="hljs-attr">RaribleFollowingUrl</span> = <span class="hljs-string">"https://api-mainnet.rarible.com/marketplace/api/v4/followings?owner=%s"</span>
    <span class="hljs-attr">RaribleFollowerUrl</span>  = <span class="hljs-string">"https://api-mainnet.rarible.com/marketplace/api/v4/followers?user=%s"</span>
)
</code></pre><pre data-type="codeBlock" text="func sendRequest(client *http.Client, args RequestArgs) ([]byte, error) {
    var req *http.Request
    var err error

    switch args.method {
    case &quot;GET&quot;:
        req, err = http.NewRequest(args.method, args.url, nil)
        if err != nil {
            return nil, err
        }
        for k, v := range args.header {
            req.Header.Add(k, v)
        }
        query := req.URL.Query()
        for k, v := range args.params {
            query.Add(k, v)
        }
        req.URL.RawQuery = query.Encode()
...
"><code>func sendRequest(client <span class="hljs-operator">*</span>http.Client, args RequestArgs) ([]<span class="hljs-keyword">byte</span>, <span class="hljs-function"><span class="hljs-keyword">error</span>) </span>{
    <span class="hljs-keyword">var</span> req <span class="hljs-operator">*</span>http.Request
    <span class="hljs-keyword">var</span> err <span class="hljs-function"><span class="hljs-keyword">error</span>

    <span class="hljs-title">switch</span> <span class="hljs-title">args</span>.<span class="hljs-title">method</span> </span>{
    case <span class="hljs-string">"GET"</span>:
        req, err <span class="hljs-operator">=</span> http.NewRequest(args.method, args.url, nil)
        <span class="hljs-keyword">if</span> err <span class="hljs-operator">!</span><span class="hljs-operator">=</span> nil {
            <span class="hljs-keyword">return</span> nil, err
        }
        <span class="hljs-keyword">for</span> k, v :<span class="hljs-operator">=</span> range args.header {
            req.Header.Add(k, v)
        }
        query :<span class="hljs-operator">=</span> req.URL.Query()
        <span class="hljs-keyword">for</span> k, v :<span class="hljs-operator">=</span> range args.params {
            query.Add(k, v)
        }
        req.URL.RawQuery <span class="hljs-operator">=</span> query.Encode()
...
</code></pre><p>Such an approach is more customizable and flexible than RSS3, but is not as out-of-the-box as RSS3 and may require manual deployment and debugging by the developer.</p><ul><li><p><strong>CyberConnect packages</strong></p></li></ul><p>The source code for the CyberConnect npm library is available at <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/cyberconnecthq/js-cyberconnect">this repository</a>. This library provides CyberConnect classes that include functions for DID and interactive social graph data, encapsulating complex authentication logic into easy-to-use functions. Developers can use this library for social software development.</p><h4 id="h-144-answers" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">1.4.4 Answers</h4><ol><li><p>Is the project sufficiently Web3 (decentralized, open source, open data)?</p></li></ol><p>CyberConnect is more of a developer-oriented project, and it opens up the interface to the ceramic network for developers to use faster than RSS3.</p><p>For decentralization, the Ceramic used by CyberConnect is a decentralized network that uses IPFS for storage.</p><p>For open source, the third-party libraries and indexer for the CyberConnect project are open source, but the rest of the client code is not.</p><p>For open data, CyberConnect has opened up its own data for developers to use.</p><ol><li><p>What is the current ecosystem and progress of the project?</p></li></ol><p>Currently Cyberconnect&apos;s client has 38w users, and the account with the most followers has more than 1w followers.</p><h3 id="h-15-project-galaxy" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">1.5 Project Galaxy</h3><blockquote><p>&quot;Build better communities in Web3&quot;</p></blockquote><p>Project Galaxy is an NFT-as-a-service infrastructure platform that allows anyone to create, distribute, or gamify NFTs at will using custom on-chain data, developers to create custom loyalty programs, and individuals to distribute and subscribe to NFTs.</p><p>Project Galaxy is similar to OpenSea in that it aggregates various families of NFTs, features NFT showcases and follows users, and more. It also includes an aggregation page for activities such as AMA, which makes it more intuitive and easy to follow the trends and progress of each eco-community.</p><h3 id="h-16-showme" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">1.6 Showme</h3><blockquote><p>&quot;A subscription NFT social network built on Web3&quot;</p></blockquote><p>Showme provides subscriptions to communities such as NFT to follow, allowing users to more closely engage and stay up to date with community trends. Whenever a user subscribes to a new community, a new NFT is Minted and used as an on-chain credential. At the same time, community credentials on different chains are separate from the communities themselves.</p><p>Showme&apos;s on-chain footprint index uses the protocol provided by RSS3 for crawling.</p><h3 id="h-17-rss3-cyberconnect-project-galaxy-showme" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">1.7 RSS3, CyberConnect, Project Galaxy, Showme</h3><p>Both RSS3 and CyberConnect are protocols for capturing on-chain and off-chain data to do so, bridging the silos of data across Web3&apos;s blockchain networks. They form a social data network that belongs entirely to users and uses decentralized storage that can be used by different projects.</p><p>CyberConnect is more advanced than RSS3 and is more Web2 social, with personal page likes and soon a live chat feature.</p><p>The other difference is that RSS3 has RSS as its main component, which means that RSS3 has a natural contradiction with the recommendation system and the list of recommended followers on <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://revery.so">revery.so</a> is randomly generated; Cyberconnect is more flexible and uses a recommendation system to better capture users&apos; possible preferences and anticipate their next actions.</p><p>NFT is an important part of social in the Web3 era, and Project Galaxy and Showme focus on cultivating NFT communities, with Project Galaxy working closely with Cyberconnect and Showme working closely with RSS3. Project Galaxy focuses on community activities such as AMA of service projects, while Showme focuses on spontaneous communication and announcement of service communities.</p><h2 id="h-0x02-noncegeek-views" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x02 NonceGeek views</h2><blockquote><p><strong>This chapter describes the subjective view of NonceGeek.</strong></p></blockquote><blockquote><p>RSS is a web feed that allows users and applications to access updates to websites in a standardized, computer-readable format. Subscribing to RSS feeds can allow a user to keep track of many different websites in a single news aggregator, which constantly monitor sites for new content, removing the need for the user to manually check them. News aggregators (or &quot;RSS readers&quot;) can be built into a browser, installed on a desktop computer, or installed on a mobile device.</p><p>-- Wikipedia</p></blockquote><p>RSS originated in the early days of the Internet era, before the existence of giant whales of apps like today (Facebook, Twitter, Google, Tencent, TikTok......). People used RSS to parse their favorite feeds.</p><p>With the development of the Internet, various App whales have emerged, and we just need to register an account, and the App will feed us information. We no longer need to customize our own feeds. App will &quot;continuously push&quot; based on our browsing preferences...... So, RSS is gradually being eliminated by history.</p><p>This is certainly an inevitable process.</p><p>However, there are some interesting questions to ponder. Is this inevitable process the &quot;right&quot; one, and is RSS likely to be revived? And if so, what will the new generation of RSS look like?</p><h3 id="h-21-the-humane-and-right" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2.1 The &quot;humane&quot; and &quot;right&quot;</h3><p>Too often, we believe that &quot;survival of the fittest&quot; means that those who survive are naturally right.</p><p>However, this crude judgment is problematic. Very often, what survives is &quot;in line with human nature&quot;, not &quot;right&quot;.</p><p>For example, if we think &quot;healthy food = right, unhealthy food = wrong&quot;. The reason why fast food has survived so well in the world is not because it is right, but because it responds to human nature.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">216,501 Hamburger Stock Photos, Pictures &amp; Royalty-Free Images - iStock</figcaption></figure><p>Similarly, why is it that &quot;recommendation algorithm-based apps&quot; are alive and well, but RSS is dying out?</p><p>I think it&apos;s because...</p><p>The App based on recommendation algorithm is in line with human nature, but it doesn&apos;t make it right.</p><p>As the old saying goes, &quot;good advice often jars on the ear,&quot; and saying nice things is human nature and will be liked naturally.</p><p>Likewise, recommending content based on your existing preferences is human nature and will be naturally liked.</p><p>However, just as being addicted to fast food can make us less and less healthy, being caught up in recommendation algorithms can affect our &quot;mental health&quot; as well.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">推荐系统下的喜好加强模型(EN)</figcaption></figure><p>We can draw a simple model to describe it.</p><p>Suppose initially I show &quot;Preference A&quot; and &quot;Preference B&quot; in the App (e.g. TikTok), then the App will keep recommending me content of &quot;Preference A&quot; and &quot;Preference B&quot;, thus reinforcing my preference for &quot;Preference A&quot; and &quot;Preference B&quot;, and then the cycle continues......</p><p>It&apos;s naturally in the App&apos;s interest for users to get caught up in their existing preferences - because they stick to the App.</p><p><strong>But is it really in the user&apos;s interest?</strong></p><p>I was addicted to soap operas for a while, so my timeline was full of soap operas. Then suddenly one day I broke away. I wanted to cut ties with soap operas, but the app still pushed soap operas based on my preferences.</p><p>This is the essence of the recommendation algorithm - <strong>&quot;to keep strengthening your existing preferences, creating stickiness to your existing preferences, which in turn becomes stickiness to the App&quot;</strong>.</p><p>We can see that its essence is closed and not open at the spiritual level. After a long period of time under the system of &quot;recommendation algorithm&quot;, we will eventually come to a state - we no longer make changes to our preferences, but the existing preferences keep increasing.</p><p><strong>Even if we link the Internet, we will still become one closed system after another.</strong></p><p>The opposite is RSS, which is absolutely anti-human, requiring you to get your own subscription feeds and then manage them manually on your own - similar to how we go about making complicated dishes at home.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">RSS 下的模型（EN）</figcaption></figure><p>However, this sacrifice is rewarded with an open and comfortable information system!</p><p>As shown above, in the RSS-based system, we have Preference A and Preference B. We are free to control the &quot;traffic&quot; of each preference, let&apos;s say 100 messages per day for &quot;Preference A&quot; and 50 messages per day for &quot;Preference B&quot;. I used to like &quot;fishing&quot; and subscribed to a lot of &quot;fishing&quot; related feeds, but now I don&apos;t like it anymore, Ok, cut all the related &quot;feeds&quot;!</p><p>TimeLine is instantly clean.</p><p>Therefore, this system is <strong>&quot;open&quot;</strong>, and people who use this system will also have <strong>&quot;high openness&quot;</strong>.</p><p>Openness is the essential spirit of the Internet, isn&apos;t it?</p><h3 id="h-22-is-it-possible-for-rss-to-be-revived" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2.2 Is it possible for RSS to be revived?</h3><p>The road to RSS revival may be a tortuous one, but in the long run RSS will regain a larger market.</p><p>But one key factor is that there are &quot;incentives&quot; to offset the &quot;costs of hassle&quot; associated with RSS use, depending on the design. We can divide the incentives into &quot;economic incentives&quot; and &quot;non-economic incentives&quot;.</p><ul><li><p><strong>Economic Incentives</strong></p><p>There is a financial incentive for providing a good RSS feed, which may be created by the provider or integrated by the provider.</p></li><li><p><strong>Non-financial Incentives</strong></p><p>For example, reputation in the Crypto world, etc.</p></li></ul><h3 id="h-23-what-does-a-base-on-blockchainweb3-rss-look-like" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2.3 What does a Base on Blockchain/Web3 RSS look like?</h3><p>The following is purely a personal opinion.</p><h4 id="h-231-the-redefined-personal-blog" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">2.3.1 The redefined personal blog</h4><p>A personal blog is a blog with its own domain name that is not dependent on any blogging platform.</p><p>Although personal blogs have declined in China (only some of the tech leads are still running and maintaining blogs), there are still many personal bloggers from a global perspective.</p><p>In the Crypto world, we can redefine blogging, which is supposed to be an important source of information for RSS. So it seems we should talk about a &quot;blogging renaissance&quot; before a RSS renaissance? But that&apos;s another topic.</p><p>Here&apos;s a brief list of possible ways Crypto blogs could play out.</p><ul><li><p>The Crypto identity of the blogger can be seen</p></li><li><p>The ability to aggregate the blogger&apos;s NFTs</p></li><li><p>Can aggregate the blogger&apos;s multiple Web3 dApp content, such as Mirror</p></li><li><p>If the blogger is a technical blogger, it can show the Web3 projects the blogger is involved in</p></li><li><p>There can be a gateway to the Crypto World/Metaverse where the blogger resides</p></li><li><p>Finally, of course, the blogger can provide RSS feeds</p></li></ul><h4 id="h-232-penetrating-revenue-and-traceable-re-creation" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">2.3.2 Penetrating revenue and traceable re-creation</h4><p>This is different from the Web2 RSS system. Because it&apos;s based on blockchain, the new generation of RSS is technically &quot;revenue-penetrating&quot; and &quot;re-creation-traceable&quot;.</p><p>In other words, through smart contracts, the creators and distributors of RSS feeds, original works and re-creations can both receive revenue, so that the new generation of RSS can really carry &quot;tangible value&quot; and thus offset the &quot;cost of trouble&quot; brought about by the use of RSS.</p><p>However, the proposition of blockchain empowering creators has been mentioned for years, but we have not seen any particularly successful product. Is this because the previous products were not designed from the perspective of &quot;RSS revival&quot;? This requires further thought and discussion.</p><h2 id="h-0x03-secondary-development-practice" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x03 Secondary development practice</h2><blockquote><p><strong>Performing secondary development practices is a mean to gain a deeper understanding of the product.</strong></p></blockquote><h3 id="h-31-rss3-architecture" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">3.1 RSS3 architecture</h3><blockquote><p><strong>Pics Got From:</strong> <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/diygod/status/1492462952322109444?s=21">https://twitter.com/diygod/status/1492462952322109444?s=21</a></p></blockquote><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/b54bbbcb63aee5385205e7550e8eb68874d538285c77b2ad14db29937ffa4d76.jpg" alt="Image" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">Image</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/984a0ae88aa90d2d6afc566f13ddb83ed957873e7a8f3424104f91c46d9e936c.jpg" alt="Image" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">Image</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/efa081ee9cd855ec1fa7ea88d29e88f97b98727faebd18008830d827122c6635.jpg" alt="Image" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">Image</figcaption></figure><h3 id="h-32-development-ideas" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">3.2 Development ideas</h3><p>Because the RSS3 data are publicly available:</p><blockquote><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/NaturalSelectionLabs/RSS3-Network-Data">https://github.com/NaturalSelectionLabs/RSS3-Network-Data</a></p></blockquote><p>So it is easy to implement RSS3-based projects through the SDK or directly through the API interface. Here, we implement an example of an on-chain resume incorporating Markdown documents in <code>rss3.bio</code> (now renamed <code>cheers.bio</code>);</p><blockquote><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://erqi.github.io/Web3Pass/#/">https://erqi.github.io/Web3Pass/#/</a></p></blockquote><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">image-20220226224246371</figcaption></figure><p>The source code is available at;</p><blockquote><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ErQi/Web3Pass/tree/resume">https://github.com/ErQi/Web3Pass/tree/resume</a></p></blockquote><h3 id="h-33-practices" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">3.3 Practices</h3><p>The Footprint area of the original project was removed and filled with Content. Then a custom Markdown component was introduced to complement the Content area.</p><h4 id="h-331-add-markdownvue" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">3.3.1 Add Markdown.vue</h4><p>This component group is to be used to load the content display of Markdown.</p><p>Loading mechanism</p><pre data-type="codeBlock" text="    Get markdown content -&gt; Process into markdown html format -&gt; Render by introducing markdown style file
"><code>    Get markdown content <span class="hljs-operator">-</span><span class="hljs-operator">></span> Process into markdown html format <span class="hljs-operator">-</span><span class="hljs-operator">></span> Render by introducing markdown style file
</code></pre><h4 id="h-332-get-markdown-content" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">3.3.2 Get markdown content</h4><p>Here we have two forms of fetching. We get it from local files and github api respectively.</p><p><strong>Local loading method</strong></p><p>To load locally, you need webpack to recognize the md file, and you need to configure the corresponding loader. Add the <code>html-loader</code> package dependency via npm, and then configure the corresponding loader in the <code>rules</code> section of the <code>webpack.config.js</code> configuration file.</p><pre data-type="codeBlock" text="            {
                test: /\.md$/,
                use: [
                    {
                        loader: &apos;html-loader&apos;,
                    },
                ],
            },
"><code>            {
                test: <span class="hljs-operator">/</span>\.md$/,
                use: [
                    {
                        loader: <span class="hljs-string">'html-loader'</span>,
                    },
                ],
            },
</code></pre><p>Once configured, you can import the local md file via <code>import</code> to get the corresponding content. To load locally, you need to modify the <code>v-html</code> attribute of the <code>article</code> tag in <code>Markdown.vue</code>.</p><pre data-type="codeBlock" text="import md from &apos;@/assets/RSS3源码分析.md&apos;;

...

    &lt;article className=&quot;markdown-body&quot; v-html=&quot;compiledMarkdown&quot;&gt;&lt;/article&gt;
"><code><span class="hljs-keyword">import</span> <span class="hljs-title">md</span> <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'@/assets/RSS3源码分析.md'</span>;

...

    <span class="hljs-operator">&#x3C;</span>article className<span class="hljs-operator">=</span><span class="hljs-string">"markdown-body"</span> v<span class="hljs-operator">-</span>html<span class="hljs-operator">=</span><span class="hljs-string">"compiledMarkdown"</span><span class="hljs-operator">></span><span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>article<span class="hljs-operator">></span>
</code></pre><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://blog.csdn.net/Boring_Wednesday/article/details/78651631">Create your own GitHub repository quickly</a></p><p><strong>Network loading method</strong></p><p>The network load uses the github api to get the content of the file in the corresponding path. The use of the api is not described in detail. The normal content is base64 encoded. So we add a <code>base64</code> file to decode it.</p><pre data-type="codeBlock" text="        axios.get(config.mdUrl).then((response) =&gt; {
            this.mdText = response.data.content;
            this.mdText = BASE64Util.base64_decode(this.mdText);
            this.mdText = marked(this.mdText || &apos;&apos;, {
                sanitize: true,
            });
            console.log(this.mdText);
        });
"><code>        axios.get(config.mdUrl).then((response) <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
            <span class="hljs-built_in">this</span>.mdText <span class="hljs-operator">=</span> response.data.content;
            <span class="hljs-built_in">this</span>.mdText <span class="hljs-operator">=</span> BASE64Util.base64_decode(<span class="hljs-built_in">this</span>.mdText);
            <span class="hljs-built_in">this</span>.mdText <span class="hljs-operator">=</span> marked(<span class="hljs-built_in">this</span>.mdText <span class="hljs-operator">|</span><span class="hljs-operator">|</span> <span class="hljs-string">''</span>, {
                sanitize: <span class="hljs-literal">true</span>,
            });
            console.log(<span class="hljs-built_in">this</span>.mdText);
        });
</code></pre><p>Also, the <code>v-html</code> attribute of the <code>article</code> tag in <code>Markdown.vue</code> uses the parsed <code>mdText</code> attribute directly.</p><pre data-type="codeBlock" text="    &lt;article className=&quot;markdown-body&quot; v-html=&quot;mdText&quot;&gt;&lt;/article&gt;
"><code>    <span class="hljs-operator">&#x3C;</span>article className<span class="hljs-operator">=</span><span class="hljs-string">"markdown-body"</span> v<span class="hljs-operator">-</span>html<span class="hljs-operator">=</span><span class="hljs-string">"mdText"</span><span class="hljs-operator">></span><span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>article<span class="hljs-operator">></span>
</code></pre><p>The default load file path is configured in the <code>/mdUrl</code> property of the <code>/src/config.ts</code> file.</p><pre data-type="codeBlock" text="// The standard format is as follows.
https://api.github.com/repos/WeLightProject/WeLightBlockchainOS/contents/README.md?ref=main
// https://api.github.com/repos/{organization/username}/{projectname}/contents/{folderpath,name}?ref={branchname}
"><code>/<span class="hljs-regexp">/ The standard format is as follows.
https:/</span><span class="hljs-regexp">/api.github.com/repos</span><span class="hljs-regexp">/WeLightProject/</span><span class="hljs-title class_">WeLightBlockchain</span>OS/contents/<span class="hljs-variable constant_">README</span>.md?ref=main
/<span class="hljs-regexp">/ https:/</span><span class="hljs-regexp">/api.github.com/repos</span><span class="hljs-regexp">/{organization/username</span>}/{projectname}/contents/{folderpath,name}<span class="hljs-string">?r</span>ef={branchname}
</code></pre><p><strong>Processing to html format</strong></p><p>The markdown content into html format requires the <code>marked</code> library, which can be imported and used after adding the dependencies via npm. Baidu&apos;s import is without brackets, but here without brackets it will report an error, the reason is unknown, I also saw this import method in other files, so I tried to add brackets, only to solve the problem that has been reported as unable to import.</p><p>After importing the original md content directly as parameters passed in, the return is the content of the html format</p><pre data-type="codeBlock" text="import { marked } from &apos;marked&apos;;

            .....

            marked(md || &apos;&apos;, {
                sanitize: true,
            })
"><code><span class="hljs-keyword">import</span> { <span class="hljs-title">marked</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'marked'</span>;

            .....

            marked(md <span class="hljs-operator">|</span><span class="hljs-operator">|</span> <span class="hljs-string">''</span>, {
                sanitize: <span class="hljs-literal">true</span>,
            })
</code></pre><p><strong>Introduce css style rendering</strong></p><p>Introduce the <code>markdown-it-vue</code> dependency via npm, and then import the following style.</p><pre data-type="codeBlock" text="import &apos;markdown-it-vue/dist/markdown-it-vue.css&apos;;
"><code><span class="hljs-keyword">import</span> <span class="hljs-string">'markdown-it-vue/dist/markdown-it-vue.css'</span>;
</code></pre><p>I wanted to use a third-party component to display vue directly in one step, but after I introduced it, I got all kinds of errors. The reason is unknown. I suspect it&apos;s because the current vue version is 5.x. Because in the <code>markdown-it-vue</code> issue, I saw that vue 5.x version was reporting errors when importing. The error message is not the same though. I&apos;ve tried all the other markdown rendering and editing components, but it&apos;s just a mess of errors. It doesn&apos;t work properly.</p><p>So finally I had to go for <code>introduce basic content-&gt;convert html format-&gt;css style rendering</code> basic processing to handle it.</p><h4 id="h-333-fixed-home-pages-access-address" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">3.3.3 Fixed home page&apos;s access address</h4><p>In the original project, the wallet address is used to capture user data and then visit the home page of the wallet user. In the case of on-chain resume, this step is not needed and the page of the fixed user is displayed directly.</p><p>Tried to locate the home page directly through the route and splice the user to get the data, and found that it did not work well.</p><p>The final solution was a bit of a detour, redirecting directly to the home page inside the home page.</p><p>Need to display a user data directly modify <code>address</code> in <code>src/config.ts</code> can be.</p><h4 id="h-334-deployment" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">3.3.4 Deployment</h4><p>After downloading the project, modify the wallet address in <code>src/config.ts</code> and the corresponding md file url address to suit your needs.</p><pre data-type="codeBlock" text="export default {
    address: &apos;0xC994B5384C0d0611De2ecE7d6fF1aD16C34A812F&apos;,
    mdUrl: &apos;https://api.github.com/repos/komomoo/vuepress-theme-resume/contents/example/README.md?ref=master&apos;,
    ...
}
"><code>export default {
    <span class="hljs-keyword">address</span>: <span class="hljs-string">'0xC994B5384C0d0611De2ecE7d6fF1aD16C34A812F'</span>,
    mdUrl: <span class="hljs-string">'https://api.github.com/repos/komomoo/vuepress-theme-resume/contents/example/README.md?ref=master'</span>,
    ...
}
</code></pre><p>Then use the <code>webpack</code> command to package, the package can be accessed normally (packaging time is long, no progress bar, you need to wait patiently, about 1 minute or so).</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">msfew</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">leeduckgo</figcaption></figure>]]></content:encoded>
            <author>apecoder@newsletter.paragraph.com (Web3dAppDevCamp)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/9cb5da88fe2456a589702ed1286542b7de436f147792069c1b1bcd03a106a1a6.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[Build SVG NFT dApp by Scaffold-Eth | Web3.0 dApp Dev 0x07]]></title>
            <link>https://paragraph.com/@apecoder/build-svg-nft-dapp-by-scaffold-eth-web3-0-dapp-dev-0x07</link>
            <guid>k3MI4C9dVX4GkgU7de0l</guid>
            <pubDate>Fri, 11 Feb 2022 12:15:54 GMT</pubDate>
            <description><![CDATA[国内用户如需交流，可加微信：197626581.Authors: qiwihui, msfewHistory Articles List:Quickstart | Web3.0 dApp Dev 0x01Web3.0 dApp Developer Growth Path | Web3.0 dApp Dev 0x02Scaffold-Eth Quickstart | Web3.0 dApp Dev 0x03Get & Set Value 1.0 | Web3.0 dApp Dev 0x04Get & Set Value 2.0 | Web3.0 dApp Dev 0x05Get & Set Value 3.0 | Web3.0 dApp Dev 0x06loogies-svg-nft is a simple NFT minting and displaying project provided by scaffold-eth. In this tutorial, we will walk you through a step-by-step analysis and impleme...]]></description>
            <content:encoded><![CDATA[<blockquote><p>国内用户如需交流，可加微信：197626581.</p></blockquote><blockquote><p><strong>Authors:</strong> <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/qiwihui">qiwihui</a>, msfew</p></blockquote><blockquote><p>History Articles List:</p><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://t.co/sUbwu4kzGA">Quickstart | Web3.0 dApp Dev 0x01</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://t.co/sfpx5DjoZj">Web3.0 dApp Developer Growth Path | Web3.0 dApp Dev 0x02</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://t.co/lvL1IfousS">Scaffold-Eth Quickstart | Web3.0 dApp Dev 0x03</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://t.co/6v0ajRD1kp">Get &amp; Set Value 1.0 | Web3.0 dApp Dev 0x04</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/0x73c7448760517E3E6e416b2c130E3c6dB2026A1d/b2Pz3Cxq3A9bjKWNlkgEqStZaMc6w89Cupgw9CcsPSs">Get &amp; Set Value 2.0 | Web3.0 dApp Dev 0x05</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/0x73c7448760517E3E6e416b2c130E3c6dB2026A1d/HvS9-pIa1raDuBUCaKGDZUpkFqElUX0fZpMkjoe5HQA">Get &amp; Set Value 3.0 | Web3.0 dApp Dev 0x06</a></p></li></ul></blockquote><p>loogies-svg-nft is a simple NFT minting and displaying project provided by scaffold-eth. In this tutorial, we will walk you through a step-by-step analysis and implementation of this project.</p><p>Since the <code>loogies-svg-nft</code> branch and the <code>master</code> branch of the project have some differences in the component library and home page, the <code>master</code> branch code needs to be merged with the <code>loogies-svg-nft</code> branch to resolve the conflicts and get a brand new set of code based on the new component library. You can see the <code>loogies-svg-nft</code> branch of the project at <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/qiwihui/scaffold-eth.git">https://github.com/qiwihui/scaffold-eth.git</a>. The following part of this article will be based on these codes for deployment and analysis.</p><h2 id="h-0x01-running-and-testing-locally" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x01 Running and testing locally</h2><p>First let&apos;s run the project to see what we are going to analyze and implement.</p><h3 id="h-running-locally" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Running locally</h3><p>First we run the project locally.</p><ol><li><p>clone the project and switch to the <code>loogies-svg-nft</code> branch:</p><pre data-type="codeBlock" text="git clone https://github.com/qiwihui/scaffold-eth.git loogies-svg-nft
cd loogies-svg-nft
git checkout loogies-svg-nft
"><code>git clone https:<span class="hljs-comment">//github.com/qiwihui/scaffold-eth.git loogies-svg-nft</span>
cd loogies<span class="hljs-operator">-</span>svg<span class="hljs-operator">-</span>nft
git checkout loogies<span class="hljs-operator">-</span>svg<span class="hljs-operator">-</span>nft
</code></pre></li><li><p>install dependencies</p><pre data-type="codeBlock" text="yarn install
"><code></code></pre></li><li><p>start the front end server</p><pre data-type="codeBlock" text="yarn start
"><code>yarn <span class="hljs-keyword">start</span>
</code></pre></li><li><p>run the local test network in a second terminal window</p><pre data-type="codeBlock" text="yarn chain
"><code></code></pre></li><li><p>deploy contract in a third terminal window</p><pre data-type="codeBlock" text="yarn deploy
"><code></code></pre></li><li><p>go to <code>http://localhost:3000</code> in browser to see the app</p></li></ol><h3 id="h-testing-locally" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Testing locally</h3><ol><li><p>First add the local network to the MetaMask wallet and switch to the local network;</p><ul><li><p>Network name: <code>Localhost 8545</code></p></li><li><p>Add RPC URL: <code>http://localhost:8545</code></p></li><li><p>Chain ID: <code>31337</code></p></li><li><p>Currency Symbol: <code>ETH</code></p></li></ul></li><li><p>Create a new local wallet address;</p></li><li><p>Copy the wallet address and send some test ETH to this address in the bottom left corner of the page;</p></li><li><p>Click on <code>connect</code> in the top right corner of the page to connect to the wallet;</p></li><li><p>Click on Mint button to mint;</p></li><li><p>When the transaction succeed, you can see the newly minted NFT.</p></li></ol><p>Now we begin our analysis of the project contract.</p><h2 id="h-0x02-loogies-contract-analysis" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x02 Loogies Contract Analysis</h2><h3 id="h-nft-and-erc721" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">NFT and ERC721</h3><p><strong>NFT</strong> (Non-Fungible Token), refers to non-homogenized tokens, corresponding to the ERC-721 standard on Ethereum. Generally in smart contracts, the definition of NFT contains <code>tokenId</code> and <code>tokenURI</code>, <code>tokenId</code> is unique ID for each NFT, and <code>tokenURI</code> for the metadata of the NFT is saved, which can be image URL, description, attributes, etc. If an NFT wants to display and sell in the NFT marketplace, the <code>tokenURI</code> content needs to correspond to the standards of the NFT marketplace. For example, in the NFT marketplace OpenSea&apos;s <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.opensea.io/docs/metadata-standards">metadata standards</a>, it is indicate attributes that need to be set for NFT display.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">NFT metadata and presentation&apos;s connection in OpenSea</figcaption></figure><p>NFT metadata and presentation&apos;s connection in OpenSea</p><h3 id="h-contract-overview" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Contract overview</h3><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/scaffold-eth/scaffold-eth/tree/loogies-svg-nft">loogies-svg-nft project</a>&apos;s contract code is at &apos; <code>packages/hardhat/contracts/</code>, and contains three files.</p><pre data-type="codeBlock" text="packages/hardhat/contracts/
├── HexStrings.sol
├── ToColor.sol
└── YourCollectible.sol
"><code>packages<span class="hljs-operator">/</span>hardhat<span class="hljs-operator">/</span>contracts<span class="hljs-operator">/</span>
├── HexStrings.sol
├── ToColor.sol
└── YourCollectible.sol
</code></pre><ul><li><p><code>HexString.sol</code>: generate address string;</p></li><li><p><code>ToColor.sol</code>: generate color value string;</p></li><li><p><code>YourCollectible.sol</code>： <code>Loogies</code> NFT&apos;s contract file with functions of minting and metadata generating.</p></li></ul><p>Contract architecture and methods:</p><pre data-type="codeBlock" text="contract YourCollectible is ERC721, Ownable {

    // Constructor function
  constructor() public ERC721(&quot;Loogies&quot;, &quot;LOOG&quot;) {
  }
  // Mint NFT
  function mintItem()
      public
      returns (uint256)
  {
    ...
  }
    // Get tokenURI from tokenId
  function tokenURI(uint256 id) public view override returns (string memory) {
    ...
  }
    // Generate SVG from tokenId
  function generateSVGofTokenById(uint256 id) internal view returns (string memory) {
    ...
  }

    // Render tokenId&apos;s svg code for graphics display
  function renderTokenById(uint256 id) public view returns (string memory) {
    ...
  }

}
"><code><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">YourCollectible</span> <span class="hljs-keyword">is</span> <span class="hljs-title">ERC721</span>, <span class="hljs-title">Ownable</span> </span>{

    <span class="hljs-comment">// Constructor function</span>
  <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title">ERC721</span>(<span class="hljs-params"><span class="hljs-string">"Loogies"</span>, <span class="hljs-string">"LOOG"</span></span>) </span>{
  }
  <span class="hljs-comment">// Mint NFT</span>
  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">mintItem</span>(<span class="hljs-params"></span>)
      <span class="hljs-title"><span class="hljs-keyword">public</span></span>
      <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span></span>)
  </span>{
    ...
  }
    <span class="hljs-comment">// Get tokenURI from tokenId</span>
  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">tokenURI</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> id</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">override</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span></span>) </span>{
    ...
  }
    <span class="hljs-comment">// Generate SVG from tokenId</span>
  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">generateSVGofTokenById</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> id</span>) <span class="hljs-title"><span class="hljs-keyword">internal</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span></span>) </span>{
    ...
  }

    <span class="hljs-comment">// Render tokenId's svg code for graphics display</span>
  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">renderTokenById</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> id</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span></span>) </span>{
    ...
  }

}
</code></pre><h3 id="h-constructor-function" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Constructor function</h3><pre data-type="codeBlock" text="constructor() public ERC721(&quot;Loogies&quot;, &quot;LOOG&quot;) {
    // RELEASE THE LOOGIES!
  }
"><code><span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title">ERC721</span>(<span class="hljs-params"><span class="hljs-string">"Loogies"</span>, <span class="hljs-string">"LOOG"</span></span>) </span>{
    <span class="hljs-comment">// RELEASE THE LOOGIES!</span>
  }
</code></pre><p>Token name: <code>Loogies</code></p><p>Token symbol: <code>LOOG</code></p><p>The contract is inherited from OpenZeppelin&apos;s <code>ERC721.sol</code>, which is the basic contract code provided by OpenZeppelin and can be easily used by developers.</p><h3 id="h-library-functions" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Library functions</h3><p>Contract applies different library functions for <code>uint256</code>, <code>uint160</code> and <code>bytes3</code> to extend features:</p><pre data-type="codeBlock" text="// let uint256 have toHexString
using Strings for uint256;
// let uint160 have configurable toHexString
using HexStrings for uint160;
// let bytes3 have easy color representation
using ToColor for bytes3;
// counter feature
using Counters for Counters.Counter;
"><code><span class="hljs-comment">// let uint256 have toHexString</span>
<span class="hljs-keyword">using</span> <span class="hljs-title">Strings</span> <span class="hljs-title"><span class="hljs-keyword">for</span></span> <span class="hljs-title"><span class="hljs-keyword">uint256</span></span>;
<span class="hljs-comment">// let uint160 have configurable toHexString</span>
<span class="hljs-keyword">using</span> <span class="hljs-title">HexStrings</span> <span class="hljs-title"><span class="hljs-keyword">for</span></span> <span class="hljs-title"><span class="hljs-keyword">uint160</span></span>;
<span class="hljs-comment">// let bytes3 have easy color representation</span>
<span class="hljs-keyword">using</span> <span class="hljs-title">ToColor</span> <span class="hljs-title"><span class="hljs-keyword">for</span></span> <span class="hljs-title"><span class="hljs-keyword">bytes3</span></span>;
<span class="hljs-comment">// counter feature</span>
<span class="hljs-keyword">using</span> <span class="hljs-title">Counters</span> <span class="hljs-title"><span class="hljs-keyword">for</span></span> <span class="hljs-title">Counters</span>.<span class="hljs-title">Counter</span>;
</code></pre><h3 id="h-mint-time-limit" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Mint time limit</h3><p>The following code is for Mint time limit:</p><pre data-type="codeBlock" text="uint256 mintDeadline = block.timestamp + 24 hours;

function mintItem()
      public
      returns (uint256)
  {
      require( block.timestamp &lt; mintDeadline, &quot;DONE MINTING&quot;);
...
"><code><span class="hljs-keyword">uint256</span> mintDeadline <span class="hljs-operator">=</span> <span class="hljs-built_in">block</span>.<span class="hljs-built_in">timestamp</span> <span class="hljs-operator">+</span> <span class="hljs-number">24</span> <span class="hljs-literal">hours</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">mintItem</span>(<span class="hljs-params"></span>)
      <span class="hljs-title"><span class="hljs-keyword">public</span></span>
      <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span></span>)
  </span>{
      <span class="hljs-built_in">require</span>( <span class="hljs-built_in">block</span>.<span class="hljs-built_in">timestamp</span> <span class="hljs-operator">&#x3C;</span> mintDeadline, <span class="hljs-string">"DONE MINTING"</span>);
...
</code></pre><p>Contracts is mintable within 24 hours of deployment, and beyond that time an exception is raised. This mechanism is similar to pre-sales. Since this contract is relatively simple, no whitelist mechanism is used, and generally in practice, pre-sales and whitelists are used to control the NFTs issuing.</p><h3 id="h-mint-nft" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Mint NFT</h3><p>Minting NFT is to set two variables in contract:</p><ul><li><p><code>tokenId</code> with <code>owner</code></p></li><li><p><code>tokenId</code> with <code>tokenURI</code></p></li></ul><p>Let&apos;s look at the minting function <code>mintItem</code>:</p><pre data-type="codeBlock" text="// Store each Loogies&apos; attribute
mapping (uint256 =&gt; bytes3) public color;
mapping (uint256 =&gt; uint256) public chubbiness;

...

function mintItem()
      public
      returns (uint256)
  {
      require( block.timestamp &lt; mintDeadline, &quot;DONE MINTING&quot;);
            // Self increment for _tokenIds to make sure _tokenIds is non-fungiable
      _tokenIds.increment();

      uint256 id = _tokenIds.current();
            // Binder minter and tokenId
      _mint(msg.sender, id);
            // Randomly generate tokenId&apos;s attributes
      bytes32 predictableRandom = keccak256(abi.encodePacked( blockhash(block.number-1), msg.sender, address(this), id ));
      color[id] = bytes2(predictableRandom[0]) | ( bytes2(predictableRandom[1]) &gt;&gt; 8 ) | ( bytes3(predictableRandom[2]) &gt;&gt; 16 );
      chubbiness[id] = 35+((55*uint256(uint8(predictableRandom[3])))/255);

      return id;
  }
"><code><span class="hljs-comment">// Store each Loogies' attribute</span>
<span class="hljs-keyword">mapping</span> (<span class="hljs-keyword">uint256</span> <span class="hljs-operator">=</span><span class="hljs-operator">></span> <span class="hljs-keyword">bytes3</span>) <span class="hljs-keyword">public</span> color;
<span class="hljs-keyword">mapping</span> (<span class="hljs-keyword">uint256</span> <span class="hljs-operator">=</span><span class="hljs-operator">></span> <span class="hljs-keyword">uint256</span>) <span class="hljs-keyword">public</span> chubbiness;

...

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">mintItem</span>(<span class="hljs-params"></span>)
      <span class="hljs-title"><span class="hljs-keyword">public</span></span>
      <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span></span>)
  </span>{
      <span class="hljs-built_in">require</span>( <span class="hljs-built_in">block</span>.<span class="hljs-built_in">timestamp</span> <span class="hljs-operator">&#x3C;</span> mintDeadline, <span class="hljs-string">"DONE MINTING"</span>);
            <span class="hljs-comment">// Self increment for _tokenIds to make sure _tokenIds is non-fungiable</span>
      _tokenIds.increment();

      <span class="hljs-keyword">uint256</span> id <span class="hljs-operator">=</span> _tokenIds.current();
            <span class="hljs-comment">// Binder minter and tokenId</span>
      _mint(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, id);
            <span class="hljs-comment">// Randomly generate tokenId's attributes</span>
      <span class="hljs-keyword">bytes32</span> predictableRandom <span class="hljs-operator">=</span> <span class="hljs-built_in">keccak256</span>(<span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encodePacked</span>( <span class="hljs-built_in">blockhash</span>(<span class="hljs-built_in">block</span>.<span class="hljs-built_in">number</span>-<span class="hljs-number">1</span>), <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>), id ));
      color[id] <span class="hljs-operator">=</span> <span class="hljs-keyword">bytes2</span>(predictableRandom[<span class="hljs-number">0</span>]) <span class="hljs-operator">|</span> ( <span class="hljs-keyword">bytes2</span>(predictableRandom[<span class="hljs-number">1</span>]) <span class="hljs-operator">></span><span class="hljs-operator">></span> <span class="hljs-number">8</span> ) <span class="hljs-operator">|</span> ( <span class="hljs-keyword">bytes3</span>(predictableRandom[<span class="hljs-number">2</span>]) <span class="hljs-operator">></span><span class="hljs-operator">></span> <span class="hljs-number">16</span> );
      chubbiness[id] <span class="hljs-operator">=</span> <span class="hljs-number">35</span><span class="hljs-operator">+</span>((<span class="hljs-number">55</span><span class="hljs-operator">*</span><span class="hljs-keyword">uint256</span>(<span class="hljs-keyword">uint8</span>(predictableRandom[<span class="hljs-number">3</span>])))<span class="hljs-operator">/</span><span class="hljs-number">255</span>);

      <span class="hljs-keyword">return</span> id;
  }
</code></pre><p>Also:</p><ul><li><p><code>tokenId</code> self increments when minting to make sure each <code>tokenId</code> is only one;</p></li><li><p><code>_mint</code> function binds <code>tokenId</code> with <code>owner</code>;</p></li><li><p>Each <code>tokenId</code>&apos;s attribute is generated randomly:</p><ul><li><p>By pre-block&apos;s hash (<code>blockhash(block.number-1)</code>), <code>msg.sender</code>, contract address (<code>address(this)</code>) and <code>tokenId</code>&apos;s generated hash <code>predictableRandom</code>;</p></li><li><p>Calculate NFT color: doing bit operations to <code>predictableRandom</code>&apos;s first three bits to get the color, color is represented by bytes3. <code>bytes2(predictableRandom[0])</code> is the lowest blue value, <code>( bytes2(predictableRandom[1]) &gt;&gt; 8 )</code> is the green value, <code>( bytes3(predictableRandom[2]) &gt;&gt; 16 )</code> is the red value;</p></li><li><p>Calculate NFT chubbiness: <code>35+((55*uint256(uint8(predictableRandom[3])))/255);</code> ，<code>uint8(predictableRandom[3])</code> is between 0~255, so the minimum is 35, and the maximum is 35 + 55 = 90.</p></li></ul></li></ul><p>For example: When <code>color</code> is <code>0x4cc4c1</code>, <code>chubbiness</code> is 88, the NFT picture is:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">loogies-1</figcaption></figure><h3 id="h-tokenuri-function" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">tokenURI function</h3><p>Function <code>tokenURI</code> takes <code>tokenId</code> parameter, returns encoded metadata string:</p><pre data-type="codeBlock" text="function tokenURI(uint256 id) public view override returns (string memory) {
            // check id if exist
      require(_exists(id), &quot;not exist&quot;);
      string memory name = string(abi.encodePacked(&apos;Loogie #&apos;,id.toString()));
      string memory description = string(abi.encodePacked(&apos;This Loogie is the color #&apos;,color[id].toColor(),&apos; with a chubbiness of &apos;,uint2str(chubbiness[id]),&apos;!!!&apos;));
      // generate svg base64 for image
            string memory image = Base64.encode(bytes(generateSVGofTokenById(id)));

      return
          string(
              abi.encodePacked(
                &apos;data:application/json;base64,&apos;,
                                // encode metadata with base64
                Base64.encode(
                    bytes(
                          abi.encodePacked(
                              &apos;{&quot;name&quot;:&quot;&apos;,
                              name,
                              &apos;&quot;, &quot;description&quot;:&quot;&apos;,
                              description,
                              &apos;&quot;, &quot;external_url&quot;:&quot;https://burnyboys.com/token/&apos;,
                              id.toString(),
                              &apos;&quot;, &quot;attributes&quot;: [{&quot;trait_type&quot;: &quot;color&quot;, &quot;value&quot;: &quot;#&apos;,
                              color[id].toColor(),
                              &apos;&quot;},{&quot;trait_type&quot;: &quot;chubbiness&quot;, &quot;value&quot;: &apos;,
                              uint2str(chubbiness[id]),
                              &apos;}], &quot;owner&quot;:&quot;&apos;,
                              (uint160(ownerOf(id))).toHexString(20),
                              &apos;&quot;, &quot;image&quot;: &quot;&apos;,
                              &apos;data:image/svg+xml;base64,&apos;,
                              image,
                              &apos;&quot;}&apos;
                          )
                        )
                    )
              )
          );
  }
// Generated SVG string
function generateSVGofTokenById(uint256 id) internal view returns (string memory) {
...
}

// Render image
// Visibility is `public` to enable it being called by other contracts for composition.
function renderTokenById(uint256 id) public view returns (string memory) {
...
}
"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">tokenURI</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> id</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">override</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span></span>) </span>{
            <span class="hljs-comment">// check id if exist</span>
      <span class="hljs-built_in">require</span>(_exists(id), <span class="hljs-string">"not exist"</span>);
      <span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span> name <span class="hljs-operator">=</span> <span class="hljs-keyword">string</span>(<span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encodePacked</span>(<span class="hljs-string">'Loogie #'</span>,id.toString()));
      <span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span> description <span class="hljs-operator">=</span> <span class="hljs-keyword">string</span>(<span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encodePacked</span>(<span class="hljs-string">'This Loogie is the color #'</span>,color[id].toColor(),<span class="hljs-string">' with a chubbiness of '</span>,uint2str(chubbiness[id]),<span class="hljs-string">'!!!'</span>));
      <span class="hljs-comment">// generate svg base64 for image</span>
            <span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span> image <span class="hljs-operator">=</span> Base64.encode(<span class="hljs-keyword">bytes</span>(generateSVGofTokenById(id)));

      <span class="hljs-keyword">return</span>
          <span class="hljs-keyword">string</span>(
              <span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encodePacked</span>(
                <span class="hljs-string">'data:application/json;base64,'</span>,
                                <span class="hljs-comment">// encode metadata with base64</span>
                Base64.encode(
                    <span class="hljs-keyword">bytes</span>(
                          <span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encodePacked</span>(
                              <span class="hljs-string">'{"name":"'</span>,
                              name,
                              <span class="hljs-string">'", "description":"'</span>,
                              description,
                              <span class="hljs-string">'", "external_url":"https://burnyboys.com/token/'</span>,
                              id.toString(),
                              <span class="hljs-string">'", "attributes": [{"trait_type": "color", "value": "#'</span>,
                              color[id].toColor(),
                              <span class="hljs-string">'"},{"trait_type": "chubbiness", "value": '</span>,
                              uint2str(chubbiness[id]),
                              <span class="hljs-string">'}], "owner":"'</span>,
                              (<span class="hljs-keyword">uint160</span>(ownerOf(id))).toHexString(<span class="hljs-number">20</span>),
                              <span class="hljs-string">'", "image": "'</span>,
                              <span class="hljs-string">'data:image/svg+xml;base64,'</span>,
                              image,
                              <span class="hljs-string">'"}'</span>
                          )
                        )
                    )
              )
          );
  }
<span class="hljs-comment">// Generated SVG string</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">generateSVGofTokenById</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> id</span>) <span class="hljs-title"><span class="hljs-keyword">internal</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span></span>) </span>{
...
}

<span class="hljs-comment">// Render image</span>
<span class="hljs-comment">// Visibility is `public` to enable it being called by other contracts for composition.</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">renderTokenById</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> id</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span></span>) </span>{
...
}
</code></pre><p>In this, <code>generateSVGofTokenById</code> function returns <code>tokenId</code>&apos;s SVG string on its color and chubbiness, <code>renderTokenById</code> renders the token.</p><p>We see that the NFT needs to include:</p><ul><li><p>name</p></li><li><p>description</p></li><li><p>external_url</p></li><li><p>attributes</p><ul><li><p>color</p></li><li><p>chubbiness</p></li><li><p>owner</p></li><li><p>image</p></li></ul></li></ul><p>We can get to know more about SVG by an example.When <code>tokenId</code> is 1, the <code>tokenURI</code> is:</p><pre data-type="codeBlock" text="data:application/json;base64,eyJuYW1lIjoiTG9vZ2llICMxIiwiZGVzY3JpcHRpb24iOiJUaGlzIExvb2dpZSBpcyB0aGUgY29sb3IgIzRjYzRjMSB3aXRoIGEgY2h1YmJpbmVzcyBvZiA4OCEhISIsImV4dGVybmFsX3VybCI6Imh0dHBzOi8vYnVybnlib3lzLmNvbS90b2tlbi8xIiwiYXR0cmlidXRlcyI6W3sidHJhaXRfdHlwZSI6ImNvbG9yIiwidmFsdWUiOiIjNGNjNGMxIn0seyJ0cmFpdF90eXBlIjoiY2h1YmJpbmVzcyIsInZhbHVlIjo4OH1dLCJvd25lciI6IjB4MTY5ODQxYWEzMDI0Y2ZhNTcwMDI0ZWI3ZGQ2YmY1Zjc3NDA5MjA4OCIsImltYWdlIjoiZGF0YTppbWFnZS9zdmcreG1sO2Jhc2U2NCxQSE4yWnlCM2FXUjBhRDBpTkRBd0lpQm9aV2xuYUhROUlqUXdNQ0lnZUcxc2JuTTlJbWgwZEhBNkx5OTNkM2N1ZHpNdWIzSm5Mekl3TURBdmMzWm5JajQ4WnlCcFpEMGlaWGxsTVNJK1BHVnNiR2x3YzJVZ2MzUnliMnRsTFhkcFpIUm9QU0l6SWlCeWVUMGlNamt1TlNJZ2NuZzlJakk1TGpVaUlHbGtQU0p6ZG1kZk1TSWdZM2s5SWpFMU5DNDFJaUJqZUQwaU1UZ3hMalVpSUhOMGNtOXJaVDBpSXpBd01DSWdabWxzYkQwaUkyWm1aaUl2UGp4bGJHeHBjSE5sSUhKNVBTSXpMalVpSUhKNFBTSXlMalVpSUdsa1BTSnpkbWRmTXlJZ1kzazlJakUxTkM0MUlpQmplRDBpTVRjekxqVWlJSE4wY205clpTMTNhV1IwYUQwaU15SWdjM1J5YjJ0bFBTSWpNREF3SWlCbWFXeHNQU0lqTURBd01EQXdJaTgrUEM5blBqeG5JR2xrUFNKb1pXRmtJajQ4Wld4c2FYQnpaU0JtYVd4c1BTSWpOR05qTkdNeElpQnpkSEp2YTJVdGQybGtkR2c5SWpNaUlHTjRQU0l5TURRdU5TSWdZM2s5SWpJeE1TNDRNREEyTlNJZ2FXUTlJbk4yWjE4MUlpQnllRDBpT0RnaUlISjVQU0kxTVM0NE1EQTJOU0lnYzNSeWIydGxQU0lqTURBd0lpOCtQQzluUGp4bklHbGtQU0psZVdVeUlqNDhaV3hzYVhCelpTQnpkSEp2YTJVdGQybGtkR2c5SWpNaUlISjVQU0l5T1M0MUlpQnllRDBpTWprdU5TSWdhV1E5SW5OMloxOHlJaUJqZVQwaU1UWTRMalVpSUdONFBTSXlNRGt1TlNJZ2MzUnliMnRsUFNJak1EQXdJaUJtYVd4c1BTSWpabVptSWk4K1BHVnNiR2x3YzJVZ2NuazlJak11TlNJZ2NuZzlJak1pSUdsa1BTSnpkbWRmTkNJZ1kzazlJakUyT1M0MUlpQmplRDBpTWpBNElpQnpkSEp2YTJVdGQybGtkR2c5SWpNaUlHWnBiR3c5SWlNd01EQXdNREFpSUhOMGNtOXJaVDBpSXpBd01DSXZQand2Wno0OEwzTjJaejQ9In0=
"><code>data:application/json;<span class="hljs-built_in">base64</span>,eyJuYW1lIjoiTG9vZ2llICMxIiwiZGVzY3JpcHRpb24iOiJUaGlzIExvb2dpZSBpcyB0aGUgY29sb3IgIzRjYzRjMSB3aXRoIGEgY2h1YmJpbmVzcyBvZiA4OCEhISIsImV4dGVybmFsX3VybCI6Imh0dHBzOi8vYnVybnlib3lzLmNvbS90b2tlbi8xIiwiYXR0cmlidXRlcyI6W3sidHJhaXRfdHlwZSI6ImNvbG9yIiwidmFsdWUiOiIjNGNjNGMxIn0seyJ0cmFpdF90eXBlIjoiY2h1YmJpbmVzcyIsInZhbHVlIjo4OH1dLCJvd25lciI6IjB4MTY5ODQxYWEzMDI0Y2ZhNTcwMDI0ZWI3ZGQ2YmY1Zjc3NDA5MjA4OCIsImltYWdlIjoiZGF0YTppbWFnZS9zdmcreG1sO2Jhc2U2NCxQSE4yWnlCM2FXUjBhRDBpTkRBd0lpQm9aV2xuYUhROUlqUXdNQ0lnZUcxc2JuTTlJbWgwZEhBNkx5OTNkM2N1ZHpNdWIzSm5Mekl3TURBdmMzWm5JajQ4WnlCcFpEMGlaWGxsTVNJK1BHVnNiR2x3YzJVZ2MzUnliMnRsTFhkcFpIUm9QU0l6SWlCeWVUMGlNamt1TlNJZ2NuZzlJakk1TGpVaUlHbGtQU0p6ZG1kZk1TSWdZM2s5SWpFMU5DNDFJaUJqZUQwaU1UZ3hMalVpSUhOMGNtOXJaVDBpSXpBd01DSWdabWxzYkQwaUkyWm1aaUl2UGp4bGJHeHBjSE5sSUhKNVBTSXpMalVpSUhKNFBTSXlMalVpSUdsa1BTSnpkbWRmTXlJZ1kzazlJakUxTkM0MUlpQmplRDBpTVRjekxqVWlJSE4wY205clpTMTNhV1IwYUQwaU15SWdjM1J5YjJ0bFBTSWpNREF3SWlCbWFXeHNQU0lqTURBd01EQXdJaTgrUEM5blBqeG5JR2xrUFNKb1pXRmtJajQ4Wld4c2FYQnpaU0JtYVd4c1BTSWpOR05qTkdNeElpQnpkSEp2YTJVdGQybGtkR2c5SWpNaUlHTjRQU0l5TURRdU5TSWdZM2s5SWpJeE1TNDRNREEyTlNJZ2FXUTlJbk4yWjE4MUlpQnllRDBpT0RnaUlISjVQU0kxTVM0NE1EQTJOU0lnYzNSeWIydGxQU0lqTURBd0lpOCtQQzluUGp4bklHbGtQU0psZVdVeUlqNDhaV3hzYVhCelpTQnpkSEp2YTJVdGQybGtkR2c5SWpNaUlISjVQU0l5T1M0MUlpQnllRDBpTWprdU5TSWdhV1E5SW5OMloxOHlJaUJqZVQwaU1UWTRMalVpSUdONFBTSXlNRGt1TlNJZ2MzUnliMnRsUFNJak1EQXdJaUJtYVd4c1BTSWpabVptSWk4K1BHVnNiR2x3YzJVZ2NuazlJak11TlNJZ2NuZzlJak1pSUdsa1BTSnpkbWRmTkNJZ1kzazlJakUyT1M0MUlpQmplRDBpTWpBNElpQnpkSEp2YTJVdGQybGtkR2c5SWpNaUlHWnBiR3c5SWlNd01EQXdNREFpSUhOMGNtOXJaVDBpSXpBd01DSXZQand2Wno0OEwzTjJaejQ9In0=
</code></pre><p>Decode <code>data:application/json;base64,</code> with base64. Then the string can generate the following json (simplified version):</p><pre data-type="codeBlock" text="{
  &quot;name&quot;: &quot;Loogie #1&quot;,
  &quot;description&quot;: &quot;This Loogie is the color #4cc4c1 with a chubbiness of 88!!!&quot;,
  &quot;external_url&quot;: &quot;https://burnyboys.com/token/1&quot;,
  &quot;attributes&quot;: [
    {
      &quot;trait_type&quot;: &quot;color&quot;,
      &quot;value&quot;: &quot;#4cc4c1&quot;
    },
    {
      &quot;trait_type&quot;: &quot;chubbiness&quot;,
      &quot;value&quot;: 88
    }
  ],
  &quot;owner&quot;: &quot;0x169841aa3024cfa570024eb7dd6bf5f774092088&quot;,
  &quot;image&quot;: &quot;data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAwIiBoZWlnaHQ9IjQwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBpZD0iZXllMSI+PGVsbGlwc2Ugc3Ryb2tlLXdpZHRoPSIzIiByeT0iMjkuNSIgcng9IjI5LjUiIGlkPSJzdmdfMSIgY3k9IjE1NC41IiBjeD0iMTgxLjUiIHN0cm9rZT0iIzAwMCIgZmlsbD0iI2ZmZiIvPjxlbGxpcHNlIHJ5PSIzLjUiIHJ4PSIyLjUiIGlkPSJzdmdfMyIgY3k9IjE1NC41IiBjeD0iMTczLjUiIHN0cm9rZS13aWR0aD0iMyIgc3Ryb2tlPSIjMDAwIiBmaWxsPSIjMDAwMDAwIi8+PC9nPjxnIGlkPSJoZWFkIj48ZWxsaXBzZSBmaWxsPSIjNGNjNGMxIiBzdHJva2Utd2lkdGg9IjMiIGN4PSIyMDQuNSIgY3k9IjIxMS44MDA2NSIgaWQ9InN2Z181IiByeD0iODgiIHJ5PSI1MS44MDA2NSIgc3Ryb2tlPSIjMDAwIi8+PC9nPjxnIGlkPSJleWUyIj48ZWxsaXBzZSBzdHJva2Utd2lkdGg9IjMiIHJ5PSIyOS41IiByeD0iMjkuNSIgaWQ9InN2Z18yIiBjeT0iMTY4LjUiIGN4PSIyMDkuNSIgc3Ryb2tlPSIjMDAwIiBmaWxsPSIjZmZmIi8+PGVsbGlwc2Ugcnk9IjMuNSIgcng9IjMiIGlkPSJzdmdfNCIgY3k9IjE2OS41IiBjeD0iMjA4IiBzdHJva2Utd2lkdGg9IjMiIGZpbGw9IiMwMDAwMDAiIHN0cm9rZT0iIzAwMCIvPjwvZz48L3N2Zz4=&quot;
}
"><code><span class="hljs-punctuation">{</span>
  <span class="hljs-attr">"name"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"Loogie #1"</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"description"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"This Loogie is the color #4cc4c1 with a chubbiness of 88!!!"</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"external_url"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"https://burnyboys.com/token/1"</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"attributes"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span>
    <span class="hljs-punctuation">{</span>
      <span class="hljs-attr">"trait_type"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"color"</span><span class="hljs-punctuation">,</span>
      <span class="hljs-attr">"value"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"#4cc4c1"</span>
    <span class="hljs-punctuation">}</span><span class="hljs-punctuation">,</span>
    <span class="hljs-punctuation">{</span>
      <span class="hljs-attr">"trait_type"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"chubbiness"</span><span class="hljs-punctuation">,</span>
      <span class="hljs-attr">"value"</span><span class="hljs-punctuation">:</span> <span class="hljs-number">88</span>
    <span class="hljs-punctuation">}</span>
  <span class="hljs-punctuation">]</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"owner"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"0x169841aa3024cfa570024eb7dd6bf5f774092088"</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"image"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAwIiBoZWlnaHQ9IjQwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBpZD0iZXllMSI+PGVsbGlwc2Ugc3Ryb2tlLXdpZHRoPSIzIiByeT0iMjkuNSIgcng9IjI5LjUiIGlkPSJzdmdfMSIgY3k9IjE1NC41IiBjeD0iMTgxLjUiIHN0cm9rZT0iIzAwMCIgZmlsbD0iI2ZmZiIvPjxlbGxpcHNlIHJ5PSIzLjUiIHJ4PSIyLjUiIGlkPSJzdmdfMyIgY3k9IjE1NC41IiBjeD0iMTczLjUiIHN0cm9rZS13aWR0aD0iMyIgc3Ryb2tlPSIjMDAwIiBmaWxsPSIjMDAwMDAwIi8+PC9nPjxnIGlkPSJoZWFkIj48ZWxsaXBzZSBmaWxsPSIjNGNjNGMxIiBzdHJva2Utd2lkdGg9IjMiIGN4PSIyMDQuNSIgY3k9IjIxMS44MDA2NSIgaWQ9InN2Z181IiByeD0iODgiIHJ5PSI1MS44MDA2NSIgc3Ryb2tlPSIjMDAwIi8+PC9nPjxnIGlkPSJleWUyIj48ZWxsaXBzZSBzdHJva2Utd2lkdGg9IjMiIHJ5PSIyOS41IiByeD0iMjkuNSIgaWQ9InN2Z18yIiBjeT0iMTY4LjUiIGN4PSIyMDkuNSIgc3Ryb2tlPSIjMDAwIiBmaWxsPSIjZmZmIi8+PGVsbGlwc2Ugcnk9IjMuNSIgcng9IjMiIGlkPSJzdmdfNCIgY3k9IjE2OS41IiBjeD0iMjA4IiBzdHJva2Utd2lkdGg9IjMiIGZpbGw9IiMwMDAwMDAiIHN0cm9rZT0iIzAwMCIvPjwvZz48L3N2Zz4="</span>
<span class="hljs-punctuation">}</span>
</code></pre><p>We decode <code>image</code> value and format it to get image SVG:</p><pre data-type="codeBlock" text="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;400&quot; height=&quot;400&quot;&gt;
   &lt;g id=&quot;eye1&quot;&gt;
      &lt;ellipse stroke-width=&quot;3&quot; ry=&quot;29.5&quot; rx=&quot;29.5&quot; id=&quot;svg_1&quot; cy=&quot;154.5&quot; cx=&quot;181.5&quot; stroke=&quot;#000&quot; fill=&quot;#fff&quot; /&gt;
      &lt;ellipse ry=&quot;3.5&quot; rx=&quot;2.5&quot; id=&quot;svg_3&quot; cy=&quot;154.5&quot; cx=&quot;173.5&quot; stroke-width=&quot;3&quot; stroke=&quot;#000&quot; fill=&quot;#000000&quot; /&gt;
   &lt;/g&gt;
   &lt;g id=&quot;head&quot;&gt;
      &lt;ellipse fill=&quot;#4cc4c1&quot; stroke-width=&quot;3&quot; cx=&quot;204.5&quot; cy=&quot;211.80065&quot; id=&quot;svg_5&quot; rx=&quot;88&quot; ry=&quot;51.80065&quot; stroke=&quot;#000&quot; /&gt;
   &lt;/g&gt;
   &lt;g id=&quot;eye2&quot;&gt;
      &lt;ellipse stroke-width=&quot;3&quot; ry=&quot;29.5&quot; rx=&quot;29.5&quot; id=&quot;svg_2&quot; cy=&quot;168.5&quot; cx=&quot;209.5&quot; stroke=&quot;#000&quot; fill=&quot;#fff&quot; /&gt;
      &lt;ellipse ry=&quot;3.5&quot; rx=&quot;3&quot; id=&quot;svg_4&quot; cy=&quot;169.5&quot; cx=&quot;208&quot; stroke-width=&quot;3&quot; fill=&quot;#000000&quot; stroke=&quot;#000&quot; /&gt;
   &lt;/g&gt;
&lt;/svg&gt;
"><code><span class="hljs-operator">&#x3C;</span>?xml version<span class="hljs-operator">=</span><span class="hljs-string">"1.0"</span> encoding<span class="hljs-operator">=</span><span class="hljs-string">"UTF-8"</span>?<span class="hljs-operator">></span>
<span class="hljs-operator">&#x3C;</span>svg xmlns<span class="hljs-operator">=</span><span class="hljs-string">"http://www.w3.org/2000/svg"</span> width<span class="hljs-operator">=</span><span class="hljs-string">"400"</span> height<span class="hljs-operator">=</span><span class="hljs-string">"400"</span><span class="hljs-operator">></span>
   <span class="hljs-operator">&#x3C;</span>g id<span class="hljs-operator">=</span><span class="hljs-string">"eye1"</span><span class="hljs-operator">></span>
      <span class="hljs-operator">&#x3C;</span>ellipse stroke<span class="hljs-operator">-</span>width<span class="hljs-operator">=</span><span class="hljs-string">"3"</span> ry<span class="hljs-operator">=</span><span class="hljs-string">"29.5"</span> rx<span class="hljs-operator">=</span><span class="hljs-string">"29.5"</span> id<span class="hljs-operator">=</span><span class="hljs-string">"svg_1"</span> cy<span class="hljs-operator">=</span><span class="hljs-string">"154.5"</span> cx<span class="hljs-operator">=</span><span class="hljs-string">"181.5"</span> stroke<span class="hljs-operator">=</span><span class="hljs-string">"#000"</span> fill<span class="hljs-operator">=</span><span class="hljs-string">"#fff"</span> <span class="hljs-operator">/</span><span class="hljs-operator">></span>
      <span class="hljs-operator">&#x3C;</span>ellipse ry<span class="hljs-operator">=</span><span class="hljs-string">"3.5"</span> rx<span class="hljs-operator">=</span><span class="hljs-string">"2.5"</span> id<span class="hljs-operator">=</span><span class="hljs-string">"svg_3"</span> cy<span class="hljs-operator">=</span><span class="hljs-string">"154.5"</span> cx<span class="hljs-operator">=</span><span class="hljs-string">"173.5"</span> stroke<span class="hljs-operator">-</span>width<span class="hljs-operator">=</span><span class="hljs-string">"3"</span> stroke<span class="hljs-operator">=</span><span class="hljs-string">"#000"</span> fill<span class="hljs-operator">=</span><span class="hljs-string">"#000000"</span> <span class="hljs-operator">/</span><span class="hljs-operator">></span>
   <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>g<span class="hljs-operator">></span>
   <span class="hljs-operator">&#x3C;</span>g id<span class="hljs-operator">=</span><span class="hljs-string">"head"</span><span class="hljs-operator">></span>
      <span class="hljs-operator">&#x3C;</span>ellipse fill<span class="hljs-operator">=</span><span class="hljs-string">"#4cc4c1"</span> stroke<span class="hljs-operator">-</span>width<span class="hljs-operator">=</span><span class="hljs-string">"3"</span> cx<span class="hljs-operator">=</span><span class="hljs-string">"204.5"</span> cy<span class="hljs-operator">=</span><span class="hljs-string">"211.80065"</span> id<span class="hljs-operator">=</span><span class="hljs-string">"svg_5"</span> rx<span class="hljs-operator">=</span><span class="hljs-string">"88"</span> ry<span class="hljs-operator">=</span><span class="hljs-string">"51.80065"</span> stroke<span class="hljs-operator">=</span><span class="hljs-string">"#000"</span> <span class="hljs-operator">/</span><span class="hljs-operator">></span>
   <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>g<span class="hljs-operator">></span>
   <span class="hljs-operator">&#x3C;</span>g id<span class="hljs-operator">=</span><span class="hljs-string">"eye2"</span><span class="hljs-operator">></span>
      <span class="hljs-operator">&#x3C;</span>ellipse stroke<span class="hljs-operator">-</span>width<span class="hljs-operator">=</span><span class="hljs-string">"3"</span> ry<span class="hljs-operator">=</span><span class="hljs-string">"29.5"</span> rx<span class="hljs-operator">=</span><span class="hljs-string">"29.5"</span> id<span class="hljs-operator">=</span><span class="hljs-string">"svg_2"</span> cy<span class="hljs-operator">=</span><span class="hljs-string">"168.5"</span> cx<span class="hljs-operator">=</span><span class="hljs-string">"209.5"</span> stroke<span class="hljs-operator">=</span><span class="hljs-string">"#000"</span> fill<span class="hljs-operator">=</span><span class="hljs-string">"#fff"</span> <span class="hljs-operator">/</span><span class="hljs-operator">></span>
      <span class="hljs-operator">&#x3C;</span>ellipse ry<span class="hljs-operator">=</span><span class="hljs-string">"3.5"</span> rx<span class="hljs-operator">=</span><span class="hljs-string">"3"</span> id<span class="hljs-operator">=</span><span class="hljs-string">"svg_4"</span> cy<span class="hljs-operator">=</span><span class="hljs-string">"169.5"</span> cx<span class="hljs-operator">=</span><span class="hljs-string">"208"</span> stroke<span class="hljs-operator">-</span>width<span class="hljs-operator">=</span><span class="hljs-string">"3"</span> fill<span class="hljs-operator">=</span><span class="hljs-string">"#000000"</span> stroke<span class="hljs-operator">=</span><span class="hljs-string">"#000"</span> <span class="hljs-operator">/</span><span class="hljs-operator">></span>
   <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>g<span class="hljs-operator">></span>
<span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>svg<span class="hljs-operator">></span>
</code></pre><p>SVG is a language defined in XML to describe two-dimensional vector and vector/raster graphics. It is widely used as it can be displayed in arbitrarily large sizes and without sacrificing image quality, it can be described using code, and it is easy to edit.</p><p>As can be seen from the above code combined with the following image, this SVG contains the following.</p><ul><li><p>An XML declaration in the first line, indicating the version and encoding type, followed by the width and height of the SVG;</p></li><li><p><code>eye1</code>: eye circle and black eyes drawn by two ellipses;</p></li><li><p><code>head</code>: ellipse filled with <code>#4cc4c1</code> color as the body;</p></li><li><p><code>eye2</code>: identical to <code>eye1</code>, in a different position;</p></li></ul><p><code>eye1</code>, <code>head</code> and <code>eye2</code> are superimposed in sequence to get the final shape.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">loogies-1</figcaption></figure><h3 id="h-helper-function" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Helper function</h3><ol><li><p><code>uint2str</code> converts <code>uint</code> to string, like convert <code>123</code> to <code>&apos;123&apos;</code></p></li></ol><pre data-type="codeBlock" text="function uint2str(uint _i) internal pure returns (string memory _uintAsString) {
      if (_i == 0) {
          return &quot;0&quot;;
      }
      uint j = _i;
            // uint length
      uint len;
      while (j != 0) {
          len++;
          j /= 10;
      }
      bytes memory bstr = new bytes(len);
      uint k = len;
      while (_i != 0) {
          k = k-1;
                // _i single digits
          uint8 temp = (48 + uint8(_i - _i / 10 * 10));
          bytes1 b1 = bytes1(temp);
          bstr[k] = b1;
          _i /= 10;
      }
      return string(bstr);
  }
"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">uint2str</span>(<span class="hljs-params"><span class="hljs-keyword">uint</span> _i</span>) <span class="hljs-title"><span class="hljs-keyword">internal</span></span> <span class="hljs-title"><span class="hljs-keyword">pure</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span> _uintAsString</span>) </span>{
      <span class="hljs-keyword">if</span> (_i <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">0</span>) {
          <span class="hljs-keyword">return</span> <span class="hljs-string">"0"</span>;
      }
      <span class="hljs-keyword">uint</span> j <span class="hljs-operator">=</span> _i;
            <span class="hljs-comment">// uint length</span>
      <span class="hljs-keyword">uint</span> len;
      <span class="hljs-keyword">while</span> (j <span class="hljs-operator">!</span><span class="hljs-operator">=</span> <span class="hljs-number">0</span>) {
          len<span class="hljs-operator">+</span><span class="hljs-operator">+</span>;
          j <span class="hljs-operator">/</span><span class="hljs-operator">=</span> <span class="hljs-number">10</span>;
      }
      <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">memory</span> bstr <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-keyword">bytes</span>(len);
      <span class="hljs-keyword">uint</span> k <span class="hljs-operator">=</span> len;
      <span class="hljs-keyword">while</span> (_i <span class="hljs-operator">!</span><span class="hljs-operator">=</span> <span class="hljs-number">0</span>) {
          k <span class="hljs-operator">=</span> k<span class="hljs-number">-1</span>;
                <span class="hljs-comment">// _i single digits</span>
          <span class="hljs-keyword">uint8</span> temp <span class="hljs-operator">=</span> (<span class="hljs-number">48</span> <span class="hljs-operator">+</span> <span class="hljs-keyword">uint8</span>(_i <span class="hljs-operator">-</span> _i <span class="hljs-operator">/</span> <span class="hljs-number">10</span> <span class="hljs-operator">*</span> <span class="hljs-number">10</span>));
          <span class="hljs-keyword">bytes1</span> b1 <span class="hljs-operator">=</span> <span class="hljs-keyword">bytes1</span>(temp);
          bstr[k] <span class="hljs-operator">=</span> b1;
          _i <span class="hljs-operator">/</span><span class="hljs-operator">=</span> <span class="hljs-number">10</span>;
      }
      <span class="hljs-keyword">return</span> <span class="hljs-keyword">string</span>(bstr);
  }
</code></pre><ol><li><p><code>ToColor.sol</code> library: convert <code>byte3</code> type to color strings. Eg. <code>0x4cc4c1</code> as input and <code>&apos;4cc4c1&apos;</code> as output.</p></li></ol><pre data-type="codeBlock" text="library ToColor {
    bytes16 internal constant ALPHABET = &apos;0123456789abcdef&apos;;

    function toColor(bytes3 value) internal pure returns (string memory) {
      bytes memory buffer = new bytes(6);
      for (uint256 i = 0; i &lt; 3; i++) {
          buffer[i*2+1] = ALPHABET[uint8(value[i]) &amp; 0xf];
          buffer[i*2] = ALPHABET[uint8(value[i]&gt;&gt;4) &amp; 0xf];
      }
      return string(buffer);
    }
}
"><code><span class="hljs-class"><span class="hljs-keyword">library</span> <span class="hljs-title">ToColor</span> </span>{
    <span class="hljs-keyword">bytes16</span> <span class="hljs-keyword">internal</span> <span class="hljs-keyword">constant</span> ALPHABET <span class="hljs-operator">=</span> <span class="hljs-string">'0123456789abcdef'</span>;

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">toColor</span>(<span class="hljs-params"><span class="hljs-keyword">bytes3</span> value</span>) <span class="hljs-title"><span class="hljs-keyword">internal</span></span> <span class="hljs-title"><span class="hljs-keyword">pure</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span></span>) </span>{
      <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">memory</span> buffer <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-keyword">bytes</span>(<span class="hljs-number">6</span>);
      <span class="hljs-keyword">for</span> (<span class="hljs-keyword">uint256</span> i <span class="hljs-operator">=</span> <span class="hljs-number">0</span>; i <span class="hljs-operator">&#x3C;</span> <span class="hljs-number">3</span>; i<span class="hljs-operator">+</span><span class="hljs-operator">+</span>) {
          buffer[i<span class="hljs-operator">*</span><span class="hljs-number">2</span><span class="hljs-operator">+</span><span class="hljs-number">1</span>] <span class="hljs-operator">=</span> ALPHABET[<span class="hljs-keyword">uint8</span>(value[i]) <span class="hljs-operator">&#x26;</span> <span class="hljs-number">0xf</span>];
          buffer[i<span class="hljs-operator">*</span><span class="hljs-number">2</span>] <span class="hljs-operator">=</span> ALPHABET[<span class="hljs-keyword">uint8</span>(value[i]<span class="hljs-operator">></span><span class="hljs-operator">></span><span class="hljs-number">4</span>) <span class="hljs-operator">&#x26;</span> <span class="hljs-number">0xf</span>];
      }
      <span class="hljs-keyword">return</span> <span class="hljs-keyword">string</span>(buffer);
    }
}
</code></pre><ol><li><p><code>HexStrings.sol</code> library: Mainly extract <code>uint</code> based on <code>length</code> index, just like extract 20 indices of address: <code>(*uint160*(ownerOf(id))).toHexString(20)</code>, this expression generates the coresponding <code>tokenId</code> owner address.</p></li></ol><pre data-type="codeBlock" text="library HexStrings {
    bytes16 internal constant ALPHABET = &apos;0123456789abcdef&apos;;

    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = &apos;0&apos;;
        buffer[1] = &apos;x&apos;;
        for (uint256 i = 2 * length + 1; i &gt; 1; --i) {
            buffer[i] = ALPHABET[value &amp; 0xf];
            value &gt;&gt;= 4;
        }
        return string(buffer);
    }
}
"><code><span class="hljs-class"><span class="hljs-keyword">library</span> <span class="hljs-title">HexStrings</span> </span>{
    <span class="hljs-keyword">bytes16</span> <span class="hljs-keyword">internal</span> <span class="hljs-keyword">constant</span> ALPHABET <span class="hljs-operator">=</span> <span class="hljs-string">'0123456789abcdef'</span>;

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">toHexString</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> value, <span class="hljs-keyword">uint256</span> length</span>) <span class="hljs-title"><span class="hljs-keyword">internal</span></span> <span class="hljs-title"><span class="hljs-keyword">pure</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span></span>) </span>{
        <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">memory</span> buffer <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-keyword">bytes</span>(<span class="hljs-number">2</span> <span class="hljs-operator">*</span> length <span class="hljs-operator">+</span> <span class="hljs-number">2</span>);
        buffer[<span class="hljs-number">0</span>] <span class="hljs-operator">=</span> <span class="hljs-string">'0'</span>;
        buffer[<span class="hljs-number">1</span>] <span class="hljs-operator">=</span> <span class="hljs-string">'x'</span>;
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">uint256</span> i <span class="hljs-operator">=</span> <span class="hljs-number">2</span> <span class="hljs-operator">*</span> length <span class="hljs-operator">+</span> <span class="hljs-number">1</span>; i <span class="hljs-operator">></span> <span class="hljs-number">1</span>; <span class="hljs-operator">-</span><span class="hljs-operator">-</span>i) {
            buffer[i] <span class="hljs-operator">=</span> ALPHABET[value <span class="hljs-operator">&#x26;</span> <span class="hljs-number">0xf</span>];
            value <span class="hljs-operator">></span><span class="hljs-operator">></span><span class="hljs-operator">=</span> <span class="hljs-number">4</span>;
        }
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">string</span>(buffer);
    }
}
</code></pre><p>That&apos;s it for the contract code analysis.</p><p>Below we will provide a brief analysis of the front-end logic, and then we will implement the NFT minting and display functionality step by step. Before submitting front-end code, follow the steps below to add the functionality.</p><pre data-type="codeBlock" text="git checkout a98156f6a03a0bc8fc98c8c77cef6fbf59f03b31
"><code></code></pre><h2 id="h-0x03-front-end-logic-analysis" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x03 Front end logic analysis</h2><p>The project front-end files are in <code>packages/react-app</code>, and the locations of the files covered in the following articles will be found in this file.</p><blockquote><p>check App.jsx：</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/qiwihui/scaffold-eth/blob/loogies-svg-nft/packages/react-app/src/App.jsx">https://github.com/qiwihui/scaffold-eth/blob/loogies-svg-nft/packages/react-app/src/App.jsx</a></p></blockquote><p>First we take a look at <code>src/App.jsx</code>. It is the main component for the project. We can view it in our editor.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">Appjsx.png</figcaption></figure><p>It has sections and functions of:</p><ul><li><p><code>Header</code>: show title</p></li><li><p>_<code>NetworkDisplay</code>: show network</p></li><li><p>_<code>Menu</code>, <code>Switch</code>: show and switch menu</p></li><li><p>_<code>ThemeSwitch</code>: switch light and dark theme</p></li><li><p>_<code>Account</code>: show account info</p></li><li><p>And two <code>Row</code>s show gas and supported faucet in the lower left corner</p></li></ul><p>Then we take a look at _<code>NetworkDisplay</code> and <code>Account</code>&apos;s logic design, and functions in <code>Menu</code>, and <code>Switch</code>.</p><h3 id="h-networkdisplay" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0"><code>NetworkDisplay</code></h3><p>Component is at: <code>src/components/NetworkDisplay.jsx</code>.</p><p>With those two functions:</p><ol><li><p>Show current network;</p></li><li><p>If the current network is not supported, then show error. The network id for local network should be <code>31337</code>.</p></li></ol><pre data-type="codeBlock" text="function NetworkDisplay({
  NETWORKCHECK,
  localChainId,
  selectedChainId,
  targetNetwork,
  USE_NETWORK_SELECTOR,
  logoutOfWeb3Modal,
}) {
  let networkDisplay = &quot;&quot;;
  if (NETWORKCHECK &amp;&amp; localChainId &amp;&amp; selectedChainId &amp;&amp; localChainId !== selectedChainId) {
    const networkSelected = NETWORK(selectedChainId);
    const networkLocal = NETWORK(localChainId);
    if (selectedChainId === 1337 &amp;&amp; localChainId === 31337) {
            // show error network id
            ...
    } else {
            // show network is not correct
            ...
    }
  } else {
    networkDisplay = USE_NETWORK_SELECTOR ? null : (
      // show network name
      &lt;div style={{ zIndex: -1, position: &quot;absolute&quot;, right: 154, top: 28, padding: 16, color: targetNetwork.color }}&gt;
        {targetNetwork.name}
      &lt;/div&gt;
    );
  }

  console.log({ networkDisplay });

  return networkDisplay;
}
"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">NetworkDisplay</span>(<span class="hljs-params">{
  NETWORKCHECK,
  localChainId,
  selectedChainId,
  targetNetwork,
  USE_NETWORK_SELECTOR,
  logoutOfWeb3Modal,
}</span>) </span>{
  let networkDisplay <span class="hljs-operator">=</span> <span class="hljs-string">""</span>;
  <span class="hljs-keyword">if</span> (NETWORKCHECK <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span> localChainId <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span> selectedChainId <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span> localChainId <span class="hljs-operator">!</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span> selectedChainId) {
    const networkSelected <span class="hljs-operator">=</span> NETWORK(selectedChainId);
    const networkLocal <span class="hljs-operator">=</span> NETWORK(localChainId);
    <span class="hljs-keyword">if</span> (selectedChainId <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">1337</span> <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span> localChainId <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">31337</span>) {
            <span class="hljs-comment">// show error network id</span>
            ...
    } <span class="hljs-keyword">else</span> {
            <span class="hljs-comment">// show network is not correct</span>
            ...
    }
  } <span class="hljs-keyword">else</span> {
    networkDisplay <span class="hljs-operator">=</span> USE_NETWORK_SELECTOR ? null : (
      <span class="hljs-comment">// show network name</span>
      <span class="hljs-operator">&#x3C;</span>div style<span class="hljs-operator">=</span>{{ zIndex: <span class="hljs-number">-1</span>, position: <span class="hljs-string">"absolute"</span>, right: <span class="hljs-number">154</span>, top: <span class="hljs-number">28</span>, padding: <span class="hljs-number">16</span>, color: targetNetwork.color }}<span class="hljs-operator">></span>
        {targetNetwork.<span class="hljs-built_in">name</span>}
      <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">></span>
    );
  }

  console.log({ networkDisplay });

  <span class="hljs-keyword">return</span> networkDisplay;
}
</code></pre><h3 id="h-account" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0"><code>Account</code></h3><p>Component is at <code>src/components/Account.jsx</code>.</p><p>With those three functions:</p><ol><li><p>show current address</p></li><li><p>show address balance</p></li><li><p>show <code>Connect</code> or <code>Logout</code></p></li></ol><p>When user clicks <code>Connect</code>, the front end calls <code>loadWeb3Modal</code>. This function is needed to connect with wallets such as MetaMask and listen to the wallet&apos;s _ <code>chainChanged</code>, <code>accountsChanged</code> and <code>disconnect</code> events, i.e. to modify the display status when we switch networks, select connected accounts and cancel connections in the wallet.</p><pre data-type="codeBlock" text="const loadWeb3Modal = useCallback(async () =&gt; {
  // connect wallet
  const provider = await web3Modal.connect();
  setInjectedProvider(new ethers.providers.Web3Provider(provider));
  // listen to network switch
  provider.on(&apos;chainChanged&apos;, (chainId) =&gt; {
    console.log(`chain changed to ${chainId}! updating providers`);
    setInjectedProvider(new ethers.providers.Web3Provider(provider));
  });
  // listen to changed accounts
  provider.on(&apos;accountsChanged&apos;, () =&gt; {
    console.log(`account changed!`);
    setInjectedProvider(new ethers.providers.Web3Provider(provider));
  });
  // Subscribe to session disconnection
  provider.on(&apos;disconnect&apos;, (code, reason) =&gt; {
    console.log(code, reason);
    logoutOfWeb3Modal();
  });
  // eslint-disable-next-line
}, [setInjectedProvider]);
"><code>const loadWeb3Modal <span class="hljs-operator">=</span> useCallback(async () <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
  <span class="hljs-comment">// connect wallet</span>
  const provider <span class="hljs-operator">=</span> await web3Modal.connect();
  setInjectedProvider(<span class="hljs-keyword">new</span> ethers.providers.Web3Provider(provider));
  <span class="hljs-comment">// listen to network switch</span>
  provider.on(<span class="hljs-string">'chainChanged'</span>, (chainId) <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
    console.log(`chain changed to ${chainId}<span class="hljs-operator">!</span> updating providers`);
    setInjectedProvider(<span class="hljs-keyword">new</span> ethers.providers.Web3Provider(provider));
  });
  <span class="hljs-comment">// listen to changed accounts</span>
  provider.on(<span class="hljs-string">'accountsChanged'</span>, () <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
    console.log(`account changed<span class="hljs-operator">!</span>`);
    setInjectedProvider(<span class="hljs-keyword">new</span> ethers.providers.Web3Provider(provider));
  });
  <span class="hljs-comment">// Subscribe to session disconnection</span>
  provider.on(<span class="hljs-string">'disconnect'</span>, (code, reason) <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
    console.log(code, reason);
    logoutOfWeb3Modal();
  });
  <span class="hljs-comment">// eslint-disable-next-line</span>
}, [setInjectedProvider]);
</code></pre><p>Similarly, in the case of a connected wallet, the user clicks <code>Logout</code> to call the <code>logoutOfWeb3Modal</code> function.</p><pre data-type="codeBlock" text="const logoutOfWeb3Modal = async () =&gt; {
  // clear cached network provider and disconnect
  await web3Modal.clearCachedProvider();
  if (
    injectedProvider &amp;&amp;
    injectedProvider.provider &amp;&amp;
    typeof injectedProvider.provider.disconnect == &apos;function&apos;
  ) {
    await injectedProvider.provider.disconnect();
  }
  setTimeout(() =&gt; {
    window.location.reload();
  }, 1);
};
"><code>const logoutOfWeb3Modal <span class="hljs-operator">=</span> async () <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
  <span class="hljs-comment">// clear cached network provider and disconnect</span>
  await web3Modal.clearCachedProvider();
  <span class="hljs-keyword">if</span> (
    injectedProvider <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span>
    injectedProvider.provider <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span>
    typeof injectedProvider.provider.disconnect <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-string">'function'</span>
  ) {
    await injectedProvider.provider.disconnect();
  }
  setTimeout(() <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
    window.location.reload();
  }, <span class="hljs-number">1</span>);
};
</code></pre><h3 id="h-menu-switch" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0"><code>Menu</code>， <code>Switch</code></h3><p>These two correspond to the display menu and correspond to the switch menu functions, these menus include:</p><ul><li><p><code>App Home</code>: the project wants us to put the functions we need to implement in this menu, such as the minting and display functions of NFT that we will implement.</p></li><li><p><code>Debug Contracts</code>: debug their own written contract functions, will be based on the contract&apos;s ABI file to show the state variables and functions that can be called.</p></li><li><p><code>Hints</code>: hints for coding.</p></li><li><p><code>ExampleUI</code>: sample UI, which can be used for programming purposes.</p></li><li><p><code>Mainnet DAI</code>: the state of the contracts and available functions of the <code>DAI</code> network, with the same functionality as <code>Debug Contracts</code>.</p></li><li><p><code>Subgraph</code>: Listening and querying for events in contracts using The Graph protocol.</p></li></ul><h3 id="h-debug-output" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Debug output</h3><p><code>App.jsx</code> also has debugging output that prints the current page status, allowing you to view the current status variables in real time during development.</p><pre data-type="codeBlock" text="//
// 🧫 DEBUG 👨🏻‍🔬
//
useEffect(() =&gt; {
  if (
    DEBUG &amp;&amp;
    mainnetProvider &amp;&amp;
    address &amp;&amp;
    selectedChainId &amp;&amp;
    yourLocalBalance &amp;&amp;
    yourMainnetBalance &amp;&amp;
    readContracts &amp;&amp;
    writeContracts &amp;&amp;
    mainnetContracts
  ) {
    console.log(
      &apos;_____________________________________ 🏗 scaffold-eth _____________________________________&apos;,
    );
    console.log(&apos;🌎 mainnetProvider&apos;, mainnetProvider);
    console.log(&apos;🏠 localChainId&apos;, localChainId);
    console.log(&apos;👩‍💼 selected address:&apos;, address);
    console.log(&apos;🕵🏻‍♂️ selectedChainId:&apos;, selectedChainId);
    console.log(
      &apos;💵 yourLocalBalance&apos;,
      yourLocalBalance ? ethers.utils.formatEther(yourLocalBalance) : &apos;...&apos;,
    );
    console.log(
      &apos;💵 yourMainnetBalance&apos;,
      yourMainnetBalance ? ethers.utils.formatEther(yourMainnetBalance) : &apos;...&apos;,
    );
    console.log(&apos;📝 readContracts&apos;, readContracts);
    console.log(&apos;🌍 DAI contract on mainnet:&apos;, mainnetContracts);
    console.log(&apos;💵 yourMainnetDAIBalance&apos;, myMainnetDAIBalance);
    console.log(&apos;🔐 writeContracts&apos;, writeContracts);
  }
}, [
  mainnetProvider,
  address,
  selectedChainId,
  yourLocalBalance,
  yourMainnetBalance,
  readContracts,
  writeContracts,
  mainnetContracts,
  localChainId,
  myMainnetDAIBalance,
]);
"><code><span class="hljs-comment">//</span>
<span class="hljs-comment">// 🧫 DEBUG 👨🏻‍🔬</span>
<span class="hljs-comment">//</span>
useEffect(() <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
  <span class="hljs-keyword">if</span> (
    DEBUG <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span>
    mainnetProvider <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span>
    <span class="hljs-keyword">address</span> <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span>
    selectedChainId <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span>
    yourLocalBalance <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span>
    yourMainnetBalance <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span>
    readContracts <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span>
    writeContracts <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span>
    mainnetContracts
  ) {
    console.log(
      <span class="hljs-string">'_____________________________________ 🏗 scaffold-eth _____________________________________'</span>,
    );
    console.log(<span class="hljs-string">'🌎 mainnetProvider'</span>, mainnetProvider);
    console.log(<span class="hljs-string">'🏠 localChainId'</span>, localChainId);
    console.log(<span class="hljs-string">'👩‍💼 selected address:'</span>, <span class="hljs-keyword">address</span>);
    console.log(<span class="hljs-string">'🕵🏻‍♂️ selectedChainId:'</span>, selectedChainId);
    console.log(
      <span class="hljs-string">'💵 yourLocalBalance'</span>,
      yourLocalBalance ? ethers.utils.formatEther(yourLocalBalance) : <span class="hljs-string">'...'</span>,
    );
    console.log(
      <span class="hljs-string">'💵 yourMainnetBalance'</span>,
      yourMainnetBalance ? ethers.utils.formatEther(yourMainnetBalance) : <span class="hljs-string">'...'</span>,
    );
    console.log(<span class="hljs-string">'📝 readContracts'</span>, readContracts);
    console.log(<span class="hljs-string">'🌍 DAI contract on mainnet:'</span>, mainnetContracts);
    console.log(<span class="hljs-string">'💵 yourMainnetDAIBalance'</span>, myMainnetDAIBalance);
    console.log(<span class="hljs-string">'🔐 writeContracts'</span>, writeContracts);
  }
}, [
  mainnetProvider,
  <span class="hljs-keyword">address</span>,
  selectedChainId,
  yourLocalBalance,
  yourMainnetBalance,
  readContracts,
  writeContracts,
  mainnetContracts,
  localChainId,
  myMainnetDAIBalance,
]);
</code></pre><p>After viewing the basic functions of the home page, we start implementing the two functions of NFT minting and displaying the NFT list.</p><h2 id="h-0x04-nft-functions" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x04 NFT functions</h2><p>We will implement the following three main components of functionality.</p><ul><li><p>Minting NFTs;</p></li><li><p>Displaying the NFT list;</p></li><li><p>Displaying a list of NFT contract interfaces.</p></li></ul><h3 id="h-minting-nft" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Minting NFT</h3><p>First we find the component corresponding to <code>App Home</code>, as you can see from the code below, which uses the <code>Home</code> component, located at <code>src/views/Home.jsx</code>.</p><pre data-type="codeBlock" text="    ...
    &lt;Switch&gt;
        &lt;Route exact path=&quot;/&quot;&gt;
          {/* pass in any web3 props to this Home component. For example, yourLocalBalance */}
          &lt;Home yourLocalBalance={yourLocalBalance} readContracts={readContracts} /&gt;
        &lt;/Route&gt;
    ....
"><code>    ...
    <span class="hljs-operator">&#x3C;</span>Switch<span class="hljs-operator">></span>
        <span class="hljs-operator">&#x3C;</span>Route exact path<span class="hljs-operator">=</span><span class="hljs-string">"/"</span><span class="hljs-operator">></span>
          {<span class="hljs-comment">/* pass in any web3 props to this Home component. For example, yourLocalBalance */</span>}
          <span class="hljs-operator">&#x3C;</span>Home yourLocalBalance<span class="hljs-operator">=</span>{yourLocalBalance} readContracts<span class="hljs-operator">=</span>{readContracts} <span class="hljs-operator">/</span><span class="hljs-operator">></span>
        <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>Route<span class="hljs-operator">></span>
    ....
</code></pre><p>Delete contents in <code>Home.jsx</code> and add the following Mint button:</p><pre data-type="codeBlock" text="import React, { useState } from &apos;react&apos;;
import { Button, Card, List } from &apos;antd&apos;;

function Home({ isSigner, loadWeb3Modal, tx, writeContracts }) {
  return (
    &lt;div&gt;
      {/* Mint button */}
      &lt;div
        style={{
          maxWidth: 820,
          margin: &apos;auto&apos;,
          marginTop: 32,
          paddingBottom: 32,
        }}
      &gt;
        {isSigner ? (
          &lt;Button
            type={&apos;primary&apos;}
            onClick={() =&gt; {
              tx(writeContracts.YourCollectible.mintItem());
            }}
          &gt;
            MINT
          &lt;/Button&gt;
        ) : (
          &lt;Button type={&apos;primary&apos;} onClick={loadWeb3Modal}&gt;
            CONNECT WALLET
          &lt;/Button&gt;
        )}
      &lt;/div&gt;
    &lt;/div&gt;
  );
}

export default Home;
"><code><span class="hljs-keyword">import</span> <span class="hljs-title">React</span>, { <span class="hljs-title">useState</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">Button</span>, <span class="hljs-title">Card</span>, <span class="hljs-title">List</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'antd'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params">{ isSigner, loadWeb3Modal, <span class="hljs-built_in">tx</span>, writeContracts }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="hljs-operator">&#x3C;</span>div<span class="hljs-operator">></span>
      {<span class="hljs-comment">/* Mint button */</span>}
      <span class="hljs-operator">&#x3C;</span>div
        style<span class="hljs-operator">=</span>{{
          maxWidth: <span class="hljs-number">820</span>,
          margin: <span class="hljs-string">'auto'</span>,
          marginTop: <span class="hljs-number">32</span>,
          paddingBottom: <span class="hljs-number">32</span>,
        }}
      <span class="hljs-operator">></span>
        {isSigner ? (
          <span class="hljs-operator">&#x3C;</span>Button
            <span class="hljs-keyword">type</span><span class="hljs-operator">=</span>{<span class="hljs-string">'primary'</span>}
            onClick<span class="hljs-operator">=</span>{() <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
              <span class="hljs-built_in">tx</span>(writeContracts.YourCollectible.mintItem());
            }}
          <span class="hljs-operator">></span>
            MINT
          <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>Button<span class="hljs-operator">></span>
        ) : (
          <span class="hljs-operator">&#x3C;</span>Button <span class="hljs-keyword">type</span><span class="hljs-operator">=</span>{<span class="hljs-string">'primary'</span>} onClick<span class="hljs-operator">=</span>{loadWeb3Modal}<span class="hljs-operator">></span>
            CONNECT WALLET
          <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>Button<span class="hljs-operator">></span>
        )}
      <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">></span>
    <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">></span>
  );
}

export default Home;
</code></pre><p>Change <code>Switch</code>&apos;s component into:</p><pre data-type="codeBlock" text="      ...
      &lt;Switch&gt;
        &lt;Route exact path=&quot;/&quot;&gt;
          {/* pass in any web3 props to this Home component. For example, yourLocalBalance */}
          &lt;Home
            isSigner={userSigner}
            loadWeb3Modal={loadWeb3Modal}
            tx={tx}
            writeContracts={writeContracts}
          /&gt;
       ...
"><code>      ...
      <span class="hljs-operator">&#x3C;</span>Switch<span class="hljs-operator">></span>
        <span class="hljs-operator">&#x3C;</span>Route exact path<span class="hljs-operator">=</span><span class="hljs-string">"/"</span><span class="hljs-operator">></span>
          {<span class="hljs-comment">/* pass in any web3 props to this Home component. For example, yourLocalBalance */</span>}
          <span class="hljs-operator">&#x3C;</span>Home
            isSigner<span class="hljs-operator">=</span>{userSigner}
            loadWeb3Modal<span class="hljs-operator">=</span>{loadWeb3Modal}
            <span class="hljs-built_in">tx</span><span class="hljs-operator">=</span>{<span class="hljs-built_in">tx</span>}
            writeContracts<span class="hljs-operator">=</span>{writeContracts}
          <span class="hljs-operator">/</span><span class="hljs-operator">></span>
       ...
</code></pre><p>It should look like this:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">mint-button</figcaption></figure><p>After clicking Mint, we can see that the transaction was successfully issued, at this point, although we successfully minted the NFT, we still need to add the list to show our NFT.</p><h3 id="h-show-nft-list" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Show NFT list</h3><p>Add a list to display containing the NFT can be transferred to other addresses.</p><pre data-type="codeBlock" text="import React, { useState } from &apos;react&apos;;
import { Button, Card, List } from &apos;antd&apos;;
import { useContractReader } from &apos;eth-hooks&apos;;
import { Address, AddressInput } from &apos;../components&apos;;

function Home({
  isSigner,
  loadWeb3Modal,
  yourCollectibles,
  address,
  blockExplorer,
  mainnetProvider,
  tx,
  readContracts,
  writeContracts,
}) {
  const [transferToAddresses, setTransferToAddresses] = useState({});

  return (
    &lt;div&gt;
      {/* Mint button */}
      ...
      {/* List */}
      &lt;div style={{ width: 820, margin: &apos;auto&apos;, paddingBottom: 256 }}&gt;
        &lt;List
          bordered
          dataSource={yourCollectibles}
          renderItem={(item) =&gt; {
            const id = item.id.toNumber();
            console.log(&apos;IMAGE&apos;, item.image);
            return (
              &lt;List.Item key={id + &apos;_&apos; + item.uri + &apos;_&apos; + item.owner}&gt;
                &lt;Card
                  title={
                    &lt;div&gt;
                      &lt;span style={{ fontSize: 18, marginRight: 8 }}&gt;
                        {item.name}
                      &lt;/span&gt;
                    &lt;/div&gt;
                  }
                &gt;
                  &lt;a
                    href={
                      &apos;https://opensea.io/assets/&apos; +
                      (readContracts &amp;&amp;
                        readContracts.YourCollectible &amp;&amp;
                        readContracts.YourCollectible.address) +
                      &apos;/&apos; +
                      item.id
                    }
                    target=&apos;_blank&apos;
                  &gt;
                    &lt;img src={item.image} /&gt;
                  &lt;/a&gt;
                  &lt;div&gt;{item.description}&lt;/div&gt;
                &lt;/Card&gt;
                {/* NFT transfering */}
                &lt;div&gt;
                  owner:{&apos; &apos;}
                  &lt;Address
                    address={item.owner}
                    ensProvider={mainnetProvider}
                    blockExplorer={blockExplorer}
                    fontSize={16}
                  /&gt;
                  &lt;AddressInput
                    ensProvider={mainnetProvider}
                    placeholder=&apos;transfer to address&apos;
                    value={transferToAddresses[id]}
                    onChange={(newValue) =&gt; {
                      const update = {};
                      update[id] = newValue;
                      setTransferToAddresses({
                        ...transferToAddresses,
                        ...update,
                      });
                    }}
                  /&gt;
                  &lt;Button
                    onClick={() =&gt; {
                      console.log(&apos;writeContracts&apos;, writeContracts);
                      tx(
                        writeContracts.YourCollectible.transferFrom(
                          address,
                          transferToAddresses[id],
                          id,
                        ),
                      );
                    }}
                  &gt;
                    Transfer
                  &lt;/Button&gt;
                &lt;/div&gt;
              &lt;/List.Item&gt;
            );
          }}
        /&gt;
      &lt;/div&gt;
      {/* Display info */}
      &lt;div
        style={{
          maxWidth: 820,
          margin: &apos;auto&apos;,
          marginTop: 32,
          paddingBottom: 256,
        }}
      &gt;
        🛠 built with{&apos; &apos;}
        &lt;a
          href=&apos;https://github.com/austintgriffith/scaffold-eth&apos;
          target=&apos;_blank&apos;
        &gt;
          🏗 scaffold-eth
        &lt;/a&gt;
        🍴 &lt;a
          href=&apos;https://github.com/austintgriffith/scaffold-eth&apos;
          target=&apos;_blank&apos;
        &gt;
          Fork this repo
        &lt;/a&gt; and build a cool SVG NFT!
      &lt;/div&gt;
    &lt;/div&gt;
  );
}

export default Home;
"><code><span class="hljs-keyword">import</span> <span class="hljs-title">React</span>, { <span class="hljs-title">useState</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">Button</span>, <span class="hljs-title">Card</span>, <span class="hljs-title">List</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'antd'</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">useContractReader</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'eth-hooks'</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">Address</span>, <span class="hljs-title">AddressInput</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'../components'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params">{
  isSigner,
  loadWeb3Modal,
  yourCollectibles,
  <span class="hljs-keyword">address</span>,
  blockExplorer,
  mainnetProvider,
  <span class="hljs-built_in">tx</span>,
  readContracts,
  writeContracts,
}</span>) </span>{
  const [transferToAddresses, setTransferToAddresses] <span class="hljs-operator">=</span> useState({});

  <span class="hljs-keyword">return</span> (
    <span class="hljs-operator">&#x3C;</span>div<span class="hljs-operator">></span>
      {<span class="hljs-comment">/* Mint button */</span>}
      ...
      {<span class="hljs-comment">/* List */</span>}
      <span class="hljs-operator">&#x3C;</span>div style<span class="hljs-operator">=</span>{{ width: <span class="hljs-number">820</span>, margin: <span class="hljs-string">'auto'</span>, paddingBottom: <span class="hljs-number">256</span> }}<span class="hljs-operator">></span>
        <span class="hljs-operator">&#x3C;</span>List
          bordered
          dataSource<span class="hljs-operator">=</span>{yourCollectibles}
          renderItem<span class="hljs-operator">=</span>{(item) <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
            const id <span class="hljs-operator">=</span> item.id.toNumber();
            console.log(<span class="hljs-string">'IMAGE'</span>, item.image);
            <span class="hljs-keyword">return</span> (
              <span class="hljs-operator">&#x3C;</span>List.Item key<span class="hljs-operator">=</span>{id <span class="hljs-operator">+</span> <span class="hljs-string">'_'</span> <span class="hljs-operator">+</span> item.uri <span class="hljs-operator">+</span> <span class="hljs-string">'_'</span> <span class="hljs-operator">+</span> item.owner}<span class="hljs-operator">></span>
                <span class="hljs-operator">&#x3C;</span>Card
                  title<span class="hljs-operator">=</span>{
                    <span class="hljs-operator">&#x3C;</span>div<span class="hljs-operator">></span>
                      <span class="hljs-operator">&#x3C;</span>span style<span class="hljs-operator">=</span>{{ fontSize: <span class="hljs-number">18</span>, marginRight: <span class="hljs-number">8</span> }}<span class="hljs-operator">></span>
                        {item.<span class="hljs-built_in">name</span>}
                      <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>span<span class="hljs-operator">></span>
                    <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">></span>
                  }
                <span class="hljs-operator">></span>
                  <span class="hljs-operator">&#x3C;</span>a
                    href<span class="hljs-operator">=</span>{
                      <span class="hljs-string">'https://opensea.io/assets/'</span> <span class="hljs-operator">+</span>
                      (readContracts <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span>
                        readContracts.YourCollectible <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span>
                        readContracts.YourCollectible.<span class="hljs-built_in">address</span>) <span class="hljs-operator">+</span>
                      <span class="hljs-string">'/'</span> <span class="hljs-operator">+</span>
                      item.id
                    }
                    target<span class="hljs-operator">=</span><span class="hljs-string">'_blank'</span>
                  <span class="hljs-operator">></span>
                    <span class="hljs-operator">&#x3C;</span>img src<span class="hljs-operator">=</span>{item.image} <span class="hljs-operator">/</span><span class="hljs-operator">></span>
                  <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>a<span class="hljs-operator">></span>
                  <span class="hljs-operator">&#x3C;</span>div<span class="hljs-operator">></span>{item.description}<span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">></span>
                <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>Card<span class="hljs-operator">></span>
                {<span class="hljs-comment">/* NFT transfering */</span>}
                <span class="hljs-operator">&#x3C;</span>div<span class="hljs-operator">></span>
                  owner:{<span class="hljs-string">' '</span>}
                  <span class="hljs-operator">&#x3C;</span>Address
                    <span class="hljs-keyword">address</span><span class="hljs-operator">=</span>{item.owner}
                    ensProvider<span class="hljs-operator">=</span>{mainnetProvider}
                    blockExplorer<span class="hljs-operator">=</span>{blockExplorer}
                    fontSize<span class="hljs-operator">=</span>{<span class="hljs-number">16</span>}
                  <span class="hljs-operator">/</span><span class="hljs-operator">></span>
                  <span class="hljs-operator">&#x3C;</span>AddressInput
                    ensProvider<span class="hljs-operator">=</span>{mainnetProvider}
                    placeholder<span class="hljs-operator">=</span><span class="hljs-string">'transfer to address'</span>
                    value<span class="hljs-operator">=</span>{transferToAddresses[id]}
                    onChange<span class="hljs-operator">=</span>{(newValue) <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
                      const update <span class="hljs-operator">=</span> {};
                      update[id] <span class="hljs-operator">=</span> newValue;
                      setTransferToAddresses({
                        ...transferToAddresses,
                        ...update,
                      });
                    }}
                  <span class="hljs-operator">/</span><span class="hljs-operator">></span>
                  <span class="hljs-operator">&#x3C;</span>Button
                    onClick<span class="hljs-operator">=</span>{() <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
                      console.log(<span class="hljs-string">'writeContracts'</span>, writeContracts);
                      <span class="hljs-built_in">tx</span>(
                        writeContracts.YourCollectible.transferFrom(
                          <span class="hljs-keyword">address</span>,
                          transferToAddresses[id],
                          id,
                        ),
                      );
                    }}
                  <span class="hljs-operator">></span>
                    Transfer
                  <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>Button<span class="hljs-operator">></span>
                <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">></span>
              <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>List.Item>
            );
          }}
        <span class="hljs-operator">/</span><span class="hljs-operator">></span>
      <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">></span>
      {<span class="hljs-comment">/* Display info */</span>}
      <span class="hljs-operator">&#x3C;</span>div
        style<span class="hljs-operator">=</span>{{
          maxWidth: <span class="hljs-number">820</span>,
          margin: <span class="hljs-string">'auto'</span>,
          marginTop: <span class="hljs-number">32</span>,
          paddingBottom: <span class="hljs-number">256</span>,
        }}
      <span class="hljs-operator">></span>
        🛠 built with{<span class="hljs-string">' '</span>}
        <span class="hljs-operator">&#x3C;</span>a
          href<span class="hljs-operator">=</span><span class="hljs-string">'https://github.com/austintgriffith/scaffold-eth'</span>
          target<span class="hljs-operator">=</span><span class="hljs-string">'_blank'</span>
        <span class="hljs-operator">></span>
          🏗 scaffold<span class="hljs-operator">-</span>eth
        <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>a<span class="hljs-operator">></span>
        🍴 <span class="hljs-operator">&#x3C;</span>a
          href<span class="hljs-operator">=</span><span class="hljs-string">'https://github.com/austintgriffith/scaffold-eth'</span>
          target<span class="hljs-operator">=</span><span class="hljs-string">'_blank'</span>
        <span class="hljs-operator">></span>
          Fork <span class="hljs-built_in">this</span> repo
        <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>a<span class="hljs-operator">></span> and build a cool SVG NFT<span class="hljs-operator">!</span>
      <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">></span>
    <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">></span>
  );
}

export default Home;
</code></pre><p>Change the component into:</p><pre data-type="codeBlock" text="      ...
      &lt;Switch&gt;
        &lt;Route exact path=&quot;/&quot;&gt;
          {/* pass in any web3 props to this Home component. For example, yourLocalBalance */}
          &lt;Home
            isSigner={userSigner}
            loadWeb3Modal={loadWeb3Modal}
            yourCollectibles={yourCollectibles}
            address={address}
            blockExplorer={blockExplorer}
            mainnetProvider={mainnetProvider}
            tx={tx}
            writeContracts={writeContracts}
            readContracts={readContracts}
          /&gt;
       ...
"><code>      ...
      <span class="hljs-operator">&#x3C;</span>Switch<span class="hljs-operator">></span>
        <span class="hljs-operator">&#x3C;</span>Route exact path<span class="hljs-operator">=</span><span class="hljs-string">"/"</span><span class="hljs-operator">></span>
          {<span class="hljs-comment">/* pass in any web3 props to this Home component. For example, yourLocalBalance */</span>}
          <span class="hljs-operator">&#x3C;</span>Home
            isSigner<span class="hljs-operator">=</span>{userSigner}
            loadWeb3Modal<span class="hljs-operator">=</span>{loadWeb3Modal}
            yourCollectibles<span class="hljs-operator">=</span>{yourCollectibles}
            <span class="hljs-keyword">address</span><span class="hljs-operator">=</span>{<span class="hljs-keyword">address</span>}
            blockExplorer<span class="hljs-operator">=</span>{blockExplorer}
            mainnetProvider<span class="hljs-operator">=</span>{mainnetProvider}
            <span class="hljs-built_in">tx</span><span class="hljs-operator">=</span>{<span class="hljs-built_in">tx</span>}
            writeContracts<span class="hljs-operator">=</span>{writeContracts}
            readContracts<span class="hljs-operator">=</span>{readContracts}
          <span class="hljs-operator">/</span><span class="hljs-operator">></span>
       ...
</code></pre><p>It should look like this:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">nft-display-list</figcaption></figure><p>But we found that when we mint again, the list doesn&apos;t update, it&apos;s still the same, so we need to add an event listener to <code>App.jsx</code> that will refresh the list once we mint NFT:</p><pre data-type="codeBlock" text="// Track current NFT numbers
const balance = useContractReader(
  readContracts,
  &apos;YourCollectible&apos;,
  &apos;balanceOf&apos;,
  [address],
);
console.log(&apos;🤗 balance:&apos;, balance);

const yourBalance = balance &amp;&amp; balance.toNumber &amp;&amp; balance.toNumber();
const [yourCollectibles, setYourCollectibles] = useState();
//
// 🧠 This useEffect hook updates yourCollectibles when balance is changing.
//
useEffect(() =&gt; {
  const updateYourCollectibles = async () =&gt; {
    const collectibleUpdate = [];
    for (let tokenIndex = 0; tokenIndex &lt; balance; tokenIndex++) {
      try {
        console.log(&apos;GEtting token index&apos;, tokenIndex);
        const tokenId = await readContracts.YourCollectible.tokenOfOwnerByIndex(
          address,
          tokenIndex,
        );
        console.log(&apos;tokenId&apos;, tokenId);
        const tokenURI = await readContracts.YourCollectible.tokenURI(tokenId);
        const jsonManifestString = atob(tokenURI.substring(29));
        console.log(&apos;jsonManifestString&apos;, jsonManifestString);

        try {
          const jsonManifest = JSON.parse(jsonManifestString);
          console.log(&apos;jsonManifest&apos;, jsonManifest);
          collectibleUpdate.push({
            id: tokenId,
            uri: tokenURI,
            owner: address,
            ...jsonManifest,
          });
        } catch (e) {
          console.log(e);
        }
      } catch (e) {
        console.log(e);
      }
    }
    setYourCollectibles(collectibleUpdate.reverse());
  };
  updateYourCollectibles();
}, [address, yourBalance]);
"><code><span class="hljs-comment">// Track current NFT numbers</span>
const balance <span class="hljs-operator">=</span> useContractReader(
  readContracts,
  <span class="hljs-string">'YourCollectible'</span>,
  <span class="hljs-string">'balanceOf'</span>,
  [<span class="hljs-keyword">address</span>],
);
console.log(<span class="hljs-string">'🤗 balance:'</span>, balance);

const yourBalance <span class="hljs-operator">=</span> balance <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span> balance.toNumber <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span> balance.toNumber();
const [yourCollectibles, setYourCollectibles] <span class="hljs-operator">=</span> useState();
<span class="hljs-comment">//</span>
<span class="hljs-comment">// 🧠 This useEffect hook updates yourCollectibles when balance is changing.</span>
<span class="hljs-comment">//</span>
useEffect(() <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
  const updateYourCollectibles <span class="hljs-operator">=</span> async () <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
    const collectibleUpdate <span class="hljs-operator">=</span> [];
    <span class="hljs-keyword">for</span> (let tokenIndex <span class="hljs-operator">=</span> <span class="hljs-number">0</span>; tokenIndex <span class="hljs-operator">&#x3C;</span> balance; tokenIndex<span class="hljs-operator">+</span><span class="hljs-operator">+</span>) {
      <span class="hljs-keyword">try</span> {
        console.log(<span class="hljs-string">'GEtting token index'</span>, tokenIndex);
        const tokenId <span class="hljs-operator">=</span> await readContracts.YourCollectible.tokenOfOwnerByIndex(
          <span class="hljs-keyword">address</span>,
          tokenIndex,
        );
        console.log(<span class="hljs-string">'tokenId'</span>, tokenId);
        const tokenURI <span class="hljs-operator">=</span> await readContracts.YourCollectible.tokenURI(tokenId);
        const jsonManifestString <span class="hljs-operator">=</span> atob(tokenURI.substring(<span class="hljs-number">29</span>));
        console.log(<span class="hljs-string">'jsonManifestString'</span>, jsonManifestString);

        <span class="hljs-keyword">try</span> {
          const jsonManifest <span class="hljs-operator">=</span> JSON.parse(jsonManifestString);
          console.log(<span class="hljs-string">'jsonManifest'</span>, jsonManifest);
          collectibleUpdate.<span class="hljs-built_in">push</span>({
            id: tokenId,
            uri: tokenURI,
            owner: <span class="hljs-keyword">address</span>,
            ...jsonManifest,
          });
        } <span class="hljs-keyword">catch</span> (e) {
          console.log(e);
        }
      } <span class="hljs-keyword">catch</span> (e) {
        console.log(e);
      }
    }
    setYourCollectibles(collectibleUpdate.reverse());
  };
  updateYourCollectibles();
}, [<span class="hljs-keyword">address</span>, yourBalance]);
</code></pre><p>At this point, when we mint again, the list is automatically updated to show the latest NFT.</p><h3 id="h-show-nft-contract-abi-list" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Show NFT contract ABI list</h3><p>This function is relatively simple and requires only the following changes to the corresponding debug section:</p><pre data-type="codeBlock" text="      &lt;Route exact path=&quot;/debug&quot;&gt;
          {/*
                🎛 this scaffolding is full of commonly used components
                this &lt;Contract/&gt; component will automatically parse your ABI
                and give you a form to interact with it locally
            */}

          &lt;Contract
            name=&quot;YourCollectible&quot;
            price={price}
            signer={userSigner}
            provider={localProvider}
            address={address}
            blockExplorer={blockExplorer}
            contractConfig={contractConfig}
          /&gt;
"><code>      <span class="hljs-operator">&#x3C;</span>Route exact path<span class="hljs-operator">=</span><span class="hljs-string">"/debug"</span><span class="hljs-operator">></span>
          {<span class="hljs-comment">/*
                🎛 this scaffolding is full of commonly used components
                this &#x3C;Contract/> component will automatically parse your ABI
                and give you a form to interact with it locally
            */</span>}

          <span class="hljs-operator">&#x3C;</span>Contract
            name<span class="hljs-operator">=</span><span class="hljs-string">"YourCollectible"</span>
            price<span class="hljs-operator">=</span>{price}
            signer<span class="hljs-operator">=</span>{userSigner}
            provider<span class="hljs-operator">=</span>{localProvider}
            <span class="hljs-keyword">address</span><span class="hljs-operator">=</span>{<span class="hljs-keyword">address</span>}
            blockExplorer<span class="hljs-operator">=</span>{blockExplorer}
            contractConfig<span class="hljs-operator">=</span>{contractConfig}
          <span class="hljs-operator">/</span><span class="hljs-operator">></span>
</code></pre><p>更新之后，可以在 <code>Debug Contracts</code> 菜单下看到合约的可以调用的函数。</p><p>After the update, you can see the callable functions of the contract under the <code>Debug Contracts</code> menu:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">contract-funcs</figcaption></figure><p>At this point, we are done with a simple NFT minting and display DApp.</p><h2 id="h-0x05-conclusion" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x05 Conclusion</h2><p>Through this project, we learnt and understood the following knowledge:</p><ol><li><p>the basic of NFT contracts and how to upload NFT in marketplaces such as OpenSea.</p></li><li><p>how the DApp front-end connects to wallets such as MetaMask.</p></li><li><p>how to call contract functions on the front end.</p></li></ol><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">msfew</figcaption></figure>]]></content:encoded>
            <author>apecoder@newsletter.paragraph.com (Web3dAppDevCamp)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/9cb5da88fe2456a589702ed1286542b7de436f147792069c1b1bcd03a106a1a6.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[How to Make a Syncer based on Moonscan API | Moonbeam Branch 0x02]]></title>
            <link>https://paragraph.com/@apecoder/how-to-make-a-syncer-based-on-moonscan-api-moonbeam-branch-0x02</link>
            <guid>OJpgQdrMZuV3X2Lu2YsR</guid>
            <pubDate>Wed, 09 Feb 2022 13:12:43 GMT</pubDate>
            <description><![CDATA[国内用户如需交流，可加微信：197626581.MoonbeamScan ： https://moonbeam.moonscan.io/ Web3DevNFT Contract in this article： https://moonbeam.moonscan.io/address/0xb6FC950C4bC9D1e4652CbEDaB748E8Cdcfe5655FBasic ConceptWhat is a Syncer? It&apos;s a scheduled job to retrieve transactions from one contract regularly and persist them locally. The Syncer has two main parts:Syncer: responsible for retrieving transactions from the contract and persistence handling.Syncer Server: repsonsible for job scheduling and monit...]]></description>
            <content:encoded><![CDATA[<blockquote><p>国内用户如需交流，可加微信：197626581.</p></blockquote><blockquote><p>MoonbeamScan ：</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://moonbeam.moonscan.io/">https://moonbeam.moonscan.io/</a></p><p><code>Web3DevNFT</code> Contract in this article：</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://moonbeam.moonscan.io/address/0xb6FC950C4bC9D1e4652CbEDaB748E8Cdcfe5655F">https://moonbeam.moonscan.io/address/0xb6FC950C4bC9D1e4652CbEDaB748E8Cdcfe5655F</a></p></blockquote><h2 id="h-basic-concept" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Basic Concept</h2><p>What is a Syncer? It&apos;s a scheduled job to retrieve transactions from one contract regularly and persist them locally.</p><p>The Syncer has two main parts:</p><ul><li><p><code>Syncer</code>: responsible for retrieving transactions from the contract and persistence handling.</p></li><li><p><code>Syncer Server</code>: repsonsible for job scheduling and monitoring.</p></li><li><p><code>Parser</code>：Parse the transactions.</p></li></ul><p>Syncer is useful, because it formats and caches on-chain data, allowing various dApps and services to read on-chain data more quickly, improving the experience.</p><p>The traditional Syncer is implemented by connecting blockchain nodes, which has the advantage of being more stable, but we also have a lighter option -- to implement Syncer by calling the API of the Etherscan-like browser! Etherscan provides an interface to get all transactions of a specific contract, so we can do Syncer with lower complexity. This doesn&apos;t sound so Web3 because Syncer relies on the browser service to function properly, but in most scenarios, it works well!</p><h2 id="h-implementation-in-elixir" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Implementation in Elixir</h2><blockquote><p>Repo：</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/WeLightProject/tai_shang_nft_gallery">https://github.com/WeLightProject/tai_shang_nft_gallery</a></p></blockquote><h3 id="h-syncer" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Syncer</h3><p>The processing logic of Syncer contain below three main steps:</p><ol><li><p>Retrieves the latest block number of the blockchain.</p></li><li><p>Based on the last locally persited block number, retrieves transactions from the chain using Etherscan API and persist locally.</p></li><li><p>Update last block number of the contract locally.</p></li></ol><pre data-type="codeBlock" text="# https://github.com/WeLightProject/tai_shang_nft_gallery/blob/main/lib/tai_shang_nft_gallery/nft/syncer.ex

defmodule TaiShangNftGallery.Nft.Syncer do
  alias TaiShangNftGallery.NftContract
  alias TaiShangNftGallery.TxHandler
  alias TaiShangNftGallery.Chain.Fetcher
  alias TaiShangNftGallery.ScanInteractor
  require Logger

  @api_keys %{
    &quot;Moonbeam&quot; =&gt; System.get_env(&quot;MOONBEAM_API_KEY&quot;)
  }
  def sync(chain, %{last_block: last_block} = nft_contract) do

    # Step 1
    best_block = Fetcher.get_block_number(chain)
    # Step 2
    do_sync(chain, nft_contract, last_block, best_block)
    # Step 3
    NftContract.update(
      nft_contract,
      %{last_block: best_block + 1}
    )
  end

  def do_sync(%{name: name} = chain, %{addr: addr} = nft_contract, last_block, best_block) do
    # Step 2.1 - Retrieves Txns by Etherscan API
    {:ok, %{&quot;result&quot; =&gt; txs}}=
      ScanInteractor.get_txs_by_contract_addr(
        chain,
        addr,
        last_block,
        best_block,
        @api_keys[name]
      )

    # Step 2.2 - Persist transactions locally
    handle_txs(chain, nft_contract, txs)
  end

  def handle_txs(chain, nft_contract, txs) do
    Enum.each(txs, fn tx -&gt;
      Logger.info(&quot;Handling tx: #{inspect(tx)}&quot;)
      tx_atom_map = ExStructTranslator.to_atom_struct(tx)
      TxHandler.handle_tx(chain, nft_contract, tx_atom_map)
    end)
  end
end
"><code># https:<span class="hljs-comment">//github.com/WeLightProject/tai_shang_nft_gallery/blob/main/lib/tai_shang_nft_gallery/nft/syncer.ex</span>

defmodule TaiShangNftGallery.Nft.Syncer do
  alias TaiShangNftGallery.NftContract
  alias TaiShangNftGallery.TxHandler
  alias TaiShangNftGallery.Chain.Fetcher
  alias TaiShangNftGallery.ScanInteractor
  <span class="hljs-built_in">require</span> Logger

  @api_keys <span class="hljs-operator">%</span>{
    <span class="hljs-string">"Moonbeam"</span> <span class="hljs-operator">=</span><span class="hljs-operator">></span> System.get_env(<span class="hljs-string">"MOONBEAM_API_KEY"</span>)
  }
  def sync(chain, <span class="hljs-operator">%</span>{last_block: last_block} <span class="hljs-operator">=</span> nft_contract) do

    # Step <span class="hljs-number">1</span>
    best_block <span class="hljs-operator">=</span> Fetcher.get_block_number(chain)
    # Step <span class="hljs-number">2</span>
    do_sync(chain, nft_contract, last_block, best_block)
    # Step <span class="hljs-number">3</span>
    NftContract.update(
      nft_contract,
      <span class="hljs-operator">%</span>{last_block: best_block <span class="hljs-operator">+</span> <span class="hljs-number">1</span>}
    )
  end

  def do_sync(<span class="hljs-operator">%</span>{name: name} <span class="hljs-operator">=</span> chain, <span class="hljs-operator">%</span>{addr: addr} <span class="hljs-operator">=</span> nft_contract, last_block, best_block) do
    # Step <span class="hljs-number">2.1</span> <span class="hljs-operator">-</span> Retrieves Txns by Etherscan API
    {:ok, <span class="hljs-operator">%</span>{<span class="hljs-string">"result"</span> <span class="hljs-operator">=</span><span class="hljs-operator">></span> txs}}<span class="hljs-operator">=</span>
      ScanInteractor.get_txs_by_contract_addr(
        chain,
        addr,
        last_block,
        best_block,
        @api_keys[name]
      )

    # Step <span class="hljs-number">2.2</span> <span class="hljs-operator">-</span> Persist transactions locally
    handle_txs(chain, nft_contract, txs)
  end

  def handle_txs(chain, nft_contract, txs) do
    Enum.each(txs, fn <span class="hljs-built_in">tx</span> <span class="hljs-operator">-</span><span class="hljs-operator">></span>
      Logger.info(<span class="hljs-string">"Handling tx: #{inspect(tx)}"</span>)
      tx_atom_map <span class="hljs-operator">=</span> ExStructTranslator.to_atom_struct(<span class="hljs-built_in">tx</span>)
      TxHandler.handle_tx(chain, nft_contract, tx_atom_map)
    end)
  end
end
</code></pre><h3 id="h-syncer-server" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Syncer Server</h3><p>Syncer Server is implemented by <code>GenServer</code>. For those who do not know about it, you can imagine that it&apos;s some kind of process that runs forever. If there is any error, it can automatically restart.</p><p>The <code>GenServer</code> operates by handling the messages received, from itself or others. There are two main functions here:</p><ul><li><p><code>init</code>: The initialization function. It loads the Contract locally, store it in the process state and sends itself a <code>:sync</code> message.</p></li><li><p><code>handle_info</code>: The <code>:sync</code> message handler that calls the API of the <code>Syncer</code> to do the actual work.</p></li></ul><p>After each processing, the <code>Process.send_after/3</code> function sends itself a <code>:sync</code> message after 10 minutes.</p><pre data-type="codeBlock" text="# https://github.com/WeLightProject/tai_shang_nft_gallery/blob/main/lib/tai_shang_nft_gallery/syncer_server.ex
defmodule TaiShangNftGallery.SyncerServer do
  @moduledoc &quot;&quot;&quot;
    Genserver as Syncer
  &quot;&quot;&quot;
  alias TaiShangNftGallery.Nft.Syncer
  alias TaiShangNftGallery.NftContract
  use GenServer
  require Logger

  @sync_interval 600_000 # 10 minutes
  # +-----------+
  # | GenServer |
  # +-----------+
  def start_link(state) do
    GenServer.start_link(__MODULE__, state, name: :&quot;#nft_syncer&quot;)
  end

  def init([nft_contract_id: nft_contract_id]) do
    Logger.info(&quot;SyncerServer started yet.&quot;)
    nft_contract =
      nft_contract_id
      |&gt; NftContract.get_by_id()
      |&gt; NftContract.preload()
      state =
        [nft_contract: nft_contract]
    send(self(), :sync)
    {:ok, state}
  end

  def handle_info(:sync, [nft_contract: nft_contract] = state) do
    Syncer.sync(nft_contract.chain, nft_contract)
    sync_after_interval()
    {:noreply, state}
  end

  def sync_after_interval() do
    Process.send_after(self(), :sync, @sync_interval)
  end
end
"><code># https:<span class="hljs-comment">//github.com/WeLightProject/tai_shang_nft_gallery/blob/main/lib/tai_shang_nft_gallery/syncer_server.ex</span>
defmodule TaiShangNftGallery.SyncerServer do
  @moduledoc <span class="hljs-string">""</span><span class="hljs-string">"
    Genserver as Syncer
  "</span><span class="hljs-string">""</span>
  alias TaiShangNftGallery.Nft.Syncer
  alias TaiShangNftGallery.NftContract
  use GenServer
  <span class="hljs-built_in">require</span> Logger

  @sync_interval <span class="hljs-number">600_000</span> # <span class="hljs-number">10</span> <span class="hljs-literal">minutes</span>
  # <span class="hljs-operator">+</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">+</span>
  # <span class="hljs-operator">|</span> GenServer <span class="hljs-operator">|</span>
  # <span class="hljs-operator">+</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">+</span>
  def start_link(state) do
    GenServer.start_link(__MODULE__, state, name: :<span class="hljs-string">"#nft_syncer"</span>)
  end

  def init([nft_contract_id: nft_contract_id]) do
    Logger.info(<span class="hljs-string">"SyncerServer started yet."</span>)
    nft_contract <span class="hljs-operator">=</span>
      nft_contract_id
      <span class="hljs-operator">|</span><span class="hljs-operator">></span> NftContract.get_by_id()
      <span class="hljs-operator">|</span><span class="hljs-operator">></span> NftContract.preload()
      state <span class="hljs-operator">=</span>
        [nft_contract: nft_contract]
    send(<span class="hljs-built_in">self</span>(), :sync)
    {:ok, state}
  end

  def handle_info(:sync, [nft_contract: nft_contract] <span class="hljs-operator">=</span> state) do
    Syncer.sync(nft_contract.chain, nft_contract)
    sync_after_interval()
    {:noreply, state}
  end

  def sync_after_interval() do
    Process.send_after(<span class="hljs-built_in">self</span>(), :sync, @sync_interval)
  end
end
</code></pre><h3 id="h-decode-transaction" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Decode Transaction</h3><p>Different transactions actually represent different contract method call. In order to identify what exactly the transaction is doing, we have to decode the transaction <code>input</code> because the input is a hex value like <code>0x379607f5000000000000000000000000000000000000000000000000000000000000026d</code>. <code>TxHandler.handle_tx/3</code> uses <code>ABI</code> related APIs encapsulated in <code>ABIHandler.find_and_decode/2</code> to accomplish that.</p><pre data-type="codeBlock" text="# https://github.com/WeLightProject/tai_shang_nft_gallery/blob/main/lib/tai_shang_nft_gallery/tx_handler.ex
defmodule TaiShangNftGallery.TxHandler do
  @moduledoc &quot;&quot;&quot;
      Handle Ethereum Tx.
  &quot;&quot;&quot;

  alias TaiShangNftGallery.ABIHandler
  alias TaiShangNftGallery.NftContract

  def handle_tx(chain, nft_contract, tx) do
    %{
      from: from,
      to: to,
      value: value,
      input: input
    } = tx

    do_handle_tx(chain, from, to, value, input, nft_contract)
  end

  def do_handle_tx(chain, from, to, value, input, %{type: type} = nft_contract) do
    input_handled =
      nft_contract
      |&gt; NftContract.preload(:deep)
      |&gt; Map.get(:contract_abi)
      |&gt; Map.get(:abi)
      |&gt; ABIHandler.find_and_decode(input)

    &quot;Elixir.TaiShangNftGallery.TxHandler.#{type}&quot;
    |&gt; String.to_atom()
    |&gt; apply(:handle_tx, [chain, nft_contract, from, to, value, input_handled])
  end
end
"><code># https:<span class="hljs-comment">//github.com/WeLightProject/tai_shang_nft_gallery/blob/main/lib/tai_shang_nft_gallery/tx_handler.ex</span>
defmodule TaiShangNftGallery.TxHandler do
  @moduledoc <span class="hljs-string">""</span><span class="hljs-string">"
      Handle Ethereum Tx.
  "</span><span class="hljs-string">""</span>

  alias TaiShangNftGallery.ABIHandler
  alias TaiShangNftGallery.NftContract

  def handle_tx(chain, nft_contract, <span class="hljs-built_in">tx</span>) do
    <span class="hljs-operator">%</span>{
      <span class="hljs-keyword">from</span>: <span class="hljs-keyword">from</span>,
      to: to,
      <span class="hljs-built_in">value</span>: value,
      input: input
    } <span class="hljs-operator">=</span> <span class="hljs-built_in">tx</span>

    do_handle_tx(chain, <span class="hljs-keyword">from</span>, to, value, input, nft_contract)
  end

  def do_handle_tx(chain, <span class="hljs-keyword">from</span>, to, value, input, <span class="hljs-operator">%</span>{<span class="hljs-keyword">type</span>: <span class="hljs-keyword">type</span>} <span class="hljs-operator">=</span> nft_contract) do
    input_handled <span class="hljs-operator">=</span>
      nft_contract
      <span class="hljs-operator">|</span><span class="hljs-operator">></span> NftContract.preload(:deep)
      <span class="hljs-operator">|</span><span class="hljs-operator">></span> Map.get(:contract_abi)
      <span class="hljs-operator">|</span><span class="hljs-operator">></span> Map.get(:<span class="hljs-built_in">abi</span>)
      <span class="hljs-operator">|</span><span class="hljs-operator">></span> ABIHandler.find_and_decode(input)

    <span class="hljs-string">"Elixir.TaiShangNftGallery.TxHandler.#{type}"</span>
    <span class="hljs-operator">|</span><span class="hljs-operator">></span> String.to_atom()
    <span class="hljs-operator">|</span><span class="hljs-operator">></span> apply(:handle_tx, [chain, nft_contract, <span class="hljs-keyword">from</span>, to, value, input_handled])
  end
end
</code></pre><pre data-type="codeBlock" text="# https://github.com/WeLightProject/tai_shang_nft_gallery/blob/main/lib/tai_shang_nft_gallery/abi_handler.ex
defmodule TaiShangNftGallery.ABIHandler do
  alias Utils.TypeTranslator
  def find_and_decode(abi, input_hex) do
    abi
    |&gt; ABI.parse_specification
    |&gt; ABI.find_and_decode(TypeTranslator.hex_to_bin(input_hex))
  end
end
"><code># https:<span class="hljs-comment">//github.com/WeLightProject/tai_shang_nft_gallery/blob/main/lib/tai_shang_nft_gallery/abi_handler.ex</span>
defmodule TaiShangNftGallery.ABIHandler do
  alias Utils.TypeTranslator
  def find_and_decode(<span class="hljs-built_in">abi</span>, input_hex) do
    <span class="hljs-built_in">abi</span>
    <span class="hljs-operator">|</span><span class="hljs-operator">></span> ABI.parse_specification
    <span class="hljs-operator">|</span><span class="hljs-operator">></span> ABI.find_and_decode(TypeTranslator.hex_to_bin(input_hex))
  end
end
</code></pre><p>In the exact contract handler (type Web3Dev), we can see that only below methods are handled. Other than those, it returns <code>{:ok, &quot;pass&quot;}</code> directly.</p><ul><li><p><code>safeTransferFrom</code> / <code>trasnferFrom</code>: Used to transfer the ownership of the NFT</p></li><li><p><code>claim</code>: Used to initialize the NFT token</p></li><li><p><code>setTokenInfo</code>: Used to set NFT token info</p></li></ul><pre data-type="codeBlock" text="# https://github.com/WeLightProject/tai_shang_nft_gallery/blob/main/lib/tai_shang_nft_gallery/tx_handler/web_3_dev.ex
defmodule TaiShangNftGallery.TxHandler.Web3Dev do
  alias TaiShangNftGallery.Nft
  alias TaiShangNftGallery.Nft.Interactor
  alias Utils.TypeTranslator

  require Logger
  def handle_tx(chain, nft_contract, from, to, value,
    {%{function: func_name}, data})  do
      do_handle_tx(
        func_name,
        nft_contract, from, to, value, data, chain
      )
  end

  def handle_tx(_chain, _nft_contract, _from, _to, _value, _others) do
    :pass
  end

  def do_handle_tx(func, _nft_contract, from, _to, _value,
    [_from_bin, to_bin, token_id], _chain) when
    func in [&quot;safeTransferFrom&quot;, &quot;transferFrom&quot;] do
    # Change Owner
    to_str = TypeTranslator.bin_to_addr(to_bin)
    Logger.info(&quot;Transfer NFT from #{from} to #{to_str}&quot;)
    nft = Nft.get_by_token_id(token_id)
    Nft.update(nft, %{token_id: token_id, owner: to_str})
  end

  def do_handle_tx(&quot;claim&quot;, %{id: nft_c_id, addr: addr}, from, _to, _value, [token_id], chain) do
    # INIT Token
    uri = Interactor.get_token_uri(chain, addr, token_id)
    Nft.create(
      %{
        uri: uri,
        token_id: token_id,
        owner: from,
        nft_contract_id: nft_c_id
    })
  end

  def do_handle_tx(
    &quot;setTokenInfo&quot;,
    %{id: nft_c_id}, _from, _to, _value,
    [token_id, badges_raw], _chain) do
    # UPDATE TokenInfo

    token_id
    |&gt; Nft.get_by_token_id_and_nft_contract_id(nft_c_id)
    |&gt; Nft.update(%{
        badges: Poison.decode!(badges_raw), token_id: token_id
    }, :with_badges)
  end

  def do_handle_tx(_others, _, _, _, _, _, _) do
    {:ok, &quot;pass&quot;}
  end
end
"><code><span class="hljs-comment"># https://github.com/WeLightProject/tai_shang_nft_gallery/blob/main/lib/tai_shang_nft_gallery/tx_handler/web_3_dev.ex</span>
defmodule <span class="hljs-title class_">TaiShangNftGallery</span>.<span class="hljs-title class_">TxHandler</span>.<span class="hljs-title class_">Web3Dev</span> <span class="hljs-keyword">do</span>
  <span class="hljs-keyword">alias</span> <span class="hljs-title class_">TaiShangNftGallery</span>.<span class="hljs-title class_">Nft</span>
  <span class="hljs-keyword">alias</span> <span class="hljs-title class_">TaiShangNftGallery</span>.<span class="hljs-title class_">Nft</span>.<span class="hljs-title class_">Interactor</span>
  <span class="hljs-keyword">alias</span> <span class="hljs-title class_">Utils</span>.<span class="hljs-title class_">TypeTranslator</span>

  <span class="hljs-keyword">require</span> <span class="hljs-title class_">Logger</span>
  <span class="hljs-keyword">def</span> <span class="hljs-title function_">handle_tx</span>(<span class="hljs-params">chain, nft_contract, from, to, value,
    {<span class="hljs-string">%{function: func_name}</span>, data}</span>)  <span class="hljs-keyword">do</span>
      do_handle_tx(
        func_name,
        nft_contract, from, to, value, data, chain
      )
  <span class="hljs-keyword">end</span>

  <span class="hljs-keyword">def</span> <span class="hljs-title function_">handle_tx</span>(<span class="hljs-params">_chain, _nft_contract, _from, _to, _value, _others</span>) <span class="hljs-keyword">do</span>
    <span class="hljs-symbol">:pass</span>
  <span class="hljs-keyword">end</span>

  <span class="hljs-keyword">def</span> <span class="hljs-title function_">do_handle_tx</span>(<span class="hljs-params">func, _nft_contract, from, _to, _value,
    [_from_bin, to_bin, token_id], _chain</span>) <span class="hljs-keyword">when</span>
    func <span class="hljs-keyword">in</span> [<span class="hljs-string">"safeTransferFrom"</span>, <span class="hljs-string">"transferFrom"</span>] <span class="hljs-keyword">do</span>
    <span class="hljs-comment"># Change Owner</span>
    to_str = <span class="hljs-title class_">TypeTranslator</span>.bin_to_addr(to_bin)
    <span class="hljs-title class_">Logger</span>.info(<span class="hljs-string">"Transfer NFT from <span class="hljs-subst">#{from}</span> to <span class="hljs-subst">#{to_str}</span>"</span>)
    nft = <span class="hljs-title class_">Nft</span>.get_by_token_id(token_id)
    <span class="hljs-title class_">Nft</span>.update(nft, <span class="hljs-string">%{token_id: token_id, owner: to_str}</span>)
  <span class="hljs-keyword">end</span>

  <span class="hljs-keyword">def</span> <span class="hljs-title function_">do_handle_tx</span>(<span class="hljs-params"><span class="hljs-string">"claim"</span>, <span class="hljs-string">%{id: nft_c_id, addr: addr}</span>, from, _to, _value, [token_id], chain</span>) <span class="hljs-keyword">do</span>
    <span class="hljs-comment"># INIT Token</span>
    uri = <span class="hljs-title class_">Interactor</span>.get_token_uri(chain, addr, token_id)
    <span class="hljs-title class_">Nft</span>.create(
      <span class="hljs-string">%{
        uri: uri,
        token_id: token_id,
        owner: from,
        nft_contract_id: nft_c_id
    }</span>)
  <span class="hljs-keyword">end</span>

  <span class="hljs-keyword">def</span> <span class="hljs-title function_">do_handle_tx</span>(<span class="hljs-params">
    <span class="hljs-string">"setTokenInfo"</span>,
    <span class="hljs-string">%{id: nft_c_id}</span>, _from, _to, _value,
    [token_id, badges_raw], _chain</span>) <span class="hljs-keyword">do</span>
    <span class="hljs-comment"># UPDATE TokenInfo</span>

    token_id
    |<span class="hljs-params">> Nft.get_by_token_id_and_nft_contract_id(nft_c_id)
    </span>|> <span class="hljs-title class_">Nft</span>.update(<span class="hljs-string">%{
        badges: Poison.decode!(badges_raw), token_id: token_id
    }</span>, <span class="hljs-symbol">:with_badges</span>)
  <span class="hljs-keyword">end</span>

  <span class="hljs-keyword">def</span> <span class="hljs-title function_">do_handle_tx</span>(<span class="hljs-params">_others, _, _, _, _, _, _</span>) <span class="hljs-keyword">do</span>
    {<span class="hljs-symbol">:ok</span>, <span class="hljs-string">"pass"</span>}
  <span class="hljs-keyword">end</span>
<span class="hljs-keyword">end</span>
</code></pre><h2 id="h-implementation-in-nodejs" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Implementation in Node.js</h2><blockquote><p>See code in:</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/WeLightProject/Web3-dApp-Camp/tree/main/blockchain-server/syncer/syncer_demo_js">https://github.com/WeLightProject/Web3-dApp-Camp/tree/main/blockchain-server/syncer/syncer_demo_js</a></p></blockquote><h3 id="h-syncer" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Syncer</h3><p>Let&apos;s see how do we implement the Syncer in Node.js. Using APIs provided by <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://web3js.readthedocs.io/en/v1.7.0/web3-eth.html#getblocknumber">Web3</a> and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://moonbeam.moonscan.io/apis">Moonbeam</a>, it&apos;s very easy to interact with Moonbeam chain.</p><blockquote><h4 id="h-getblocknumber" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">getBlockNumber</h4><blockquote><p>web3.eth.getBlockNumber([callback])Returns the current block number.</p></blockquote><h5 id="h-returns" class="text-lg font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Returns</h5><p><code>Promise</code> returns <code>Number</code> - The number of the most recent block.</p></blockquote><blockquote><h4 id="h-get-a-list-of-normal-transactions-by-address" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Get a list of &apos;Normal&apos; Transactions By Address</h4><p>[Optional Parameters] startblock: starting blockNo to retrieve results, endblock: ending blockNo to retrieve results</p><blockquote><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://api-moonbeam.moonscan.io/api?module=account&amp;action=txlist&amp;address=0x0000000000000000000000000000000000001004&amp;startblock=1&amp;endblock=99999999&amp;sort=asc&amp;apikey=YourApiKeyToken">https://api-moonbeam.moonscan.io/api?module=account&amp;action=txlist&amp;address=0x0000000000000000000000000000000000001004&amp;startblock=1&amp;endblock=99999999&amp;sort=asc&amp;apikey=YourApiKeyToken</a>(Returned &apos;isError&apos; values: 0=No Error, 1=Got Error)(Returns up to a maximum of the last 10000 transactions only)</p></blockquote><p>or</p><blockquote><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://api-moonbeam.moonscan.io/api?module=account&amp;action=txlist&amp;address=0x0000000000000000000000000000000000001004&amp;startblock=1&amp;endblock=99999999&amp;page=1&amp;offset=10&amp;sort=asc&amp;apikey=YourApiKeyToken">https://api-moonbeam.moonscan.io/api?module=account&amp;action=txlist&amp;address=0x0000000000000000000000000000000000001004&amp;startblock=1&amp;endblock=99999999&amp;page=1&amp;offset=10&amp;sort=asc&amp;apikey=YourApiKeyToken</a>(To get paginated results use page= and offset=)</p><p>Below is Syncer implemented in JavaScript. In this example, I persist the data using sqlite but you can choose anything you are familiar with. And I simply use <code>setTimeout</code> and Catch-All-Error approach to simulate a forever running process.</p><pre data-type="codeBlock" text="import Web3 from &apos;web3&apos;;
import got from &apos;got&apos;;
import sqlite3 from &apos;sqlite3&apos;;
import abiDecoder from &apos;abi-decoder&apos;;

const db = new sqlite3.Database(&apos;./sqlite.db&apos;);

const web3 = new Web3(new Web3.providers.HttpProvider(&apos;https://rpc.api.moonbeam.network&apos;));

const INTERVAL = 1 * 60 * 1000; // 10 minutes
const API_KEY = &apos;Y6AIFQQVAJ3H38CC11QFDUDJWAWNCWE3U8&apos;;

const CONTRACT_ADDRESS = &apos;0xb6FC950C4bC9D1e4652CbEDaB748E8Cdcfe5655F&apos;;
const CONTRACT_ABI = []; // ABI can be retrieved from https://moonbeam.moonscan.io/address/0xb6FC950C4bC9D1e4652CbEDaB748E8Cdcfe5655F#code

abiDecoder.addABI(CONTRACT_ABI);

async function sync() {
  try {
    const contract = await getContractInfo(CONTRACT_ADDRESS);

    // Step 1 - Retrieves the latest block number of the blockchain
    const latestBlock = await web3.eth.getBlockNumber();
    console.log(`Latest blockNumber is: ${latestBlock}`);

    const lastBlockNumber = contract.lastBlockNumber || latestBlock - 100000;

    // Step 2.1 - Retrieves Txns by Etherscan API
    const transactions = await getTransactionsOfContract(contract.address, lastBlockNumber, latestBlock);
    console.log(`${transactions.length} transactions retrieved from Block ${lastBlockNumber} to ${latestBlock}.`);

    if (transactions.length &gt; 0) {
      // Step 2.2 - Handle transactions
      await handleTransactions(contract, transactions);
    }

    // Step 3 - Persist the latest block number
    contract.lastBlockNumber = latestBlock + 1;
    await updateContractLastBlockNumber(contract);
    console.log(`lastBlockNumber of contract ${contract.id} is updated to ${contract.lastBlockNumber}.`);
  } catch (error) {
    console.error(&apos;Failed to sync transactions.&apos;, error);
  }

  nextRun();
}

function nextRun() {
  setTimeout(sync, INTERVAL);
}

async function getTransactionsOfContract(contractAddress, fromBlock, toBlock) {
  const url = `https://api-moonbeam.moonscan.io/api?module=account&amp;action=txlist&amp;address=${contractAddress}&amp;startblock=${fromBlock}&amp;endblock=${toBlock}&amp;sort=asc&amp;apikey=${API_KEY}`;
  const response = await got(url).json();

  return response.result;
}

async function _getContract(address) {
  return new Promise(function (resolve, reject) {
    db.get(&apos;SELECT id, lastBlockNumber, address FROM contract WHERE address = $address&apos;, { $address: address }, function (err, result) {
      if (err) {
        return reject(err);
      }

      return resolve(result);
    });
  });
}

async function getContractInfo(address) {
  let contract = await _getContract(address);
  if (contract) {
    return contract;
  }

  contract = {
    lastBlockNumber: 0,
    address
  };
  const contractId = await _runSQL(
    &apos;INSERT INTO contract (lastBlockNumber, address) VALUES ($lastBlockNumber, $address)&apos;,
    {
      $lastBlockNumber: contract.lastBlockNumber,
      $address: contract.address
    }
  );
  contract.id = contractId;
  return contract;
}

async function updateContractLastBlockNumber(contract) {
  return _runSQL(
    &apos;UPDATE contract SET lastBlockNumber = $lastBlockNumber WHERE id = $id&apos;,
    {
      $lastBlockNumber: contract.lastBlockNumber,
      $id: contract.id
    }
  );
}

async function execute() {
  // SQLite DB tables should be initialized first.

  await sync();
}

execute();
"><code><span class="hljs-keyword">import</span> <span class="hljs-title">Web3</span> <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'web3'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-title">got</span> <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'got'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-title">sqlite3</span> <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'sqlite3'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-title">abiDecoder</span> <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'abi-decoder'</span>;

const db <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> sqlite3.Database(<span class="hljs-string">'./sqlite.db'</span>);

const web3 <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> Web3(<span class="hljs-keyword">new</span> Web3.providers.HttpProvider(<span class="hljs-string">'https://rpc.api.moonbeam.network'</span>));

const INTERVAL <span class="hljs-operator">=</span> <span class="hljs-number">1</span> <span class="hljs-operator">*</span> <span class="hljs-number">60</span> <span class="hljs-operator">*</span> <span class="hljs-number">1000</span>; <span class="hljs-comment">// 10 minutes</span>
const API_KEY <span class="hljs-operator">=</span> <span class="hljs-string">'Y6AIFQQVAJ3H38CC11QFDUDJWAWNCWE3U8'</span>;

const CONTRACT_ADDRESS <span class="hljs-operator">=</span> <span class="hljs-string">'0xb6FC950C4bC9D1e4652CbEDaB748E8Cdcfe5655F'</span>;
const CONTRACT_ABI <span class="hljs-operator">=</span> []; <span class="hljs-comment">// ABI can be retrieved from https://moonbeam.moonscan.io/address/0xb6FC950C4bC9D1e4652CbEDaB748E8Cdcfe5655F#code</span>

abiDecoder.addABI(CONTRACT_ABI);

async <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sync</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">try</span> {
    const <span class="hljs-class"><span class="hljs-keyword">contract</span> = <span class="hljs-title">await</span> <span class="hljs-title">getContractInfo</span>(<span class="hljs-params">CONTRACT_ADDRESS</span>);

    <span class="hljs-comment">// Step 1 - Retrieves the latest block number of the blockchain</span>
    <span class="hljs-title">const</span> <span class="hljs-title">latestBlock</span> = <span class="hljs-title">await</span> <span class="hljs-title">web3</span>.<span class="hljs-title">eth</span>.<span class="hljs-title">getBlockNumber</span>(<span class="hljs-params"></span>);
    <span class="hljs-title">console</span>.<span class="hljs-title">log</span>(<span class="hljs-params">`Latest blockNumber <span class="hljs-keyword">is</span>: ${latestBlock}`</span>);

    <span class="hljs-title">const</span> <span class="hljs-title">lastBlockNumber</span> = <span class="hljs-title"><span class="hljs-keyword">contract</span></span>.<span class="hljs-title">lastBlockNumber</span> || <span class="hljs-title">latestBlock</span> - 100000;

    <span class="hljs-comment">// Step 2.1 - Retrieves Txns by Etherscan API</span>
    <span class="hljs-title">const</span> <span class="hljs-title">transactions</span> = <span class="hljs-title">await</span> <span class="hljs-title">getTransactionsOfContract</span>(<span class="hljs-params"><span class="hljs-keyword">contract</span>.<span class="hljs-keyword">address</span>, lastBlockNumber, latestBlock</span>);
    <span class="hljs-title">console</span>.<span class="hljs-title">log</span>(<span class="hljs-params">`${transactions.length} transactions retrieved <span class="hljs-keyword">from</span> Block ${lastBlockNumber} to ${latestBlock}.`</span>);

    <span class="hljs-title"><span class="hljs-keyword">if</span></span> (<span class="hljs-params">transactions.length > <span class="hljs-number">0</span></span>) </span>{
      <span class="hljs-comment">// Step 2.2 - Handle transactions</span>
      await handleTransactions(<span class="hljs-class"><span class="hljs-keyword">contract</span>, <span class="hljs-title">transactions</span>);
    }

    <span class="hljs-comment">// Step 3 - Persist the latest block number</span>
    <span class="hljs-title"><span class="hljs-keyword">contract</span></span>.<span class="hljs-title">lastBlockNumber</span> = <span class="hljs-title">latestBlock</span> + 1;
    <span class="hljs-title">await</span> <span class="hljs-title">updateContractLastBlockNumber</span>(<span class="hljs-params"><span class="hljs-keyword">contract</span></span>);
    <span class="hljs-title">console</span>.<span class="hljs-title">log</span>(<span class="hljs-params">`lastBlockNumber of <span class="hljs-keyword">contract</span> ${<span class="hljs-keyword">contract</span>.id} <span class="hljs-keyword">is</span> updated to ${<span class="hljs-keyword">contract</span>.lastBlockNumber}.`</span>);
  } <span class="hljs-title"><span class="hljs-keyword">catch</span></span> (<span class="hljs-params"><span class="hljs-keyword">error</span></span>) </span>{
    console.error(<span class="hljs-string">'Failed to sync transactions.'</span>, <span class="hljs-function"><span class="hljs-keyword">error</span>)</span>;
  }

  nextRun();
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">nextRun</span>(<span class="hljs-params"></span>) </span>{
  setTimeout(sync, INTERVAL);
}

async <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getTransactionsOfContract</span>(<span class="hljs-params">contractAddress, fromBlock, toBlock</span>) </span>{
  const url <span class="hljs-operator">=</span> `https:<span class="hljs-comment">//api-moonbeam.moonscan.io/api?module=account&#x26;action=txlist&#x26;address=${contractAddress}&#x26;startblock=${fromBlock}&#x26;endblock=${toBlock}&#x26;sort=asc&#x26;apikey=${API_KEY}`;</span>
  const response <span class="hljs-operator">=</span> await got(url).json();

  <span class="hljs-keyword">return</span> response.result;
}

async <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_getContract</span>(<span class="hljs-params"><span class="hljs-keyword">address</span></span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Promise(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">resolve, reject</span>) </span>{
    db.get(<span class="hljs-string">'SELECT id, lastBlockNumber, address FROM contract WHERE address = $address'</span>, { $<span class="hljs-keyword">address</span>: <span class="hljs-keyword">address</span> }, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">err, result</span>) </span>{
      <span class="hljs-keyword">if</span> (err) {
        <span class="hljs-keyword">return</span> reject(err);
      }

      <span class="hljs-keyword">return</span> resolve(result);
    });
  });
}

async <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getContractInfo</span>(<span class="hljs-params"><span class="hljs-keyword">address</span></span>) </span>{
  let <span class="hljs-class"><span class="hljs-keyword">contract</span> = <span class="hljs-title">await</span> <span class="hljs-title">_getContract</span>(<span class="hljs-params"><span class="hljs-keyword">address</span></span>);
  <span class="hljs-title"><span class="hljs-keyword">if</span></span> (<span class="hljs-params"><span class="hljs-keyword">contract</span></span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-class"><span class="hljs-keyword">contract</span>;
  }

  <span class="hljs-title"><span class="hljs-keyword">contract</span></span> = </span>{
    lastBlockNumber: <span class="hljs-number">0</span>,
    <span class="hljs-keyword">address</span>
  };
  const contractId <span class="hljs-operator">=</span> await _runSQL(
    <span class="hljs-string">'INSERT INTO contract (lastBlockNumber, address) VALUES ($lastBlockNumber, $address)'</span>,
    {
      $lastBlockNumber: <span class="hljs-keyword">contract</span>.lastBlockNumber,
      $<span class="hljs-keyword">address</span>: <span class="hljs-keyword">contract</span>.<span class="hljs-built_in">address</span>
    }
  );
  <span class="hljs-keyword">contract</span>.id <span class="hljs-operator">=</span> contractId;
  <span class="hljs-keyword">return</span> <span class="hljs-class"><span class="hljs-keyword">contract</span>;
}

<span class="hljs-title">async</span> <span class="hljs-title"><span class="hljs-keyword">function</span></span> <span class="hljs-title">updateContractLastBlockNumber</span>(<span class="hljs-params"><span class="hljs-keyword">contract</span></span>) </span>{
  <span class="hljs-keyword">return</span> _runSQL(
    <span class="hljs-string">'UPDATE contract SET lastBlockNumber = $lastBlockNumber WHERE id = $id'</span>,
    {
      $lastBlockNumber: <span class="hljs-keyword">contract</span>.lastBlockNumber,
      $id: <span class="hljs-keyword">contract</span>.id
    }
  );
}

async <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">execute</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// SQLite DB tables should be initialized first.</span>

  await sync();
}

execute();
</code></pre><h3 id="h-decode-transactions" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Decode Transactions</h3><p>In order to decode the transaction, we need to unitilize the APIs provided by Web3.</p><blockquote><h4 id="h-encodefunctioncall" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">encodeFunctionCall</h4><blockquote><p>web3.eth.abi.encodeFunctionCall(jsonInterface, parameters);Encodes a function call using its JSON interface object and given parameters.</p></blockquote><h5 id="h-parameters" class="text-lg font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Parameters</h5><ol><li><p><code>jsonInterface</code> - <code>Object</code>: The JSON interface object of a function.</p></li><li><p><code>parameters</code> - <code>Array</code>: The parameters to encode.</p></li><li><p><code>Function</code> - (optional) Optional callback, returns an error object as first parameter and the result as second.</p></li></ol><h5 id="h-returns" class="text-lg font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Returns</h5><p><code>String</code> - The ABI encoded function call. Means function signature + parameters.</p><h5 id="h-example" class="text-lg font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Example</h5><pre data-type="codeBlock" text="web3.eth.abi.encodeFunctionCall({
  name: &apos;myMethod&apos;,
  type: &apos;function&apos;,
  inputs: [{
      type: &apos;uint256&apos;,
      name: &apos;myNumber&apos;
  },{
      type: &apos;string&apos;,
      name: &apos;myString&apos;
  }]
}, [&apos;2345675643&apos;, &apos;Hello!%&apos;]);
&quot;0x24ee0097000000000000000000000000000000000000000000000000000000008bd02b7b0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000748656c6c6f212500000000000000000000000000000000000000000000000000&quot;
"><code>web3.eth.abi.<span class="hljs-title function_ invoke__">encodeFunctionCall</span>({
  <span class="hljs-attr">name</span>: <span class="hljs-string">'myMethod'</span>,
  <span class="hljs-attr">type</span>: <span class="hljs-string">'function'</span>,
  <span class="hljs-attr">inputs</span>: [{
      <span class="hljs-attr">type</span>: <span class="hljs-string">'uint256'</span>,
      <span class="hljs-attr">name</span>: <span class="hljs-string">'myNumber'</span>
  },{
      <span class="hljs-attr">type</span>: <span class="hljs-string">'string'</span>,
      <span class="hljs-attr">name</span>: <span class="hljs-string">'myString'</span>
  }]
}, [<span class="hljs-string">'2345675643'</span>, <span class="hljs-string">'Hello!%'</span>]);
<span class="hljs-string">"0x24ee0097000000000000000000000000000000000000000000000000000000008bd02b7b0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000748656c6c6f212500000000000000000000000000000000000000000000000000"</span>
</code></pre></blockquote><blockquote><h4 id="h-call" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">call</h4><blockquote><p>web3.eth.call(callObject [, defaultBlock] [, callback])Executes a message call transaction, which is directly executed in the VM of the node, but never mined into the blockchain.</p></blockquote><h5 id="h-parameters" class="text-lg font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Parameters</h5><ol><li><p><code>Object</code> - A transaction object, see web3.eth.sendTransaction. For calls the from property is optional however it is highly recommended to explicitly set it or it may default to address(0) depending on your node or provider.</p></li><li><p><code>Number|String|BN|BigNumber</code> - (optional) If you pass this parameter it will not use the default block set with web3.eth.defaultBlock. Pre-defined block numbers as &quot;earliest&quot;, &quot;latest&quot; and &quot;pending&quot; can also be used.</p></li><li><p><code>Function</code> - (optional) Optional callback, returns an error object as first parameter and the result as second.</p></li></ol><h5 id="h-returns" class="text-lg font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Returns</h5><p><code>Promise</code> returns <code>String</code> - The returned data of the call, e.g. a smart contract functions return value.</p><h5 id="h-example" class="text-lg font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Example</h5><pre data-type="codeBlock" text="web3.eth.call({
  to: &quot;0x11f4d0A3c12e86B4b5F39B213F7E19D048276DAe&quot;, // contract address
  data: &quot;0xc6888fa10000000000000000000000000000000000000000000000000000000000000003&quot;
})
.then(console.log);
&quot;0x000000000000000000000000000000000000000000000000000000000000000a&quot;
"><code>web3.eth.<span class="hljs-built_in">call</span>({
  to: <span class="hljs-string">"0x11f4d0A3c12e86B4b5F39B213F7E19D048276DAe"</span>, <span class="hljs-comment">// contract address</span>
  data: <span class="hljs-string">"0xc6888fa10000000000000000000000000000000000000000000000000000000000000003"</span>
})
.then(console.log);
<span class="hljs-string">"0x000000000000000000000000000000000000000000000000000000000000000a"</span>
</code></pre></blockquote><blockquote><h4 id="h-hextoutf8" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">hexToUtf8</h4><blockquote><p>web3.utils.hexToUtf8(hex)Returns the UTF-8 string representation of a given HEX value.</p></blockquote><h5 id="h-parameters" class="text-lg font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Parameters</h5><ol><li><p><code>hex</code> - <code>String</code>: A HEX string to convert to a UTF-8 string.</p></li></ol><h5 id="h-returns" class="text-lg font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Returns</h5><p><code>String</code>: The UTF-8 string.</p><h5 id="h-example" class="text-lg font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Example</h5><pre data-type="codeBlock" text="web3.utils.hexToUtf8(&apos;0x49206861766520313030e282ac&apos;);
&quot;I have 100€&quot;
"><code>web3.utils.hexToUtf8(<span class="hljs-string">'0x49206861766520313030e282ac'</span>);
<span class="hljs-string">"I have 100€"</span>
</code></pre></blockquote><pre data-type="codeBlock" text="const TRANSACTION_HANDLER = {
  safeTransferFrom: transferHandler,
  transferFrom: transferHandler,
  claim: claimHandler
}

async function handleTransactions(contract, transactions) {
  for (let i = 0; i &lt; transactions.length; i++) {
    const transaction = transactions[i];
    const decodedMethod = abiDecoder.decodeMethod(transaction.input);

    const handler = TRANSACTION_HANDLER[decodedMethod.name];
    if (handler) {
      await handler(contract, transaction, decodedMethod.params);
    }
  }
}

/**
 * Transfer the ownership of the NTF token
 * @param {*} contract The NFT contract
 * @param {*} transaction The transaction executing the claim method
 * @param {*} params Decoded parameters provided to the method.  Sample:
 *  [
 *    {
 *      name: &apos;from&apos;,
 *      value: &apos;0xc994b5384c0d0611de2ece7d6ff1ad16c34a812f&apos;,
 *      type: &apos;address&apos;
 *    },
 *    {
 *      name: &apos;to&apos;,
 *      value: &apos;0x9c88a415f6a8043d7eaf14db721efbd8309e7365&apos;,
 *      type: &apos;address&apos;
 *    },
 *    { name: &apos;tokenId&apos;, value: &apos;888888&apos;, type: &apos;uint256&apos; }
 *  ]
 */
async function transferHandler(contract, transaction, params) {
  const to = _getParam(params, &apos;to&apos;).value;
  const tokenId = parseInt(_getParam(params, &apos;tokenId&apos;).value);

  return _runSQL(
    `UPDATE nft SET owner = $owner WHERE contractId = $contractId and tokenId = $tokenId`,
    { $owner: to, $contractId: contract.id, $tokenId: tokenId }
  );
}

/**
 * Initialize the NFT token
 * @param {*} contract The NFT contract
 * @param {*} transaction The transaction executing the claim method
 * @param {*} params Decoded parameters provided to the method.  Sample: [{ name: &apos;tokenId&apos;, value: &apos;199398&apos;, type: &apos;uint256&apos; }]
 */
async function claimHandler(contract, transaction, params) {
  const tokenId = parseInt(_getParam(params, &apos;tokenId&apos;).value);
  const uri = await getTokenUri(contract.address, tokenId);

  const nft = {
    $contractId: contract.id,
    $tokenId: tokenId,
    $uri: uri,
    $owner: transaction.from,
  };

  return _runSQL(
    `INSERT INTO nft (contractId, tokenId, uri, owner) VALUES ($contractId, $tokenId, $uri, $owner)`,
    nft
  );
}

async function getTokenUri(contractAddress, tokenId) {
  const data = web3.eth.abi.encodeFunctionCall({
    name: &apos;tokenURI&apos;,
    type: &apos;function&apos;,
    inputs: [{
      type: &apos;uint256&apos;,
      name: &apos;tokenId&apos;
    }]
  }, [tokenId]);

  const uriHex = await web3.eth.call({
    to: contractAddress, // contract address
    data
  });

  return web3.utils.hexToUtf8(uriHex);
}
"><code>const TRANSACTION_HANDLER <span class="hljs-operator">=</span> {
  safeTransferFrom: transferHandler,
  transferFrom: transferHandler,
  claim: claimHandler
}

async <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleTransactions</span>(<span class="hljs-params"><span class="hljs-keyword">contract</span>, transactions</span>) </span>{
  <span class="hljs-keyword">for</span> (let i <span class="hljs-operator">=</span> <span class="hljs-number">0</span>; i <span class="hljs-operator">&#x3C;</span> transactions.<span class="hljs-built_in">length</span>; i<span class="hljs-operator">+</span><span class="hljs-operator">+</span>) {
    const transaction <span class="hljs-operator">=</span> transactions[i];
    const decodedMethod <span class="hljs-operator">=</span> abiDecoder.decodeMethod(transaction.input);

    const handler <span class="hljs-operator">=</span> TRANSACTION_HANDLER[decodedMethod.<span class="hljs-built_in">name</span>];
    <span class="hljs-keyword">if</span> (handler) {
      await handler(<span class="hljs-class"><span class="hljs-keyword">contract</span>, <span class="hljs-title">transaction</span>, <span class="hljs-title">decodedMethod</span>.<span class="hljs-title">params</span>);
    }
  }
}

<span class="hljs-comment">/**
 * Transfer the ownership of the NTF token
 * @param {*} contract The NFT contract
 * @param {*} transaction The transaction executing the claim method
 * @param {*} params Decoded parameters provided to the method.  Sample:
 *  [
 *    {
 *      name: 'from',
 *      value: '0xc994b5384c0d0611de2ece7d6ff1ad16c34a812f',
 *      type: 'address'
 *    },
 *    {
 *      name: 'to',
 *      value: '0x9c88a415f6a8043d7eaf14db721efbd8309e7365',
 *      type: 'address'
 *    },
 *    { name: 'tokenId', value: '888888', type: 'uint256' }
 *  ]
 */</span>
<span class="hljs-title">async</span> <span class="hljs-title"><span class="hljs-keyword">function</span></span> <span class="hljs-title">transferHandler</span>(<span class="hljs-params"><span class="hljs-keyword">contract</span>, transaction, params</span>) </span>{
  const to <span class="hljs-operator">=</span> _getParam(params, <span class="hljs-string">'to'</span>).<span class="hljs-built_in">value</span>;
  const tokenId <span class="hljs-operator">=</span> parseInt(_getParam(params, <span class="hljs-string">'tokenId'</span>).<span class="hljs-built_in">value</span>);

  <span class="hljs-keyword">return</span> _runSQL(
    `UPDATE nft SET owner <span class="hljs-operator">=</span> $owner WHERE contractId <span class="hljs-operator">=</span> $contractId and tokenId <span class="hljs-operator">=</span> $tokenId`,
    { $owner: to, $contractId: <span class="hljs-keyword">contract</span>.id, $tokenId: tokenId }
  );
}

<span class="hljs-comment">/**
 * Initialize the NFT token
 * @param {*} contract The NFT contract
 * @param {*} transaction The transaction executing the claim method
 * @param {*} params Decoded parameters provided to the method.  Sample: [{ name: 'tokenId', value: '199398', type: 'uint256' }]
 */</span>
async <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">claimHandler</span>(<span class="hljs-params"><span class="hljs-keyword">contract</span>, transaction, params</span>) </span>{
  const tokenId <span class="hljs-operator">=</span> parseInt(_getParam(params, <span class="hljs-string">'tokenId'</span>).<span class="hljs-built_in">value</span>);
  const uri <span class="hljs-operator">=</span> await getTokenUri(<span class="hljs-keyword">contract</span>.<span class="hljs-built_in">address</span>, tokenId);

  const nft <span class="hljs-operator">=</span> {
    $contractId: <span class="hljs-keyword">contract</span>.id,
    $tokenId: tokenId,
    $uri: uri,
    $owner: transaction.from,
  };

  <span class="hljs-keyword">return</span> _runSQL(
    `INSERT INTO nft (contractId, tokenId, uri, owner) VALUES ($contractId, $tokenId, $uri, $owner)`,
    nft
  );
}

async <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getTokenUri</span>(<span class="hljs-params">contractAddress, tokenId</span>) </span>{
  const data <span class="hljs-operator">=</span> web3.eth.abi.encodeFunctionCall({
    name: <span class="hljs-string">'tokenURI'</span>,
    <span class="hljs-keyword">type</span>: <span class="hljs-string">'function'</span>,
    inputs: [{
      <span class="hljs-keyword">type</span>: <span class="hljs-string">'uint256'</span>,
      name: <span class="hljs-string">'tokenId'</span>
    }]
  }, [tokenId]);

  const uriHex <span class="hljs-operator">=</span> await web3.eth.<span class="hljs-built_in">call</span>({
    to: contractAddress, <span class="hljs-comment">// contract address</span>
    data
  });

  <span class="hljs-keyword">return</span> web3.utils.hexToUtf8(uriHex);
}
</code></pre><p><strong>Authors:</strong></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">thinkingincrowd</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">leeduckgo</figcaption></figure></blockquote></blockquote>]]></content:encoded>
            <author>apecoder@newsletter.paragraph.com (Web3dAppDevCamp)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/9cb5da88fe2456a589702ed1286542b7de436f147792069c1b1bcd03a106a1a6.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[[News]TaiShangNFTGallery Launched!@NonceGeek]]></title>
            <link>https://paragraph.com/@apecoder/news-taishangnftgallery-launched-noncegeek</link>
            <guid>HVT3p2cc05aUvquY3Jzd</guid>
            <pubDate>Tue, 01 Feb 2022 03:44:14 GMT</pubDate>
            <description><![CDATA[国内用户如需交流，可加微信：197626581.TaiShangNFTGallery will be the first project launched for TaiShang series of project.TaiShangGallery https://gallery.noncegeek.com/TaiShangNFTGallery shows all the NFT published by NonceGeek and other publishers. Currently TaiShangNFTGallery launched Web3DevCamp@NonceGeek&apos;s Web3DevNFT. Web3DevNFT has the following utilities: 0x01) Use as user identity label Currently we have labels of:learner who has finished lessons related by Web3Dev.buidler who buidler things f...]]></description>
            <content:encoded><![CDATA[<blockquote><p>国内用户如需交流，可加微信：197626581.</p></blockquote><p>TaiShangNFTGallery will be the first project launched for TaiShang series of project.</p><blockquote><p><strong>TaiShangGallery</strong></p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://gallery.noncegeek.com/">https://gallery.noncegeek.com/</a></p></blockquote><p>TaiShangNFTGallery shows all the NFT published by NonceGeek and other publishers. Currently TaiShangNFTGallery launched <code>Web3DevCamp@NonceGeek</code>&apos;s <code>Web3DevNFT</code>.</p><p><code>Web3DevNFT</code> has the following utilities:</p><p><strong>0x01) Use as user identity label</strong></p><p>Currently we have labels of:</p><ul><li><p><strong>learner</strong></p><p>who has finished lessons related by Web3Dev.</p></li><li><p><strong>buidler</strong></p><p>who buidler things for repos related by Web3Dev.</p></li><li><p><strong>partner</strong></p><p>partner of Web3Dev.</p></li><li><p><strong>noncegeeker</strong></p><p>core member of Web3Dev.</p></li><li><p><strong>workshoper</strong></p><p>who participated in Web3DevWorkshop.</p></li><li><p><strong>camper</strong></p><p>who participated in Web3DevCamp.</p></li><li><p><strong>writer</strong></p><p>who created articles for Web3Dev.</p></li><li><p><strong>researcher</strong></p><p>who participated in research work of Web3Dev.</p></li></ul><p><strong>0x02）Use as Metaverse character role</strong></p><p>Web3DevNFT can be used as Metaverse character role in TaiShangVerse 2022.</p><p><strong>Authors:</strong></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">leeduckgo</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">msfew</figcaption></figure>]]></content:encoded>
            <author>apecoder@newsletter.paragraph.com (Web3dAppDevCamp)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/5ae84ff97c1908b76c9691fa19437ab209264743fba3f67d4512c470cc399090.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[Deploy Smart Contract by Remix on Moonbeam | Moonbeam Branch 0x01]]></title>
            <link>https://paragraph.com/@apecoder/deploy-smart-contract-by-remix-on-moonbeam-moonbeam-branch-0x01</link>
            <guid>MaHDSsbNIZwbVPCP0XSY</guid>
            <pubDate>Fri, 14 Jan 2022 03:12:52 GMT</pubDate>
            <description><![CDATA[国内用户如需交流，可加微信：197626581.Authors: Leeduckgo@NonceGeek, Msfew@NonceGeekMoonbeam is a Polkadot-based smart contract blockchain dedicated to providing development tools and networks familiar to Ethereum developers with compatible functionality. Moonbeam is a developer-friendly blockchain that enables full EVM compatibility, API compatibility with Web3.js, and a bridge to connect Moonbeam to the existing Ethereum network. Developers can easily deploy existing Solidity smart contracts and DApp fron...]]></description>
            <content:encoded><![CDATA[<blockquote><p>国内用户如需交流，可加微信：197626581.</p></blockquote><p>Authors: <strong>Leeduckgo@NonceGeek, Msfew@NonceGeek</strong></p><blockquote><p>Moonbeam is a Polkadot-based smart contract blockchain dedicated to providing development tools and networks familiar to Ethereum developers with compatible functionality. Moonbeam is a developer-friendly blockchain that enables full EVM compatibility, API compatibility with Web3.js, and a bridge to connect Moonbeam to the existing Ethereum network. Developers can easily deploy existing Solidity smart contracts and DApp front ends to Moonbeam with only minor modifications.</p><p>Since Moonbeam is an EVM-compatible chain implemented on Substrate, developers and DApps can enjoy all the benefits of EVM while simultaneously enjoying the unlimited possibilities of Substrate in the future, creating an amazing potential with the dual support of Substrate * Ethereum.</p></blockquote><p>On Moonbeam/Moonriver, how should we complete the whole process of &quot;coding → debugging → code flattern → deployment → source code verification on browser&quot; for smart contracts via Remix?</p><h2 id="h-0x1-remix-installation" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x1 Remix Installation</h2><p>Remix is our go-to tool for developing Solidity smart contracts, and sometimes we access the web online version of the Remix-IDE directly.</p><blockquote><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://remix.ethereum.org/">https://remix.ethereum.org/</a></p></blockquote><p>However, complicated smart contracts can cause Remix to be frozen, so it&apos;s best for us to set up Remix locally.</p><p>To set up Remix locally, you need to prepare two things: one is Remix-project, which serves as the front-end client of Remix; the other is Remixd, which serves as the back-end of Remix, and their Github repositories are</p><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum/remix-project">https://github.com/ethereum/remix-project</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum/remixd">https://github.com/ethereum/remixd</a></p></li></ul><h3 id="h-11-set-up-remix-project" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">1.1 Set up Remix-project</h3><p>Set up Remix-project with Docker is recommended:</p><pre data-type="codeBlock" text="docker pull remixproject/remix-ide:latest
docker run -p 8080:80 remixproject/remix-ide:latest
"><code>docker pull remixproject<span class="hljs-operator">/</span>remix<span class="hljs-operator">-</span>ide:latest
docker run <span class="hljs-operator">-</span>p <span class="hljs-number">8080</span>:<span class="hljs-number">80</span> remixproject<span class="hljs-operator">/</span>remix<span class="hljs-operator">-</span>ide:latest
</code></pre><p>Then we can access it through browser at port 8080.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">image-20201010220954147</figcaption></figure><h3 id="h-12-set-up-remixd" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">1.2 Set up Remixd</h3><p>The following is the steps for setting up Remixd:</p><p>1）Install Remixed via npm or yarn (yarn is recommended)</p><p>Via npm:</p><pre data-type="codeBlock" text="npm install remixd -g
"><code>npm install remixd <span class="hljs-operator">-</span>g
</code></pre><p>Via yarn:</p><pre data-type="codeBlock" text="yarn install -g remixd
"><code>yarn install <span class="hljs-operator">-</span>g remixd
</code></pre><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">pic1</figcaption></figure><p>2）Start Remix-IDE with one line of command</p><pre data-type="codeBlock" text="remixd -s [path/ur/solidity/files] --remix-ide http://localhost:8080
# The last parameter means which port is accessed, because we are mapping to the Remix-project of 8080, so fill in http://localhost:8080
"><code>remixd <span class="hljs-operator">-</span>s [path<span class="hljs-operator">/</span>ur<span class="hljs-operator">/</span>solidity<span class="hljs-operator">/</span>files] <span class="hljs-operator">-</span><span class="hljs-operator">-</span>remix<span class="hljs-operator">-</span>ide http:<span class="hljs-comment">//localhost:8080</span>
# The last parameter means which port <span class="hljs-keyword">is</span> accessed, because we are <span class="hljs-keyword">mapping</span> to the Remix<span class="hljs-operator">-</span>project of <span class="hljs-number">8080</span>, so fill in http:<span class="hljs-comment">//localhost:8080</span>
</code></pre><blockquote><p><strong>Note:</strong> Check the official doc for starting Remix.</p></blockquote><p>3）Click on Remix-IDE</p><p>First, you click on Solidity, select specific environment; then click on Connect to Localhost to, of course, connect to localhost.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>Now we are all set! We can use local contracts in Remix now.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><h2 id="h-0x02-writing-and-debugging-smart-contract" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x02 Writing and Debugging Smart Contract</h2><p>When writing and debugging smart contract codes, we can debug in our local Remix VM.</p><p>Only when deploying smart contract, we need to have actual interaction with the blockchain network.</p><h3 id="h-21-create-contract-file" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2.1 Create contract file</h3><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><h3 id="h-22-write-contract-code" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2.2 Write contract code</h3><p>Copy and paste those lines into <code>hello.sol</code></p><pre data-type="codeBlock" text="pragma solidity^0.8.0;

contract hello {
    string public name;
    constructor() public {
        name = &quot;welight&quot;;
    }
}
"><code><span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span>^0.8.0;</span>

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">hello</span> </span>{
    <span class="hljs-keyword">string</span> <span class="hljs-keyword">public</span> name;
    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        name <span class="hljs-operator">=</span> <span class="hljs-string">"welight"</span>;
    }
}
</code></pre><p>Here is how it looks:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>After writing the code, we need to save it. If you are using windows, hit [ctrl + s]. If Unix, hit [command + s].</p><h3 id="h-23-switch-to-compile-view-and-select-specific-compiler-version" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2.3 Switch to compile view and select specific compiler version</h3><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">image-20210318121523436</figcaption></figure><h3 id="h-24-switch-to-environment-view-and-deploy-the-contract" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2.4 Switch to environment view and deploy the contract</h3><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">image-20200520125102675</figcaption></figure><p>!image-20200520125230295</p><h3 id="h-25-open-up-contract-view-and-debug-the-function" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2.5 Open up contract view and debug the function</h3><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">image-20200520125409304</figcaption></figure><p>Click on Run to get the result.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><h2 id="h-0x03-flatten-code" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x03 Flatten Code</h2><p>In production environment, we normally don&apos;t &quot;write&quot; all the code, but use third party libraries like <code>open-zepplin</code>.</p><pre data-type="codeBlock" text="// SPDX-License-Identifier: MIT
pragma solidity 0.8.0;

import &quot;@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol&quot;;
import &quot;@openzeppelin/contracts/security/ReentrancyGuard.sol&quot;;
import &quot;@openzeppelin/contracts/access/Ownable.sol&quot;;
"><code><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> 0.8.0;</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">"@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"@openzeppelin/contracts/security/ReentrancyGuard.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"@openzeppelin/contracts/access/Ownable.sol"</span>;
</code></pre><p>Importing libraries are all good when deploying, but when doing source code verification (see <code>0x05</code>), it will generate problems like <code>File import callback not supported</code>.</p><p>So we can do <code>Flatten</code> operation for our code. We recommend usig <code>hardhat</code>.</p><p>Hardhat&apos;s tutorial resource is rich. Here is the link for one of the best.</p><blockquote><p>[Translated] Hardhat Intro Tutorial: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://learnblockchain.cn/article/1356">https://learnblockchain.cn/article/1356</a></p></blockquote><p>In this step, we use <code>hardhat flatten</code> function.</p><pre data-type="codeBlock" text=" npx hardhat flatten contracts/web3dev.sol
"><code> npx hardhat flatten contracts<span class="hljs-operator">/</span>web3dev.sol
</code></pre><p>After the execution, <code>flattened</code> code will be displayed. Then we copy and paste them into Remix.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">image-20220112201227831</figcaption></figure><p>Note that <code>flatten</code> function is still not perfect, so we need to delete manully some of the <code>SPDX</code> and <code>pragma</code>.</p><h2 id="h-0x04-deploy-smart-contract" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x04 Deploy Smart Contract</h2><p>We can deploy the contract onto the blockchain by <code>Injected Web3</code>.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">image-20220112201608832</figcaption></figure><p>Except for the network difference, contract deployment is the same as contract debugging in <code>0x02</code>.</p><p>We can easily add Moonbeam, Moonriver, and MoonbaseAlpha networks by clicking a few buttons with the help of the following doc.</p><blockquote><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.moonbeam.network/tokens/connect/metamask/">https://docs.moonbeam.network/tokens/connect/metamask/</a></p></blockquote><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">image-20220112202020362</figcaption></figure><h2 id="h-0x05-verify-contract-on-explorer" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x05 Verify Contract on Explorer</h2><p>Verifying using browser API is indeed a choice, but it&apos;s a complicated one. We can verify just by inputting the source code.</p><p>Moonbeam explorer is at:</p><blockquote><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://moonbase.moonscan.io/">https://moonbase.moonscan.io/</a></p></blockquote><p>First we see an unverified contract on explorer.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">image-20220112202930685</figcaption></figure><p>We click <code>Verify and Publish</code>.</p><p>Then select <code>Single File</code> and license:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">image-20220112203647704</figcaption></figure><p>After that, we paste the flattened code from <code>0x03</code> into the field:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">image-20220112203808386</figcaption></figure><p>Click on <code>Verify and Publish</code> to submit:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">image-20220112203835726</figcaption></figure><p>We are all done when it shows <code>Succefully</code>。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">image-20220112203911660</figcaption></figure><p>Now we access the contract again. When we click on <code>Contract</code> page, <code>Read</code> and <code>Write</code> appears!</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">image-20220112204021117</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">leeduckgo</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">msfew</figcaption></figure>]]></content:encoded>
            <author>apecoder@newsletter.paragraph.com (Web3dAppDevCamp)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/9cb5da88fe2456a589702ed1286542b7de436f147792069c1b1bcd03a106a1a6.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[【Workshop 0x01 Summary】 Generate Game Map based on Blockchain Data]]></title>
            <link>https://paragraph.com/@apecoder/workshop-0x01-summary-generate-game-map-based-on-blockchain-data</link>
            <guid>ZEuppY3lDKrYOqyV6WIx</guid>
            <pubDate>Fri, 07 Jan 2022 06:52:15 GMT</pubDate>
            <description><![CDATA[1 Participating MembersDM (Dungeon Master)ledduckgo: Cool-Oriented Programming.Players (Offline)叶开: A developer with a teacher certificate who wrote this book on Go language and blockchain小林小林能不能行: PhD students who hope to graduate on timeRay: A wage earner, a block chain noob, is studying hardAdastra: One of the heads of a university blockchain association, wage earner in web2Brian Seong: Vice President of a University Blockchain Association, an evangelist who is keen on blockchain technolog...]]></description>
            <content:encoded><![CDATA[<h2 id="h-1-participating-members" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">1 Participating Members</h2><ul><li><p>DM (Dungeon Master)</p><ul><li><p>ledduckgo: Cool-Oriented Programming.</p></li></ul></li><li><p>Players (Offline)</p><ul><li><p>叶开: A developer with a teacher certificate who wrote this book on Go language and blockchain</p></li><li><p>小林小林能不能行: PhD students who hope to graduate on time</p></li><li><p>Ray: A wage earner, a block chain noob, is studying hard</p></li><li><p>Adastra: One of the heads of a university blockchain association, wage earner in web2</p></li><li><p>Brian Seong: Vice President of a University Blockchain Association, an evangelist who is keen on blockchain technology education</p></li><li><p>饼: A member of the Blockchain Association of a certain university, an enthusiastic blockchain evangelist</p></li></ul></li><li><p>Players (Online)</p><ul><li><p>追忆似水年华: a web engineer who can only write JavaScript</p></li><li><p>fengfeng: a small developer of blockchain</p></li><li><p>Henry</p></li><li><p>Hqwangningbo: Blockchain development mastermind</p></li></ul></li><li><p>Player (Async)</p><ul><li><p>Msfew: front-end rookie, ruthless research report collection machine</p></li></ul></li></ul><h2 id="h-2-introduction-of-workshop" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">2 Introduction of Workshop</h2><blockquote><p>Project of this Workshop:</p></blockquote><blockquote><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/WeLightProject/Web3-dApp-Camp/discussions/26">https://github.com/WeLightProject/Web3-dApp-Camp/discussions/26</a></p></blockquote><p><strong>Topic:</strong> Generate game maps based on blockchain data!</p><p>Using the data on blockchain as the data source, trying to generate a 2D game map is exploring the possibility of &quot;blockchain game&quot; happily!</p><h3 id="h-21-background" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2.1 Background</h3><p><strong>&quot;Verifiable Self-growing Distributed Data Source: A New Perspective on Blockchain&quot;</strong></p><p>The blockchain system is a comprehensive product of a variety of complex technologies. Therefore, the system can be viewed from many different interesting perspectives:</p><ul><li><p>A distributed consensus system with unlimited increase of nodes without performance degradation</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mp.weixin.qq.com/s/REZs6PqlY4WdUJXuBVMnbw">A Gaussian Timer</a></p></li><li><p>A Web3 system</p></li><li><p>…</p></li></ul><p>However, this project attempts to start from a brand new perspective and treat the blockchain as a verifiable self-growing distributed data source.</p><p>This data source has the following characteristics:</p><p><strong>Self-growing</strong></p><p>Data self-grows at a fixed frequency. Therefore, under the deterministic rules, a series of objects from metadata such as regions, treasures, monsters, etc. are also self-growth!</p><p><strong>Distributed</strong></p><p>The metadata comes from the blockchain, so there is no need to worry about the loss and tampering of metadata.</p><ul><li><p><strong>Verifiable</strong></p></li></ul><p>Because both the &quot;metadata&quot; and &quot;conversion rules&quot; of the data on the chain are &quot;verifiable&quot;.</p><ul><li><p><strong>free</strong></p></li></ul><p>It&apos;s free to read blockchain data , so it is equivalent to the free data source we have!</p><h3 id="h-22-planning-of-workshop" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2.2 Planning of Workshop</h3><p>0x0) Introduction of Web3 dApp Dev Workshop@NonceGeek</p><p>Cool-Oriented Programming.</p><p>0x1) Introduction to IDEA</p><p>0x2) Brainstorming</p><p>Thinking points:</p><ul><li><p><strong>The logic of the source IDEA——</strong></p></li></ul><p>Does the IDEA of the on-chain data source make sense?</p><ul><li><p>A map generated based on blockchain data——</p><ul><li><p>What are the amazing possibilities of maps generated from on-chain data sources?</p></li><li><p>Based on the generated map, what kind of Amazing gameplay (DAO/NFT/GAME/Others) might we have?</p></li></ul></li><li><p>Diffuse thinking ——</p><ul><li><p>Based on the data source on the chain, will we have other interesting branches?</p></li></ul></li></ul><p>0x3) A small goal to be completed by this WorkShop</p><p>Given the backend interface:</p><blockquote><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/WeLightProject/tai-shang-world-generator/wiki/API-Doc">https://github.com/WeLightProject/tai-shang-world-generator/wiki/API-Doc</a></p></blockquote><p>Carry out a front-end implementation and deploy to Github-Pages!</p><p>0x4) Summary + Brainstorming again!</p><p>Perform a second brain storm on the basis of the above.</p><p>0x5) Free chat</p><p>Let&apos;s talk about anything about blockchain!</p><h2 id="h-3-summary" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">3 Summary</h2><h3 id="h-31-introduction-of-web3-dapp-dev-camp-and-workshop" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0"><strong>3.1 Introduction of Web3 dApp Dev Camp &amp; Workshop</strong></h3><p>Both Web3 dApp Dev Camp and Web3 dApp Dev Workshop were initiated by the NonceGeek team.</p><p>The Web3.0 dApp training camp includes both a project-oriented online training camp based on Github Discussion. The Purpose of Web3.0 dApp Dev Camp is to let the traditional developers, students and blockchain developers quickly acquire web3.0 dApp development skills.</p><blockquote><p><strong>Web3 Dev Camp Information Collection:</strong></p></blockquote><ul><li><p>Gitcoin: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://gitcoin.co/grants/3891/web30-dapp-dev-camp">https://gitcoin.co/grants/3891/web30-dapp-dev-camp</a></p></li><li><p>Github: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/WeLightProject/Web3-dApp-Camp/discussions">https://github.com/WeLightProject/Web3-dApp-Camp/discussions</a></p></li><li><p>Twitter: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/Web3dAppCamp">https://twitter.com/Web3dAppCamp</a></p></li><li><p>Hackerlink: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://hackerlink.io/buidl/1807">https://hackerlink.io/buidl/1807</a></p></li></ul><p>The supporting open source cloud teaching platform WeLightOS won the second prize of the China Blockchain Competition:</p><blockquote><p>WeLightOS: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://sgchanhui.gitee.io/welightblockchainos/">http://sgchanhui.gitee.io/welightblockchainos/</a></p></blockquote><p>Web3 dApp Dev Workshop is an <strong>offline version</strong>, an offline practice activity based on the &quot;desktop game concept&quot;. The current plan is:</p><ul><li><p>Offline Workshops are held at multiple locations <strong>every half a month.</strong> The workshop members are mainly members of Nonce Geek Studio, which adopts a semi-open format and invites a small number of external members to participate (targeted invitations and open paid places).</p></li><li><p>In the future planning, Workshop will gradually open its bases in <strong>New York, Hangzhou, Shenzhen, Shanghai, Nanjing and other cities.</strong></p></li></ul><h3 id="h-32-noncegeek-2022-exploration" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">3.2 NonceGeek 2022 Exploration</h3><p>NonceGeek explored the field of NFT in 2021, the Combination&amp;Decomposition of NFT (TaiShang NFT Combinator), and infrastructures for abstract(loot-liked) NFT（TaiShang NFT Wallet&amp; TaiShang NFT Renderer).</p><p>At the end of 2021, WeLight launched a new direction of exploration, such as exploring the possibility of Function-as-a-service on the Arweave blockchain network.</p><p>In 2022, NonceGeek will actively try the Metaverse Project, make differentiation in such a hot but vague concept of meta-universe, and find the right direction.</p><h3 id="h-33-taishang-world-generator-brainstorm" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">3.3 TaiShang World Generator Brainstorm</h3><h4 id="h-taishang-world-generator-introduction" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0"><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/WeLightProject/tai-shang-world-generator">TaiShang World Generator</a> Introduction</h4><p>At present, random map generation on the market is to randomly generate the map offline, and then upload the object coordinates in the map to the blockchain. Since there is no repeatability, the resulting world is not so Web3. Users cannot generate a world like the Sandbox by themselves, and the ownership of the world is still in the hands of the Sandbox.</p><p>Therefore, this project decided to proceed from this point, and directly use the data that cannot be tampered with on the chain (such as block data, tx data) as a seed to generate an abstract map. The abstract map can be further mint into NFT, and explore more ways to play with it.</p><blockquote><p>Repo: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/WeLightProject/tai-shang-world-generator">https://github.com/WeLightProject/tai-shang-world-generator</a></p></blockquote><h4 id="h-map-generation" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Map generation</h4><p>At present, TaiShang World Generator can use each block as the data source, combined with the generation rules stored on Arweave that can be loaded into the runtime of the program, and finally generate different two-dimensional matrices containing different elements.</p><p>It should be noted that the chain (Polygon+Arweave) is responsible for determining the abstract two-dimensional map, and the rendering of the abstract two-dimensional map into the final map is the responsibility of the game operator under the chain.</p><h4 id="h-generation-rules" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Generation rules</h4><p>From a bunch of random data to the map, there are actually precedents in traditional games——</p><p>Take Minecraft as an example, the map generation rules are determined before compilation, and the map will be generated and rendered according to the rules during the game.</p><p>If you &quot;re-engrave&quot; the map generation in Web3, you need to make sure: &quot;The rule code is small&quot; and &quot;The programming language supports dynamic loading code&quot;. In this way, the rule code itself can be stored on a blockchain such as Arweave, and users are allowed to Load on the server, just like a FaaS service.</p><h4 id="h-for-the-game-the-question-of-which-elements-are-on-the-chain" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">For the game, the question of which elements are on the chain</h4><p>A common practice in games is to store configuration such as generation rules in Celeste&apos;s cloud function container.</p><p>Smaller games will store the rules on the chain, but there are problems that are difficult to modify.</p><p>For big games, only data that needs to be modified, such as generation rules or game materials, will be uploaded to the chain, and most of the important data is placed off-chain.</p><h4 id="h-map-modification" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Map modification</h4><p>The actual game map is actually upgraded after the player performs the operation. How to deal with this problem in this project?</p><p>Since the source data of the map is stored on the chain, it cannot be tampered with, and the original map (the genesis map) is generated.</p><p>The source map cannot be modified, but subsequent users can destroy or build the map like Minecraft. The revised map is a brand new unique map. The user can save some interactions and modifications to the map by casting the form of NFT. This kind of thinking is similar to Bitcoin&apos;s UTXO or Arweave&apos;s SCP.</p><p>The user can choose to directly save the newly revised map or the operation log of the map.</p><h4 id="h-map-expansion" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Map expansion</h4><p>Due to the self-growth of blockchain data, all generated maps can be spliced together to form a huge map.</p><p>But this will cause a problem that if the growth rate of players in the game is less than the growth rate of the map, then most of the map will be idle.</p><p>This problem can only make sense through Mint&apos;s maps, or it can be solved by designing restriction rules.</p><h4 id="h-the-economic-model-of-the-map" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">The economic model of the map</h4><ul><li><p>Randomly generated maps with better terrain or higher rarity will have higher value.</p></li><li><p>After the game player interacts on the map, the owner of the map will receive revenue.</p></li><li><p>The map owned by the player can be spliced by the player to form a new terrain.</p></li><li><p>The value of the map can fall on the player interaction on the map, which can form an ecology.</p></li></ul><h3 id="h-34-free-chat" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">3.4 Free Chat</h3><h4 id="h-discussion-on-nft-art" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Discussion on NFT Art</h4><ul><li><p>NFT art still relies on storytelling and requires consensus;</p></li><li><p>The aborigines of Crypto prefer Geek styles such as pixel style;</p></li><li><p>This is the level of appreciation that the aboriginal people of Crypto have brought to the computer&apos;s pre-knowledge.</p></li></ul><h4 id="h-nft-cross-chain" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">NFT cross-chain</h4><ul><li><p>FX Portal can achieve decentralized cross-chain and communication between cross-chain contracts. Lock the NFT on one chain, and cast the NFT on the other chain.</p></li></ul><h3 id="h-35-other-talks-about-blockchain" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">3.5 Other talks about Blockchain</h3><h4 id="h-polygon" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Polygon</h4><p>In the process, everyone talked about Polygon. Polygon is an expansion solution for Ethereum.</p><p>The expansion of Ethereum will not be limited to one protocol, but there will be various expansion, sharding and Layer 2 solutions. Polygon is currently a PoS (Proof of Stake) Ethereum sidechain, which is basically the same as the Ethereum network in terms of use. In addition, Polygon also provides an SDK that allows developers to build a simple blockchain network by themselves. Polygon is currently studying zkEVM and is expected to launch zk and other related functions at the end of 2023.</p><h4 id="h-web3games" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0"><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://web3games.org/">Web3Games</a></h4><p>Members shared their own Web3Games organization. Web3Games is a blockchain game development service company.</p><p>The ecology of Web3Games includes blockchain games, NFT and DeFi. Web3Games provides chain game DID solutions, API-as-a-service service agreement, one-stop blockchain portal, and resources of various chain game development studios.</p><p>Web3Games provides a dedicated blockchain network for games based on Substrate, supports multi-environment and multi-smart contract operation, and supports WASM and EVM virtual machines. In addition, this blockchain also supports multi-project communication, allowing two-way interaction in different execution environments.</p><h4 id="h-substrate" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Substrate</h4><p>Substrate did not convert macros into Rust native code before version 3.0, encapsulating a lot of low-level details. At present, under the maintenance of the official team, more and more non-low-level macros have been opened up. The update speed of Substrate is about 15 days faster than Polkadot, and the update is relatively fast. It has many experimental features and is suitable for developers to learn.</p><h4 id="h-random-number-problem" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Random number problem</h4><p>Traditional smart contracts cannot get external random numbers, and can only be generated by current or future chain information in the contract. When the source code of the contract is made public, it is easy to be attacked by hackers, or the block information used to generate random numbers is obtained in advance by large mining pools, which interferes with randomness.</p><p>One example is that on the Solana chain, as a chain that goes down from time to time, the random number function is likely to be compromised after being attacked by DDoS.</p><h4 id="h-tsinghua-university-blockchain-association" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Tsinghua University Blockchain Association</h4><p>There are two main current plans of the Blockchain Association:</p><p>One is to preach, let more people understand the blockchain;</p><p>The second is to organize more activities and get in touch with more members who already know blockchain.</p><h4 id="h-welightblockchainos" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0"><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/WeLightProject/WeLightBlockchainOS">WeLightBlockchainOS</a></h4><p>In the self-introduction session, some members asked about the WeLightBlockchainOS project that the Web3 dApp Dev Camp did before. WeLightBlockchainOS is a cloud-based blockchain development toolbox that uses an operating system-like interface to help developers quickly and easily get started with blockchain development.</p><p>In the daily teaching process, the commonly used collaborative teaching operation solution is to use VNS to connect to the actual host remotely, but it cannot solve the large number of students. WeLightBlockchainOS realizes the integration of various blockchain development tools through the front-end iframe, and realizes the function of document sharing in the teaching process and remote code writing.</p><h2 id="h-4-photo-of-workshop-0x01" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">4 Photo of Workshop 0x01</h2><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">WechatIMG38</figcaption></figure><p><strong>Authors:</strong></p><p><strong>! For Chinese User, You can connect us by WeChat ID: 197626581</strong></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">msfew</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">leeduckgo</figcaption></figure>]]></content:encoded>
            <author>apecoder@newsletter.paragraph.com (Web3dAppDevCamp)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/9cb5da88fe2456a589702ed1286542b7de436f147792069c1b1bcd03a106a1a6.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[Solve a Puzzle to join WEB³DAO@CN!]]></title>
            <link>https://paragraph.com/@apecoder/solve-a-puzzle-to-join-web-dao-cn</link>
            <guid>kVaiHxFcb3bWk7F7gVo1</guid>
            <pubDate>Mon, 27 Dec 2021 07:27:37 GMT</pubDate>
            <description><![CDATA[WEB³DAO@CN WEB3 Chinese Community Preparation Group is looking forward to your joiningWEB3 Chinese Community is a decentralized DAO organization Our mission is to enhance the influence of the Chinese world in the WEB3 revolution. DAO is not a company, and it needs more people to build together to complete The first batch of 20 preparatory team members are only available for WEB3 developers to join. If you are not a WEB3 developer, don&apos;t worry. There will be available for other group memb...]]></description>
            <content:encoded><![CDATA[<h2 id="h-webdaocn-web3-chinese-community-preparation-group-is-looking-forward-to-your-joining" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"><code>WEB³DAO@CN</code> WEB3 Chinese Community Preparation Group is looking forward to your joining</h2><p>WEB3 Chinese Community is a decentralized DAO organization</p><p>Our mission is to enhance the influence of the Chinese world in the WEB3 revolution.</p><p>DAO is not a company, and it needs more people to build together to complete</p><p>The first batch of 20 preparatory team members are only available for WEB3 developers to join.</p><p>If you are not a WEB3 developer, don&apos;t worry. There will be available for other group members to join in the future.</p><h4 id="h-to-sign-up-you-need-to-solve-the-following-puzzle" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">To sign up, you need to solve the following &quot;puzzle&quot;:</h4><ol><li><p>There is a contract deployed in Polygon chain that is not open source. The address of the contract is in the QR code below.</p></li><li><p>You need to find one of the registration function methods. The parameter is another format of your WeChat nickname.</p></li><li><p>Send the transaction hash to me for verification.</p></li><li><p>Successful verification can be considered successful registration, and there will be an event in the chain triggered to record your registration order and address</p></li><li><p>The person can only be registered once. According to your contribution to the order of registration and your registration address, you will be gifted DAO Genesis honorary awards.</p></li></ol><h4 id="h-description" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Description:</h4><ul><li><p>The registration puzzle is not too difficult. It mainly test if you can use tools to call contracts that are not open source and do not have a front-end.</p></li><li><p>During the preparation period of DAO, we need to work together. If you do not have time for that, please do not sign up, but keep in mind that you still have the opportunity to participate in DAO activities in the future.</p></li><li><p>At the end of the preparation period of the DAO will assess the contribution of members. If there is no contribution or contribution is too low, DAO members may cancel the Genesis honor awards.</p></li><li><p>When registration is full, we will step up the pace of building DAO, and strive to open the WEB3DAO community as soon as possible!</p></li></ul><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">qr</figcaption></figure>]]></content:encoded>
            <author>apecoder@newsletter.paragraph.com (Web3dAppDevCamp)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/9cb5da88fe2456a589702ed1286542b7de436f147792069c1b1bcd03a106a1a6.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[Get & Set Value 3.0 |  Web3.0 dApp Dev 0x06]]></title>
            <link>https://paragraph.com/@apecoder/get-set-value-3-0-web3-0-dapp-dev-0x06</link>
            <guid>xRPZ7kdf494dtNmW0jIE</guid>
            <pubDate>Sun, 12 Dec 2021 05:50:17 GMT</pubDate>
            <description><![CDATA[In PurposeHandler version 2.0, we learned to add permission control to functions via the require statement. Now we can add a real economy mechanism to it, so that the value of purpose is controlled by a real bidding auction mechanism!0x01 Add OwnerTo get the owner of a contract owner is a must-learn operation for newbies. The easiest way is to set a public owner variable and pass the _owner parameter in the constructor.pragma solidity >=0.8.0 &#x3C;0.9.0; //SPDX-License-Identifier: MIT contra...]]></description>
            <content:encoded><![CDATA[<p>In PurposeHandler version 2.0, we learned to add permission control to functions via the <code>require</code> statement.</p><p>Now we can add a real economy mechanism to it, so that the value of <code>purpose</code> is controlled by a real bidding auction mechanism!</p><h3 id="h-0x01-add-owner" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">0x01 Add Owner</h3><p>To get the owner of a contract <code>owner</code> is a must-learn operation for newbies.</p><p>The easiest way is to set a public <code>owner</code> variable and pass the <code>_owner</code> parameter in the constructor.</p><pre data-type="codeBlock" text="pragma solidity &gt;=0.8.0 &lt;0.9.0;
//SPDX-License-Identifier: MIT

contract PurposeHandler {

  string public purpose = &quot;Building Unstoppable Apps&quot;;
  address public owner = owner;
  // fill in your own address (start with 0x) here

  constructor(address _owner) {
    owner = _owner;
  }

  function setPurpose(string memory newPurpose) public {
      // about msg.sender:
      // https://cryptozombies.io/en/lesson/2/chapter/3
      // about require:
      // https://cryptozombies.io/en/lesson/2/chapter/4
      require( msg.sender == owner, &quot;NOT THE OWNER!&quot;);

      purpose = newPurpose;
      console.log(msg.sender,&quot;set purpose to&quot;,purpose);
  }
}
"><code><span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> >=0.8.0 &#x3C;0.9.0;</span>
<span class="hljs-comment">//SPDX-License-Identifier: MIT</span>

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">PurposeHandler</span> </span>{

  <span class="hljs-keyword">string</span> <span class="hljs-keyword">public</span> purpose <span class="hljs-operator">=</span> <span class="hljs-string">"Building Unstoppable Apps"</span>;
  <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> owner <span class="hljs-operator">=</span> owner;
  <span class="hljs-comment">// fill in your own address (start with 0x) here</span>

  <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _owner</span>) </span>{
    owner <span class="hljs-operator">=</span> _owner;
  }

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setPurpose</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span> newPurpose</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
      <span class="hljs-comment">// about msg.sender:</span>
      <span class="hljs-comment">// https://cryptozombies.io/en/lesson/2/chapter/3</span>
      <span class="hljs-comment">// about require:</span>
      <span class="hljs-comment">// https://cryptozombies.io/en/lesson/2/chapter/4</span>
      <span class="hljs-built_in">require</span>( <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> owner, <span class="hljs-string">"NOT THE OWNER!"</span>);

      purpose <span class="hljs-operator">=</span> newPurpose;
      console.log(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>,<span class="hljs-string">"set purpose to"</span>,purpose);
  }
}
</code></pre><p>In production, this is generally achieved by importing <code>ownable.sol</code>.</p><p><code>ownable.sol</code> in OpenZepplin.</p><blockquote><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol">https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol</a></p></blockquote><p><code>ownable.sol</code>:</p><pre data-type="codeBlock" text="pragma solidity ^0.4.25;

  /**
  * @title Ownable
  * @dev The Ownable contract has an owner address, and provides basic authorization control
  * functions, this simplifies the implementation of &quot;user permissions&quot;.
  */
  contract Ownable {
    address private _owner;

    event OwnershipTransferred(
      address indexed previousOwner,
      address indexed newOwner
    );

    /**
    * @dev The Ownable constructor sets the original `owner` of the contract to the sender
    * account.
    */
    constructor() internal {
      _owner = msg.sender;
      emit OwnershipTransferred(address(0), _owner);
    }

    /**
    * @return the address of the owner.
    */
    function owner() public view returns(address) {
      return _owner;
    }

    /**
    * @dev Throws if called by any account other than the owner.
    */
    modifier onlyOwner() {
      require(isOwner());
      _;
    }

    /**
    * @return true if `msg.sender` is the owner of the contract.
    */
    function isOwner() public view returns(bool) {
      return msg.sender == _owner;
    }

    /**
    * @dev Allows the current owner to relinquish control of the contract.
    * @notice Renouncing to ownership will leave the contract without an owner.
    * It will not be possible to call the functions with the `onlyOwner`
    * modifier anymore.
    */
    function renounceOwnership() public onlyOwner {
      emit OwnershipTransferred(_owner, address(0));
      _owner = address(0);
    }

    /**
    * @dev Allows the current owner to transfer control of the contract to a newOwner.
    * @param newOwner The address to transfer ownership to.
    */
    function transferOwnership(address newOwner) public onlyOwner {
      _transferOwnership(newOwner);
    }

    /**
    * @dev Transfers control of the contract to a newOwner.
    * @param newOwner The address to transfer ownership to.
    */
    function _transferOwnership(address newOwner) internal {
      require(newOwner != address(0));
      emit OwnershipTransferred(_owner, newOwner);
      _owner = newOwner;
    }
  }
"><code><span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.4.25;</span>

  <span class="hljs-comment">/**
  * @title Ownable
  * @dev The Ownable contract has an owner address, and provides basic authorization control
  * functions, this simplifies the implementation of "user permissions".
  */</span>
  <span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Ownable</span> </span>{
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">private</span> _owner;

    <span class="hljs-function"><span class="hljs-keyword">event</span> <span class="hljs-title">OwnershipTransferred</span>(<span class="hljs-params">
      <span class="hljs-keyword">address</span> <span class="hljs-keyword">indexed</span> previousOwner,
      <span class="hljs-keyword">address</span> <span class="hljs-keyword">indexed</span> newOwner
    </span>)</span>;

    <span class="hljs-comment">/**
    * @dev The Ownable constructor sets the original `owner` of the contract to the sender
    * account.
    */</span>
    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">internal</span></span> </span>{
      _owner <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>;
      <span class="hljs-keyword">emit</span> OwnershipTransferred(<span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>), _owner);
    }

    <span class="hljs-comment">/**
    * @return the address of the owner.
    */</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">owner</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span>(<span class="hljs-params"><span class="hljs-keyword">address</span></span>) </span>{
      <span class="hljs-keyword">return</span> _owner;
    }

    <span class="hljs-comment">/**
    * @dev Throws if called by any account other than the owner.
    */</span>
    <span class="hljs-function"><span class="hljs-keyword">modifier</span> <span class="hljs-title">onlyOwner</span>(<span class="hljs-params"></span>) </span>{
      <span class="hljs-built_in">require</span>(isOwner());
      <span class="hljs-keyword">_</span>;
    }

    <span class="hljs-comment">/**
    * @return true if `msg.sender` is the owner of the contract.
    */</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isOwner</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span>(<span class="hljs-params"><span class="hljs-keyword">bool</span></span>) </span>{
      <span class="hljs-keyword">return</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> _owner;
    }

    <span class="hljs-comment">/**
    * @dev Allows the current owner to relinquish control of the contract.
    * @notice Renouncing to ownership will leave the contract without an owner.
    * It will not be possible to call the functions with the `onlyOwner`
    * modifier anymore.
    */</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">renounceOwnership</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title">onlyOwner</span> </span>{
      <span class="hljs-keyword">emit</span> OwnershipTransferred(_owner, <span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>));
      _owner <span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>);
    }

    <span class="hljs-comment">/**
    * @dev Allows the current owner to transfer control of the contract to a newOwner.
    * @param newOwner The address to transfer ownership to.
    */</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">transferOwnership</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> newOwner</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title">onlyOwner</span> </span>{
      _transferOwnership(newOwner);
    }

    <span class="hljs-comment">/**
    * @dev Transfers control of the contract to a newOwner.
    * @param newOwner The address to transfer ownership to.
    */</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_transferOwnership</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> newOwner</span>) <span class="hljs-title"><span class="hljs-keyword">internal</span></span> </span>{
      <span class="hljs-built_in">require</span>(newOwner <span class="hljs-operator">!</span><span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>));
      <span class="hljs-keyword">emit</span> OwnershipTransferred(_owner, newOwner);
      _owner <span class="hljs-operator">=</span> newOwner;
    }
  }
</code></pre><h3 id="h-0x02-create-auction-mechanism-by-a-require-rule" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">0x02 Create <code>auction mechanism</code> by a require rule</h3><p>The rule is that if the bid is higher than the current price, then the value of <code>set-purpose</code> can be modified; if it is not as high as the current price, then an error is thrown.</p><pre data-type="codeBlock" text="pragma solidity &gt;=0.8.0 &lt;0.9.0;
//SPDX-License-Identifier: MIT

contract PurposeHandler {

  string public purpose = &quot;Building Unstoppable Apps&quot;;
  address public owner = owner;
  uint256 public price = 0.001 ether;
  // fill in your own address (start with 0x) here

  constructor(address _owner) {
    owner = _owner;
  }

  function setPurpose(string memory newPurpose) payable public {
      require( msg.value &gt; price, &quot;NOT ENOUGH!&quot;);
      purpose = newPurpose;
      // update price when guy set
      price = msg.value;
      console.log(msg.sender,&quot;set purpose to&quot;,purpose);
  }

}
"><code><span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> >=0.8.0 &#x3C;0.9.0;</span>
<span class="hljs-comment">//SPDX-License-Identifier: MIT</span>

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">PurposeHandler</span> </span>{

  <span class="hljs-keyword">string</span> <span class="hljs-keyword">public</span> purpose <span class="hljs-operator">=</span> <span class="hljs-string">"Building Unstoppable Apps"</span>;
  <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> owner <span class="hljs-operator">=</span> owner;
  <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">public</span> price <span class="hljs-operator">=</span> <span class="hljs-number">0</span><span class="hljs-number">.001</span> <span class="hljs-literal">ether</span>;
  <span class="hljs-comment">// fill in your own address (start with 0x) here</span>

  <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _owner</span>) </span>{
    owner <span class="hljs-operator">=</span> _owner;
  }

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setPurpose</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span> newPurpose</span>) <span class="hljs-title"><span class="hljs-keyword">payable</span></span> <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
      <span class="hljs-built_in">require</span>( <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span> <span class="hljs-operator">></span> price, <span class="hljs-string">"NOT ENOUGH!"</span>);
      purpose <span class="hljs-operator">=</span> newPurpose;
      <span class="hljs-comment">// update price when guy set</span>
      price <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span>;
      console.log(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>,<span class="hljs-string">"set purpose to"</span>,purpose);
  }

}
</code></pre><h3 id="h-0x03-withdrawal-mechanism" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">0x03 Withdrawal mechanism</h3><p>The function <code>getBalance()</code> allows the <code>owner</code> to get the balance in the contract, and the function <code>getMyMoney</code> allows the balance in the contract to be withdrawn by.</p><pre data-type="codeBlock" text="pragma solidity &gt;=0.8.0 &lt;0.9.0;
//SPDX-License-Identifier: MIT

contract PurposeHandler {

  string public purpose = &quot;Building Unstoppable Apps&quot;;
  address public owner;
  uint256 public price = 0.001 ether;

  constructor(address _owner) {
    owner = _owner;
  }

  function setPurpose(string memory newPurpose) payable public {
      require( msg.value &gt; price, &quot;NOT ENOUGH!&quot;);
      purpose = newPurpose;
      // update price when guy set
      price = msg.value;
  }

  function getBalance() view public returns(uint256) {
      return address(this).balance;
  }

  function getMyMoney(address _to, uint256 amount) public {
          require(msg.sender==owner);
          address payable receiver = payable(_to);
        receiver.transfer(amount);
  }
}
"><code><span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> >=0.8.0 &#x3C;0.9.0;</span>
<span class="hljs-comment">//SPDX-License-Identifier: MIT</span>

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">PurposeHandler</span> </span>{

  <span class="hljs-keyword">string</span> <span class="hljs-keyword">public</span> purpose <span class="hljs-operator">=</span> <span class="hljs-string">"Building Unstoppable Apps"</span>;
  <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> owner;
  <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">public</span> price <span class="hljs-operator">=</span> <span class="hljs-number">0</span><span class="hljs-number">.001</span> <span class="hljs-literal">ether</span>;

  <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _owner</span>) </span>{
    owner <span class="hljs-operator">=</span> _owner;
  }

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setPurpose</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span> newPurpose</span>) <span class="hljs-title"><span class="hljs-keyword">payable</span></span> <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
      <span class="hljs-built_in">require</span>( <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span> <span class="hljs-operator">></span> price, <span class="hljs-string">"NOT ENOUGH!"</span>);
      purpose <span class="hljs-operator">=</span> newPurpose;
      <span class="hljs-comment">// update price when guy set</span>
      price <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span>;
  }

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getBalance</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span></span>) </span>{
      <span class="hljs-keyword">return</span> <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>).<span class="hljs-built_in">balance</span>;
  }

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getMyMoney</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _to, <span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
          <span class="hljs-built_in">require</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>=<span class="hljs-operator">=</span>owner);
          <span class="hljs-keyword">address</span> <span class="hljs-keyword">payable</span> receiver <span class="hljs-operator">=</span> <span class="hljs-keyword">payable</span>(_to);
        receiver.<span class="hljs-built_in">transfer</span>(amount);
  }
}
</code></pre><h3 id="h-0x04-record-logs-of-set-purpose-by-event" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">0x04 Record logs of set purpose by Event</h3><p>What is an event?</p><blockquote><p>A blockchain is a list of blocks - they are basically made up of transactions. Each transaction has a receipt attached to it, which contains zero or more log entries. These log entries represent the results generated when an event is triggered in a smart contract.</p><p>In Solidity source code, to define an <code>event</code>, you need to mark it by prefixing it with the event keyword (similar to the usage of the <code>function</code> keyword). You can then call or trigger the event from within any function that you wish to generate the event. You can trigger events from any function using the <code>emit</code> keyword.</p><p>Someone may want to add &quot;listen&quot; for events in the DAPP. It uses the filtering functionality of Web 3.0 (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethcore/parity#eth_newfilter">filtering functionality of Web 3.0</a>).</p><p>--<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://learnblockchain.cn/question/29">https://learnblockchain.cn/question/29</a></p></blockquote><p>We can add <code>event</code> to the setPurpose function to record the history of set purpose.</p><p>Translated with <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://www.DeepL.com/Translator">www.DeepL.com/Translator</a> (free version)</p><pre data-type="codeBlock" text="pragma solidity &gt;=0.8.0 &lt;0.9.0;
//SPDX-License-Identifier: MIT

contract PurposeHandler {

  event SetPurpose(address sender, string purpose);

  string public purpose = &quot;Building Unstoppable Apps&quot;;
  address public owner;
  uint256 public price = 0.001 ether;

  constructor(address _owner) {
    owner = _owner;
  }

  function setPurpose(string memory newPurpose) payable public {
      require( msg.value &gt; price, &quot;NOT ENOUGH!&quot;);
      purpose = newPurpose;
      // update price when guy set
      price = msg.value;
      emit SetPurpose(msg.sender, purpose);
  }

  function getBalance() view public returns(uint256) {
      return address(this).balance;
  }

  function getMyMoney(address _to, uint256 amount) public {
          require(msg.sender==owner);
          address payable receiver = payable(_to);
        receiver.transfer(amount);
  }
}
"><code><span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> >=0.8.0 &#x3C;0.9.0;</span>
<span class="hljs-comment">//SPDX-License-Identifier: MIT</span>

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">PurposeHandler</span> </span>{

  <span class="hljs-function"><span class="hljs-keyword">event</span> <span class="hljs-title">SetPurpose</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> sender, <span class="hljs-keyword">string</span> purpose</span>)</span>;

  <span class="hljs-keyword">string</span> <span class="hljs-keyword">public</span> purpose <span class="hljs-operator">=</span> <span class="hljs-string">"Building Unstoppable Apps"</span>;
  <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> owner;
  <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">public</span> price <span class="hljs-operator">=</span> <span class="hljs-number">0</span><span class="hljs-number">.001</span> <span class="hljs-literal">ether</span>;

  <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _owner</span>) </span>{
    owner <span class="hljs-operator">=</span> _owner;
  }

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setPurpose</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span> newPurpose</span>) <span class="hljs-title"><span class="hljs-keyword">payable</span></span> <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
      <span class="hljs-built_in">require</span>( <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span> <span class="hljs-operator">></span> price, <span class="hljs-string">"NOT ENOUGH!"</span>);
      purpose <span class="hljs-operator">=</span> newPurpose;
      <span class="hljs-comment">// update price when guy set</span>
      price <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span>;
      <span class="hljs-keyword">emit</span> SetPurpose(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, purpose);
  }

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getBalance</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span></span>) </span>{
      <span class="hljs-keyword">return</span> <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>).<span class="hljs-built_in">balance</span>;
  }

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getMyMoney</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _to, <span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
          <span class="hljs-built_in">require</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>=<span class="hljs-operator">=</span>owner);
          <span class="hljs-keyword">address</span> <span class="hljs-keyword">payable</span> receiver <span class="hljs-operator">=</span> <span class="hljs-keyword">payable</span>(_to);
        receiver.<span class="hljs-built_in">transfer</span>(amount);
  }
}
</code></pre><h3 id="h-summary" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Summary</h3><p>That&apos;s it for Get &amp; Set value series. Here are all the articles for Get &amp; Set value series.</p><blockquote><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/Web3dAppCamp/status/1450618786436943874">Eth.build Quickstart | Web3.0 dApp Dev 0x01</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/Web3dAppCamp/status/1452046900983570434">Web3.0 dApp Developer Growth Path | Web3.0 dApp Dev 0x02</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/Web3dAppCamp/status/1453378592050585604">Scaffold-Eth Quickstart | web3.0 dApp Dev 0x03</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/Web3dAppCamp/status/1457505517606035459">Get &amp; Set Value 1.0 | Web3.0 dApp Dev 0x04</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/Web3dAppCamp/status/1462976622152220673">Get &amp; Set Value 2.0 | Web3.0 dApp Dev 0x05</a></p></li><li><p>Get &amp; Set Value 3.0 | Web3.0 dApp Dev 0x06</p></li></ul></blockquote><p>In the next post, we move on to the next chapter - the design and implementation of the NFT dApp!</p><p><strong>Authors:</strong></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">leeduckgo</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">msfew</figcaption></figure>]]></content:encoded>
            <author>apecoder@newsletter.paragraph.com (Web3dAppDevCamp)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/9cb5da88fe2456a589702ed1286542b7de436f147792069c1b1bcd03a106a1a6.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[Why RSS So Important | Thinking about Web3]]></title>
            <link>https://paragraph.com/@apecoder/why-rss-so-important-thinking-about-web3</link>
            <guid>tie0OypMpqD2X79bhBGZ</guid>
            <pubDate>Thu, 09 Dec 2021 02:26:12 GMT</pubDate>
            <description><![CDATA[RSS is a web feed that allows users and applications to access updates to websites in a standardized, computer-readable format. Subscribing to RSS feeds can allow a user to keep track of many different websites in a single news aggregator, which constantly monitor sites for new content, removing the need for the user to manually check them. News aggregators (or "RSS readers") can be built into a browser, installed on a desktop computer, or installed on a mobile device. -- WikipediaRSS origina...]]></description>
            <content:encoded><![CDATA[<blockquote><p>RSS is a web feed that allows users and applications to access updates to websites in a standardized, computer-readable format. Subscribing to RSS feeds can allow a user to keep track of many different websites in a single news aggregator, which constantly monitor sites for new content, removing the need for the user to manually check them. News aggregators (or &quot;RSS readers&quot;) can be built into a browser, installed on a desktop computer, or installed on a mobile device.</p><p>-- Wikipedia</p></blockquote><p>RSS originated in the early days of the Internet era, before the existence of giant whales of apps like today (Facebook, Twitter, Google, Tencent, TikTok......). People used RSS to parse their favorite feeds.</p><p>With the development of the Internet, various App whales have emerged, and we just need to register an account, and the App will feed us information. We no longer need to customize our own feeds. App will &quot;continuously push&quot; based on our browsing preferences...... So, RSS is gradually being eliminated by history.</p><p>This is certainly an inevitable process.</p><p>However, there are some interesting questions to ponder. Is this inevitable process the &quot;right&quot; one, and is RSS likely to be revived? And if so, what will the new generation of RSS look like?</p><h2 id="h-0x01-the-humane-and-right" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x01 The &quot;humane&quot; and &quot;right&quot;</h2><p>Too often, we believe that &quot;survival of the fittest&quot; means that those who survive are naturally right.</p><p>However, this crude judgment is problematic. Very often, what survives is &quot;in line with human nature&quot;, not &quot;right&quot;.</p><p>For example, if we think &quot;healthy food = right, unhealthy food = wrong&quot;. The reason why fast food has survived so well in the world is not because it is right, but because it responds to human nature.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">216,501 Hamburger Stock Photos, Pictures &amp; Royalty-Free Images - iStock</figcaption></figure><p>Similarly, why is it that &quot;recommendation algorithm-based apps&quot; are alive and well, but RSS is dying out?</p><p>I think it&apos;s because...</p><p>The App based on recommendation algorithm is in line with human nature, but it doesn&apos;t make it right.</p><p>As the old saying goes, &quot;good advice often jars on the ear,&quot; and saying nice things is human nature and will be liked naturally.</p><p>Likewise, recommending content based on your existing preferences is human nature and will be naturally liked.</p><p>However, just as being addicted to fast food can make us less and less healthy, being caught up in recommendation algorithms can affect our &quot;mental health&quot; as well.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">image-20211209102111563</figcaption></figure><p>We can draw a simple model to describe it.</p><p>Suppose initially I show &quot;Preference A&quot; and &quot;Preference B&quot; in the App (e.g. TikTok), then the App will keep recommending me content of &quot;Preference A&quot; and &quot;Preference B&quot;, thus reinforcing my preference for &quot;Preference A&quot; and &quot;Preference B&quot;, and then the cycle continues......</p><p>It&apos;s naturally in the App&apos;s interest for users to get caught up in their existing preferences - because they stick to the App.</p><p><strong>But is it really in the user&apos;s interest?</strong></p><p>I was addicted to soap operas for a while, so my timeline was full of soap operas. Then suddenly one day I broke away. I wanted to cut ties with soap operas, but the app still pushed soap operas based on my preferences.</p><p>This is the essence of the recommendation algorithm - <strong>&quot;to keep strengthening your existing preferences, creating stickiness to your existing preferences, which in turn becomes stickiness to the App&quot;</strong>.</p><p>We can see that its essence is closed and not open at the spiritual level. After a long period of time under the system of &quot;recommendation algorithm&quot;, we will eventually come to a state - we no longer make changes to our preferences, but the existing preferences keep increasing.</p><p><strong>Even if we link the Internet, we will still become one closed system after another.</strong></p><p>The opposite is RSS, which is absolutely anti-human, requiring you to get your own subscription feeds and then manage them manually on your own - similar to how we go about making complicated dishes at home.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">image-20211209102406832</figcaption></figure><p>However, this sacrifice is rewarded with an open and comfortable information system!</p><p>As shown above, in the RSS-based system, we have Preference A and Preference B. We are free to control the &quot;traffic&quot; of each preference, let&apos;s say 100 messages per day for &quot;Preference A&quot; and 50 messages per day for &quot;Preference B&quot;. I used to like &quot;fishing&quot; and subscribed to a lot of &quot;fishing&quot; related feeds, but now I don&apos;t like it anymore, Ok, cut all the related &quot;feeds&quot;!</p><p>TimeLine is instantly clean.</p><p>Therefore, this system is <strong>&quot;open&quot;</strong>, and people who use this system will also have <strong>&quot;high openness&quot;</strong>.</p><p>Openness is the essential spirit of the Internet, isn&apos;t it?</p><h2 id="h-0x02-is-it-possible-for-rss-to-be-revived" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x02 Is it possible for RSS to be revived?</h2><p>The road to RSS revival may be a tortuous one, but in the long run RSS will regain a larger market.</p><p>But one key factor is that there are &quot;incentives&quot; to offset the &quot;costs of hassle&quot; associated with RSS use, depending on the design. We can divide the incentives into &quot;economic incentives&quot; and &quot;non-economic incentives&quot;.</p><ul><li><p><strong>Economic Incentives</strong></p><p>There is a financial incentive for providing a good RSS feed, which may be created by the provider or integrated by the provider.</p></li><li><p><strong>Non-financial Incentives</strong></p><p>For example, reputation in the Crypto world, etc.</p></li></ul><h2 id="h-0x03-what-does-a-base-on-blockchainweb3-rss-look-like" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0x03 What does a Base on Blockchain/Web3 RSS look like?</h2><p>The following is purely a personal opinion.</p><h3 id="h-the-redefined-personal-blog" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">The redefined personal blog</h3><p>A personal blog is a blog with its own domain name that is not dependent on any blogging platform.</p><p>Although personal blogs have declined in China (only some of the tech leads are still running and maintaining blogs), there are still many personal bloggers from a global perspective.</p><p>In the Crypto world, we can redefine blogging, which is supposed to be an important source of information for RSS. So it seems we should talk about a &quot;blogging renaissance&quot; before a RSS renaissance? But that&apos;s another topic.</p><p>Here&apos;s a brief list of possible ways Crypto blogs could play out.</p><ul><li><p>The Crypto identity of the blogger can be seen</p></li><li><p>The ability to aggregate the blogger&apos;s NFTs</p></li><li><p>Can aggregate the blogger&apos;s multiple Web3 dApp content, such as Mirror</p></li><li><p>If the blogger is a technical blogger, it can show the Web3 projects the blogger is involved in</p></li><li><p>There can be a gateway to the Crypto World/Metaverse where the blogger resides</p></li><li><p>Finally, of course, the blogger can provide RSS feeds</p></li></ul><h3 id="h-penetrating-revenue-and-traceable-re-creation" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Penetrating revenue and traceable re-creation</h3><p>This is different from the Web2 RSS system. Because it&apos;s based on blockchain, the new generation of RSS is technically &quot;revenue-penetrating&quot; and &quot;re-creation-traceable&quot;.</p><p>In other words, through smart contracts, the creators and distributors of RSS feeds, original works and re-creations can both receive revenue, so that the new generation of RSS can really carry &quot;tangible value&quot; and thus offset the &quot;cost of trouble&quot; brought about by the use of RSS.</p><p>However, the proposition of blockchain empowering creators has been mentioned for years, but we have not seen any particularly successful product. Is this because the previous products were not designed from the perspective of &quot;RSS revival&quot;? This requires further thought and discussion.</p><p><strong>Authors:</strong></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">leeduckgo</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">msfew</figcaption></figure>]]></content:encoded>
            <author>apecoder@newsletter.paragraph.com (Web3dAppDevCamp)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/9cb5da88fe2456a589702ed1286542b7de436f147792069c1b1bcd03a106a1a6.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[Web3 dApp Dev Camp launched on Gitcoin! ]]></title>
            <link>https://paragraph.com/@apecoder/web3-dapp-dev-camp-launched-on-gitcoin</link>
            <guid>DYNkxLAASc7E9ayp0wxg</guid>
            <pubDate>Wed, 08 Dec 2021 00:54:45 GMT</pubDate>
            <description><![CDATA[Web3.0 Camp is now launched on Gitcoin~ Come and donate to support it!https://gitcoin.co/grants/3891/web30-dapp-dev-campWhat is a Web 3.0 dApp?From a data perspectiveweb1 means that the user only gets data - we browse the static web pages as web1. web2 means that the user can go beyond getting data to send data - we can read messages and send messages with Twitter. That is web2. web3 means that on top of web2, we also have full ownership and use of the data. We all use Metamask. dApp only has...]]></description>
            <content:encoded><![CDATA[<p>Web3.0 Camp is now launched on Gitcoin~ Come and donate to support it!</p><blockquote><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://gitcoin.co/grants/3891/web30-dapp-dev-camp">https://gitcoin.co/grants/3891/web30-dapp-dev-camp</a></p></blockquote><h2 id="h-what-is-a-web-30-dapp" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"><strong>What is a Web 3.0 dApp?</strong></h2><ul><li><p><strong>From a data perspective</strong></p></li></ul><p>web1 means that the user only gets data - we browse the static web pages as web1.</p><p>web2 means that the user can go beyond getting data to send data - we can read messages and send messages with Twitter. That is web2.</p><p>web3 means that on top of web2, we also have full ownership and use of the data. We all use Metamask. dApp only has permission to call Metamask, and then Metamask asks us if we allow to sign, and if we don&apos;t sign, the transaction will never be sent.</p><ul><li><p><strong>From an application perspective</strong></p></li></ul><p>Users are able to deploy the application themselves, or use any third-party provided application, without 1) security concerns, 2) the possibility of the application being blocked by a subject (e.g., a server gets shut down), and 3) private data that cannot be accessed. One point to note is that whether the application is purely a front-end application is not a necessary indicator of whether it is a Web3 dApp. An Android App, an IOS App, an App with front- and back-end architecture, as long as it meets the above three points, can be considered as a Web3 application.</p><h2 id="h-characteristics-of-web30-dapp" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"><strong>Characteristics of Web3.0 dApp?</strong></h2><ul><li><p>** Return of identity sovereignty and data sovereignty**</p></li></ul><p>For the first time, identity sovereignty and data sovereignty can be completely in the hands of users themselves. For example, in Web3.0 real-time chatting application, we can have full disposal of our own chat records.</p><ul><li><p><strong>Selected user groups</strong></p></li></ul><p>Unlike Web 2.0, which targets large numbers of users, a Web 3.0 application is able to target only small groups of users! For example: targeting a precise 2000-3000 people. This small group of users may have strong willingness to pay, e.g. each user is willing to pay $1000 per year to the Web3.0 application for the appropriate service.</p><ul><li><p><strong>Small Freelance Teams</strong></p></li></ul><p>Web 3.0 applications correspond to very small freelance teams! Very small means that with a good IDEA and a certain level of technical skills, a small team of 1-3 people is enough to build a Web3.0 DApp. In addition, freedom is in the DNA of Web3.0 organizations, and WFH is a common label for Web3.0 organizations. <strong>Therefore, a Web3.0 business or part-time job is very suitable for software engineers! Because it is a job that can cover in your spare time!</strong></p><h2 id="h-web30-dapp-dev-camp" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"><strong>Web3.0 dApp Dev Camp</strong></h2><p>Web3.0 dApp Camp is an online project-oriented camp based on Github Discussion and offline workshops in New York/Beijing/Hangzhou/Nanjing, aiming to let &quot;traditional software developers, college students, blockchain technology practitioners&quot; quickly learn Web3.0 based on blockchains such as Ethereum and other chains.</p><p>Online Github Discussion:</p><blockquote><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/WeLightProject/Web3-dApp-Camp/discussions">https://github.com/WeLightProject/Web3-dApp-Camp/discussions</a></p></blockquote><p>Web3.0 dApp Dev Camp Twitter:</p><blockquote><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/Web3dAppCamp">https://twitter.com/Web3dAppCamp</a></p></blockquote><h2 id="h-web30-dapp-dev-camp-one-pager" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"><strong>Web3.0 dApp Dev Camp One Pager</strong></h2><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">Web3.0 dApp Developer Growth Path Full</figcaption></figure><p><strong>Authors:</strong></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">leeduckgo</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">msfew</figcaption></figure>]]></content:encoded>
            <author>apecoder@newsletter.paragraph.com (Web3dAppDevCamp)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/9cb5da88fe2456a589702ed1286542b7de436f147792069c1b1bcd03a106a1a6.png" length="0" type="image/png"/>
        </item>
    </channel>
</rss>