<?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>KevinWang</title>
        <link>https://paragraph.com/@kevin-wang</link>
        <description>undefined</description>
        <lastBuildDate>Thu, 16 Apr 2026 01:04:41 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <image>
            <title>KevinWang</title>
            <url>https://storage.googleapis.com/papyrus_images/fdbbc46fff0e8de56bbeb0bcc1b4c7f6b65752fc1f366aca3a93f7e25d84881e.png</url>
            <link>https://paragraph.com/@kevin-wang</link>
        </image>
        <copyright>All rights reserved</copyright>
        <item>
            <title><![CDATA[The Generation of Mnemonics]]></title>
            <link>https://paragraph.com/@kevin-wang/the-generation-of-mnemonics</link>
            <guid>D3fXuI4FN71L244MK7XP</guid>
            <pubDate>Sun, 14 Sep 2025 07:38:49 GMT</pubDate>
            <description><![CDATA[MnemonicWe know that in MetaMask, when you generate a new account, you will get a set of mnemonics. This article will explain the process of generating mnemonics. Let’s see the code first.function genMnemonic() { const randomWallet = ethers.Wallet.createRandom(); const mnemonic = randomWallet.mnemonic.phrase; console.log(mnemonic); return mnemonic; } static createRandom(provider?: null | Provider): HDNodeWallet { const wallet = HDNodeWallet.createRandom(); if (provider) { return wallet.connec...]]></description>
            <content:encoded><![CDATA[<h1 id="h-mnemonic" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Mnemonic</h1><p>We know that in MetaMask, when you generate a new account, you will get a set of mnemonics.</p><p>This article will explain the process of generating mnemonics.</p><p>Let’s see the code first.</p><pre data-type="codeBlock" text="function genMnemonic() {
    const randomWallet = ethers.Wallet.createRandom();
    const mnemonic = randomWallet.mnemonic.phrase;
    console.log(mnemonic);
    return mnemonic;
}

static createRandom(provider?: null | Provider): HDNodeWallet {
    const wallet = HDNodeWallet.createRandom();
    if (provider) { return wallet.connect(provider); }
    return wallet;
}

static createRandom(password?: string, path?: string, wordlist?: Wordlist): HDNodeWallet {
    if (password == null) { password = &quot;&quot;; }
    if (path == null) { path = defaultPath; }
    if (wordlist == null) { wordlist = LangEn.wordlist(); }
    const mnemonic = Mnemonic.fromEntropy(randomBytes(16), password, wordlist)
    return HDNodeWallet.#fromSeed(mnemonic.computeSeed(), mnemonic).derivePath(path);
 }
 
static fromEntropy(_entropy: BytesLike, password?: null | string, wordlist?: null | Wordlist): Mnemonic {
    const entropy = getBytes(_entropy, &quot;entropy&quot;);
    const phrase = entropyToMnemonic(entropy, wordlist);
    return new Mnemonic(_guard, hexlify(entropy), phrase, password, wordlist);
}

function entropyToMnemonic(entropy: Uint8Array, wordlist?: null | Wordlist): string {

    assertArgument((entropy.length % 4) === 0 &amp;&amp; entropy.length &gt;= 16 &amp;&amp; entropy.length &lt;= 32,
        &quot;invalid entropy size&quot;, &quot;entropy&quot;, &quot;[ REDACTED ]&quot;);

    if (wordlist == null) { wordlist = LangEn.wordlist(); }

    const indices: Array&lt;number&gt; = [ 0 ];

    let remainingBits = 11;
    for (let i = 0; i &lt; entropy.length; i++) {

        // Consume the whole byte (with still more to go)
        if (remainingBits &gt; 8) {
            indices[indices.length - 1] &lt;&lt;= 8;
            indices[indices.length - 1] |= entropy[i];

            remainingBits -= 8;

        // This byte will complete an 11-bit index
        } else {
            indices[indices.length - 1] &lt;&lt;= remainingBits;
            indices[indices.length - 1] |= entropy[i] &gt;&gt; (8 - remainingBits);

            // Start the next word
            indices.push(entropy[i] &amp; getLowerMask(8 - remainingBits));

            remainingBits += 3;
        }
    }

    // Compute the checksum bits
    const checksumBits = entropy.length / 4;
    const checksum = parseInt(sha256(entropy).substring(2, 4), 16) &amp; getUpperMask(checksumBits);

    // Shift the checksum into the word indices
    indices[indices.length - 1] &lt;&lt;= checksumBits;
    indices[indices.length - 1] |= (checksum &gt;&gt; (8 - checksumBits));

    return wordlist.join(indices.map((index) =&gt; (&lt;Wordlist&gt;wordlist).getWord(index)));
}
"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">genMnemonic</span>(<span class="hljs-params"></span>) </span>{
    const randomWallet <span class="hljs-operator">=</span> ethers.Wallet.createRandom();
    const mnemonic <span class="hljs-operator">=</span> randomWallet.mnemonic.phrase;
    console.log(mnemonic);
    <span class="hljs-keyword">return</span> mnemonic;
}

static createRandom(provider?: null <span class="hljs-operator">|</span> Provider): HDNodeWallet {
    const wallet <span class="hljs-operator">=</span> HDNodeWallet.createRandom();
    <span class="hljs-keyword">if</span> (provider) { <span class="hljs-keyword">return</span> wallet.connect(provider); }
    <span class="hljs-keyword">return</span> wallet;
}

static createRandom(password?: <span class="hljs-keyword">string</span>, path?: <span class="hljs-keyword">string</span>, wordlist?: Wordlist): HDNodeWallet {
    <span class="hljs-keyword">if</span> (password <span class="hljs-operator">=</span><span class="hljs-operator">=</span> null) { password <span class="hljs-operator">=</span> <span class="hljs-string">""</span>; }
    <span class="hljs-keyword">if</span> (path <span class="hljs-operator">=</span><span class="hljs-operator">=</span> null) { path <span class="hljs-operator">=</span> defaultPath; }
    <span class="hljs-keyword">if</span> (wordlist <span class="hljs-operator">=</span><span class="hljs-operator">=</span> null) { wordlist <span class="hljs-operator">=</span> LangEn.wordlist(); }
    const mnemonic <span class="hljs-operator">=</span> Mnemonic.fromEntropy(randomBytes(<span class="hljs-number">16</span>), password, wordlist)
    <span class="hljs-keyword">return</span> HDNodeWallet.#fromSeed(mnemonic.computeSeed(), mnemonic).derivePath(path);
 }
 
static fromEntropy(_entropy: BytesLike, password?: null <span class="hljs-operator">|</span> <span class="hljs-keyword">string</span>, wordlist?: null <span class="hljs-operator">|</span> Wordlist): Mnemonic {
    const entropy <span class="hljs-operator">=</span> getBytes(_entropy, <span class="hljs-string">"entropy"</span>);
    const phrase <span class="hljs-operator">=</span> entropyToMnemonic(entropy, wordlist);
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Mnemonic(_guard, hexlify(entropy), phrase, password, wordlist);
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">entropyToMnemonic</span>(<span class="hljs-params">entropy: Uint8Array, wordlist?: null | Wordlist</span>): <span class="hljs-title"><span class="hljs-keyword">string</span></span> </span>{

    assertArgument((entropy.<span class="hljs-built_in">length</span> <span class="hljs-operator">%</span> <span class="hljs-number">4</span>) <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">0</span> <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span> entropy.<span class="hljs-built_in">length</span> <span class="hljs-operator">></span><span class="hljs-operator">=</span> <span class="hljs-number">16</span> <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span> entropy.<span class="hljs-built_in">length</span> <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">=</span> <span class="hljs-number">32</span>,
        <span class="hljs-string">"invalid entropy size"</span>, <span class="hljs-string">"entropy"</span>, <span class="hljs-string">"[ REDACTED ]"</span>);

    <span class="hljs-keyword">if</span> (wordlist <span class="hljs-operator">=</span><span class="hljs-operator">=</span> null) { wordlist <span class="hljs-operator">=</span> LangEn.wordlist(); }

    const indices: Array<span class="hljs-operator">&#x3C;</span>number<span class="hljs-operator">></span> <span class="hljs-operator">=</span> [ <span class="hljs-number">0</span> ];

    let remainingBits <span class="hljs-operator">=</span> <span class="hljs-number">11</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> entropy.<span class="hljs-built_in">length</span>; i<span class="hljs-operator">+</span><span class="hljs-operator">+</span>) {

        <span class="hljs-comment">// Consume the whole byte (with still more to go)</span>
        <span class="hljs-keyword">if</span> (remainingBits <span class="hljs-operator">></span> <span class="hljs-number">8</span>) {
            indices[indices.<span class="hljs-built_in">length</span> <span class="hljs-operator">-</span> <span class="hljs-number">1</span>] <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">&#x3C;</span><span class="hljs-operator">=</span> <span class="hljs-number">8</span>;
            indices[indices.<span class="hljs-built_in">length</span> <span class="hljs-operator">-</span> <span class="hljs-number">1</span>] <span class="hljs-operator">|</span><span class="hljs-operator">=</span> entropy[i];

            remainingBits <span class="hljs-operator">-</span><span class="hljs-operator">=</span> <span class="hljs-number">8</span>;

        <span class="hljs-comment">// This byte will complete an 11-bit index</span>
        } <span class="hljs-keyword">else</span> {
            indices[indices.<span class="hljs-built_in">length</span> <span class="hljs-operator">-</span> <span class="hljs-number">1</span>] <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">&#x3C;</span><span class="hljs-operator">=</span> remainingBits;
            indices[indices.<span class="hljs-built_in">length</span> <span class="hljs-operator">-</span> <span class="hljs-number">1</span>] <span class="hljs-operator">|</span><span class="hljs-operator">=</span> entropy[i] <span class="hljs-operator">></span><span class="hljs-operator">></span> (<span class="hljs-number">8</span> <span class="hljs-operator">-</span> remainingBits);

            <span class="hljs-comment">// Start the next word</span>
            indices.<span class="hljs-built_in">push</span>(entropy[i] <span class="hljs-operator">&#x26;</span> getLowerMask(<span class="hljs-number">8</span> <span class="hljs-operator">-</span> remainingBits));

            remainingBits <span class="hljs-operator">+</span><span class="hljs-operator">=</span> <span class="hljs-number">3</span>;
        }
    }

    <span class="hljs-comment">// Compute the checksum bits</span>
    const checksumBits <span class="hljs-operator">=</span> entropy.<span class="hljs-built_in">length</span> <span class="hljs-operator">/</span> <span class="hljs-number">4</span>;
    const checksum <span class="hljs-operator">=</span> parseInt(<span class="hljs-built_in">sha256</span>(entropy).substring(<span class="hljs-number">2</span>, <span class="hljs-number">4</span>), <span class="hljs-number">16</span>) <span class="hljs-operator">&#x26;</span> getUpperMask(checksumBits);

    <span class="hljs-comment">// Shift the checksum into the word indices</span>
    indices[indices.<span class="hljs-built_in">length</span> <span class="hljs-operator">-</span> <span class="hljs-number">1</span>] <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">&#x3C;</span><span class="hljs-operator">=</span> checksumBits;
    indices[indices.<span class="hljs-built_in">length</span> <span class="hljs-operator">-</span> <span class="hljs-number">1</span>] <span class="hljs-operator">|</span><span class="hljs-operator">=</span> (checksum <span class="hljs-operator">></span><span class="hljs-operator">></span> (<span class="hljs-number">8</span> <span class="hljs-operator">-</span> checksumBits));

    <span class="hljs-keyword">return</span> wordlist.join(indices.map((index) <span class="hljs-operator">=</span><span class="hljs-operator">></span> (<span class="hljs-operator">&#x3C;</span>Wordlist<span class="hljs-operator">></span>wordlist).getWord(index)));
}
</code></pre><p>May be you will find the code is too long to understand. Let’s split it.</p><p>Before splitting. You should first know the basic steps of generating mnemonics</p><ol><li><p>generate random 16 bytes array</p></li><li><p>split 16 bytes array to 11 bits array</p></li><li><p>map every 11 bits data to a word</p></li></ol><h1 id="h-what-is-mnemonics" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">What is mnemonics</h1><p>Mnemonics is s a set of easy words to help user to remember their account.</p><p>There are 2048 words in all mnemonics datasource, and each account has 12/24 mnemonics.</p><p>So if we want to map a number to a mnemonics, this number should be a 11 bit data. Cause 11 bit data can get 2048 different numbers.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/fb46fd652dbe4834f3de3f776a638b6d8790030b53c1a61ac493ef38f1ba45c9.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><h1 id="h-generate-random-data" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Generate random data</h1><p>So, every mnemonic should be represented by 11 bits</p><p>The code use <code>randomBytes(16)</code> to generate a uint8array.</p><p>You will get 16 bytes, every bytes has 8 bit. So you will get totally 16 * 8 = 128 bits.</p><p>Well, now you can slip 128 bits to 11 * 11 bits. But we need 12 mnemonics, there are only 11 words.</p><p>We need 132 bits to split to 12 mnemonics(132 / 11 = 12). We need 4 more bits to fill it.</p><p>That’s the checksum, every 32 bits should have a bit of checksum.</p><h1 id="h-split-bytes" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Split bytes</h1><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/717178402484aac67cab4efbfda83fbcdc9c23e6ee649dbb10b66b65f90b5266.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>This picture explain how to change the random bytes into the list of mnemonics.</p><p>Actually the function <code>entropyToMnemonic</code> is the implemented code.</p><pre data-type="codeBlock" text="function entropyToMnemonic(entropy: Uint8Array, wordlist?: null | Wordlist): string {
    assertArgument((entropy.length % 4) === 0 &amp;&amp; entropy.length &gt;= 16 &amp;&amp; entropy.length &lt;= 32,
        &quot;invalid entropy size&quot;, &quot;entropy&quot;, &quot;[ REDACTED ]&quot;);

    if (wordlist == null) { wordlist = LangEn.wordlist(); }

    const indices: Array&lt;number&gt; = [ 0 ];
        // every mnemonic need 11 bits to map word
    let remainingBits = 11;
    for (let i = 0; i &lt; entropy.length; i++) {
        // 
        if (remainingBits &gt; 8) {
            indices[indices.length - 1] &lt;&lt;= 8;
            indices[indices.length - 1] |= entropy[i];

            remainingBits -= 8;

        // This byte will complete an 11-bit index
        } else {
            indices[indices.length - 1] &lt;&lt;= remainingBits;
            indices[indices.length - 1] |= entropy[i] &gt;&gt; (8 - remainingBits);

            // Start the next word
            indices.push(entropy[i] &amp; getLowerMask(8 - remainingBits));

            remainingBits += 3;
        }
    }

    // Compute the checksum bits
    const checksumBits = entropy.length / 4;
    const checksum = parseInt(sha256(entropy).substring(2, 4), 16) &amp; getUpperMask(checksumBits);

    // Shift the checksum into the word indices
    indices[indices.length - 1] &lt;&lt;= checksumBits;
    indices[indices.length - 1] |= (checksum &gt;&gt; (8 - checksumBits));

    return wordlist.join(indices.map((index) =&gt; (&lt;Wordlist&gt;wordlist).getWord(index)));
}
"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">entropyToMnemonic</span>(<span class="hljs-params">entropy: Uint8Array, wordlist?: null | Wordlist</span>): <span class="hljs-title"><span class="hljs-keyword">string</span></span> </span>{
    assertArgument((entropy.<span class="hljs-built_in">length</span> <span class="hljs-operator">%</span> <span class="hljs-number">4</span>) <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">0</span> <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span> entropy.<span class="hljs-built_in">length</span> <span class="hljs-operator">></span><span class="hljs-operator">=</span> <span class="hljs-number">16</span> <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span> entropy.<span class="hljs-built_in">length</span> <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">=</span> <span class="hljs-number">32</span>,
        <span class="hljs-string">"invalid entropy size"</span>, <span class="hljs-string">"entropy"</span>, <span class="hljs-string">"[ REDACTED ]"</span>);

    <span class="hljs-keyword">if</span> (wordlist <span class="hljs-operator">=</span><span class="hljs-operator">=</span> null) { wordlist <span class="hljs-operator">=</span> LangEn.wordlist(); }

    const indices: Array<span class="hljs-operator">&#x3C;</span>number<span class="hljs-operator">></span> <span class="hljs-operator">=</span> [ <span class="hljs-number">0</span> ];
        <span class="hljs-comment">// every mnemonic need 11 bits to map word</span>
    let remainingBits <span class="hljs-operator">=</span> <span class="hljs-number">11</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> entropy.<span class="hljs-built_in">length</span>; i<span class="hljs-operator">+</span><span class="hljs-operator">+</span>) {
        <span class="hljs-comment">// </span>
        <span class="hljs-keyword">if</span> (remainingBits <span class="hljs-operator">></span> <span class="hljs-number">8</span>) {
            indices[indices.<span class="hljs-built_in">length</span> <span class="hljs-operator">-</span> <span class="hljs-number">1</span>] <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">&#x3C;</span><span class="hljs-operator">=</span> <span class="hljs-number">8</span>;
            indices[indices.<span class="hljs-built_in">length</span> <span class="hljs-operator">-</span> <span class="hljs-number">1</span>] <span class="hljs-operator">|</span><span class="hljs-operator">=</span> entropy[i];

            remainingBits <span class="hljs-operator">-</span><span class="hljs-operator">=</span> <span class="hljs-number">8</span>;

        <span class="hljs-comment">// This byte will complete an 11-bit index</span>
        } <span class="hljs-keyword">else</span> {
            indices[indices.<span class="hljs-built_in">length</span> <span class="hljs-operator">-</span> <span class="hljs-number">1</span>] <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">&#x3C;</span><span class="hljs-operator">=</span> remainingBits;
            indices[indices.<span class="hljs-built_in">length</span> <span class="hljs-operator">-</span> <span class="hljs-number">1</span>] <span class="hljs-operator">|</span><span class="hljs-operator">=</span> entropy[i] <span class="hljs-operator">></span><span class="hljs-operator">></span> (<span class="hljs-number">8</span> <span class="hljs-operator">-</span> remainingBits);

            <span class="hljs-comment">// Start the next word</span>
            indices.<span class="hljs-built_in">push</span>(entropy[i] <span class="hljs-operator">&#x26;</span> getLowerMask(<span class="hljs-number">8</span> <span class="hljs-operator">-</span> remainingBits));

            remainingBits <span class="hljs-operator">+</span><span class="hljs-operator">=</span> <span class="hljs-number">3</span>;
        }
    }

    <span class="hljs-comment">// Compute the checksum bits</span>
    const checksumBits <span class="hljs-operator">=</span> entropy.<span class="hljs-built_in">length</span> <span class="hljs-operator">/</span> <span class="hljs-number">4</span>;
    const checksum <span class="hljs-operator">=</span> parseInt(<span class="hljs-built_in">sha256</span>(entropy).substring(<span class="hljs-number">2</span>, <span class="hljs-number">4</span>), <span class="hljs-number">16</span>) <span class="hljs-operator">&#x26;</span> getUpperMask(checksumBits);

    <span class="hljs-comment">// Shift the checksum into the word indices</span>
    indices[indices.<span class="hljs-built_in">length</span> <span class="hljs-operator">-</span> <span class="hljs-number">1</span>] <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">&#x3C;</span><span class="hljs-operator">=</span> checksumBits;
    indices[indices.<span class="hljs-built_in">length</span> <span class="hljs-operator">-</span> <span class="hljs-number">1</span>] <span class="hljs-operator">|</span><span class="hljs-operator">=</span> (checksum <span class="hljs-operator">></span><span class="hljs-operator">></span> (<span class="hljs-number">8</span> <span class="hljs-operator">-</span> checksumBits));

    <span class="hljs-keyword">return</span> wordlist.join(indices.map((index) <span class="hljs-operator">=</span><span class="hljs-operator">></span> (<span class="hljs-operator">&#x3C;</span>Wordlist<span class="hljs-operator">></span>wordlist).getWord(index)));
}
</code></pre><p><code>indices[indices.length - 1] &lt;&lt;= 8;</code> let the data left shift 8 bits to allow the next byte(8bit) to have a position to insert.</p><p><code>indices[indices.length - 1] |= entropy[i] &gt;&gt; (8 - remainingBits);</code> insert the remained bits of a byte.</p><p><code>remainingBits += 3;</code> seems confusing, we can derive this formula.</p><p><code>nextRemainingBits = 11 - (8 - lastRemainingBits)</code></p><p>So,</p><p><code>nextRemainingBits = 11 - 8 + lastRemainingBits = 3 + lastRemainingBits</code></p><h1 id="h-checksum" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">CheckSum</h1><p><code>indices[indices.length - 1] &lt;&lt;= checksumBits; indices[indices.length - 1] |= (checksum &gt;&gt; (8 - checksumBits));</code></p><p>Finally, when the <code>randomBytes</code> has been split, there are still 4 bits(16/4) need to fill.</p><p>It is filled by the high 4 bits of checksum.</p><p>Checksum just need the first 8 bits of <code>sha256(entropy)</code>.</p><p><code>sha256(entropy).substring(2, 4)</code> may be confusing. Actually sha256 return a string like this “0x1a2b3c”, we need to exclude 0x, so we need the substring(2,4).</p><p>And then, we will get the high <code>CheckSumbits</code> of <code>Checksum</code>, then add it into the low <code>CheckSumBits</code> bit of finally mnemonic</p>]]></content:encoded>
            <author>kevin-wang@newsletter.paragraph.com (KevinWang)</author>
        </item>
        <item>
            <title><![CDATA[What is ERC721:Section 1]]></title>
            <link>https://paragraph.com/@kevin-wang/what-is-erc721-section-1</link>
            <guid>6enh09KDs1FChZra8LxC</guid>
            <pubDate>Sat, 06 Sep 2025 12:40:42 GMT</pubDate>
            <description><![CDATA[What is ERC-721.Actually you can simply understand the ERC-721 is NFT. This is the link of EIP-721.https://eips.ethereum.org/EIPS/eip-721 Official explanation of ERC-721 is “Non-Fungible Token”, which means every token is specially. That means you can use NFT to represent unique image, stock, or even real estate.Practical ApplicationYou can find plenty of tutorial of ERC-721. And this blog will show you the practical application. Fist of all, let’s see the solidity code of a contract which im...]]></description>
            <content:encoded><![CDATA[<h1 id="h-what-is-erc-721" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">What is ERC-721.</h1><p>Actually you can simply understand the ERC-721 is NFT.</p><p>This is the link of EIP-721.<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://eips.ethereum.org/EIPS/eip-721?utm_source=chatgpt.com">https://eips.ethereum.org/EIPS/eip-721</a></p><p>Official explanation of ERC-721 is “Non-Fungible Token”, which means every token is specially. That means you can use NFT to represent unique image, stock, or even real estate.</p><h1 id="h-practical-application" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Practical Application</h1><p>You can find plenty of tutorial of ERC-721. And this blog will show you the practical application.</p><p>Fist of all, let’s see the solidity code of a contract which implemented the ERC-721 protocol.</p><pre data-type="codeBlock" text="// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {ERC721URIStorage, ERC721} from &quot;@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol&quot;;

contract Merkamigos is ERC721URIStorage {
    uint256 private _nextTokenId;

    constructor() ERC721(&quot;Merkamigos&quot;, &quot;MKG&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.20;</span>

<span class="hljs-keyword">import</span> {<span class="hljs-title">ERC721URIStorage</span>, <span class="hljs-title">ERC721</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Merkamigos</span> <span class="hljs-keyword">is</span> <span class="hljs-title">ERC721URIStorage</span> </span>{
    <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">private</span> _nextTokenId;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>) <span class="hljs-title">ERC721</span>(<span class="hljs-params"><span class="hljs-string">"Merkamigos"</span>, <span class="hljs-string">"MKG"</span></span>) </span>{}
}
</code></pre><p>It’s very easy to implement the ERC-721 by inheriting the ERC721URIStorage, but we want to find out what is happening in it.</p><p>Let’s see the constructor first.</p><h1 id="h-constructor" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">constructor()</h1><p>When the contract was deployed, the constructor() would be executed.</p><p>And you may confuse of the grammar.</p><p>In solidity, if a contract inherit from the parent contract, and it’s parent contract has a constructor function with parameters, it is necessary to call the parent contract constructor within the child contract constructor and provide parameters.</p><pre data-type="codeBlock" text="constructor() ERC721(&quot;Merkamigos&quot;, &quot;MKG&quot;) {}
"><code><span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>) <span class="hljs-title">ERC721</span>(<span class="hljs-params"><span class="hljs-string">"Merkamigos"</span>, <span class="hljs-string">"MKG"</span></span>) </span>{}
</code></pre><p>Now let’s see the constructor() of it’s father contract.</p><pre data-type="codeBlock" text="abstract contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Errors {
    using Strings for uint256;

    // Token name
    string private _name;

    // Token symbol
    string private _symbol;

    /**
     * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /// @inheritdoc IERC721Metadata
    function name() public view virtual returns (string memory) {
        return _name;
    }

    /// @inheritdoc IERC721Metadata
    function symbol() public view virtual returns (string memory) {
        return _symbol;
    }
    
     /**
     * ......
     */
}
"><code><span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">ERC721</span> <span class="hljs-keyword">is</span> <span class="hljs-title">Context</span>, <span class="hljs-title">ERC165</span>, <span class="hljs-title">IERC721</span>, <span class="hljs-title">IERC721Metadata</span>, <span class="hljs-title">IERC721Errors</span> </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">// Token name</span>
    <span class="hljs-keyword">string</span> <span class="hljs-keyword">private</span> _name;

    <span class="hljs-comment">// Token symbol</span>
    <span class="hljs-keyword">string</span> <span class="hljs-keyword">private</span> _symbol;

    <span class="hljs-comment">/**
     * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span> name_, <span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span> symbol_</span>) </span>{
        _name <span class="hljs-operator">=</span> name_;
        _symbol <span class="hljs-operator">=</span> symbol_;
    }

    <span class="hljs-comment">/// @inheritdoc IERC721Metadata</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">name</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">virtual</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">return</span> _name;
    }

    <span class="hljs-comment">/// @inheritdoc IERC721Metadata</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">symbol</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">virtual</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">return</span> _symbol;
    }
    
     <span class="hljs-comment">/**
     * ......
     */</span>
}
</code></pre><p>We can find the private parameters: _name and _symbol.</p><p>_name is the name of NTF and _symbol is the symbol of NTF.</p><p>In OpenSea, you can find all NTF have the name and symbol, it is achieved by these two parameters’s getter function, name() and symbol().</p><p>And our example contract is named as ‘Merkamigos’ and symboled as ‘MKG’.</p><h1 id="h-public-functions" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Public functions</h1><p>We find that there is no other function of parameter in our example contract. It is caused by</p><p>father contract-ERC721URIStorage and ERC-721.</p><p>We can explicitly find the public function on REMIX.</p><p>!image.png</p><h1 id="h-approve" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">approve</h1><pre data-type="codeBlock" text="abstract contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Errors {		
        /// @inheritdoc IERC721
    function approve(address to, uint256 tokenId) public virtual {
        _approve(to, tokenId, _msgSender());
    }
        /**
     * @dev Approve `to` to operate on `tokenId`
     *
     * The `auth` argument is optional. If the value passed is non 0, then this function will check that `auth` is
     * either the owner of the token, or approved to operate on all tokens held by this owner.
     *
     * Emits an {Approval} event.
     *
     * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
     */
    function _approve(address to, uint256 tokenId, address auth) internal {
        _approve(to, tokenId, auth, true);
    }

    /**
     * @dev Variant of `_approve` with an optional flag to enable or disable the {Approval} event. The event is not
     * emitted in the context of transfers.
     */
    function _approve(address to, uint256 tokenId, address auth, bool emitEvent) internal virtual {
        // Avoid reading the owner unless necessary
        if (emitEvent || auth != address(0)) {
            address owner = _requireOwned(tokenId);

            // We do not use _isAuthorized because single-token approvals should not be able to call approve
            if (auth != address(0) &amp;&amp; owner != auth &amp;&amp; !isApprovedForAll(owner, auth)) {
                revert ERC721InvalidApprover(auth);
            }

            if (emitEvent) {
                emit Approval(owner, to, tokenId);
            }
        }

        _tokenApprovals[tokenId] = to;
    }
}
"><code><span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">ERC721</span> <span class="hljs-keyword">is</span> <span class="hljs-title">Context</span>, <span class="hljs-title">ERC165</span>, <span class="hljs-title">IERC721</span>, <span class="hljs-title">IERC721Metadata</span>, <span class="hljs-title">IERC721Errors</span> </span>{		
        <span class="hljs-comment">/// @inheritdoc IERC721</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> to, <span class="hljs-keyword">uint256</span> tokenId</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">virtual</span></span> </span>{
        _approve(to, tokenId, _msgSender());
    }
        <span class="hljs-comment">/**
     * @dev Approve `to` to operate on `tokenId`
     *
     * The `auth` argument is optional. If the value passed is non 0, then this function will check that `auth` is
     * either the owner of the token, or approved to operate on all tokens held by this owner.
     *
     * Emits an {Approval} event.
     *
     * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
     */</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> to, <span class="hljs-keyword">uint256</span> tokenId, <span class="hljs-keyword">address</span> auth</span>) <span class="hljs-title"><span class="hljs-keyword">internal</span></span> </span>{
        _approve(to, tokenId, auth, <span class="hljs-literal">true</span>);
    }

    <span class="hljs-comment">/**
     * @dev Variant of `_approve` with an optional flag to enable or disable the {Approval} event. The event is not
     * emitted in the context of transfers.
     */</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> to, <span class="hljs-keyword">uint256</span> tokenId, <span class="hljs-keyword">address</span> auth, <span class="hljs-keyword">bool</span> emitEvent</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-comment">// Avoid reading the owner unless necessary</span>
        <span class="hljs-keyword">if</span> (emitEvent <span class="hljs-operator">|</span><span class="hljs-operator">|</span> auth <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">address</span> owner <span class="hljs-operator">=</span> _requireOwned(tokenId);

            <span class="hljs-comment">// We do not use _isAuthorized because single-token approvals should not be able to call approve</span>
            <span class="hljs-keyword">if</span> (auth <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-operator">&#x26;</span><span class="hljs-operator">&#x26;</span> owner <span class="hljs-operator">!</span><span class="hljs-operator">=</span> auth <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span> <span class="hljs-operator">!</span>isApprovedForAll(owner, auth)) {
                <span class="hljs-keyword">revert</span> ERC721InvalidApprover(auth);
            }

            <span class="hljs-keyword">if</span> (emitEvent) {
                <span class="hljs-keyword">emit</span> Approval(owner, to, tokenId);
            }
        }

        _tokenApprovals[tokenId] <span class="hljs-operator">=</span> to;
    }
}
</code></pre><p>The caller can use <code>approve()</code> to specify another address to own the auth of controlling the token. <code>_tokenApprovals</code> records the mapping of tokenId to approvals. Notice that there is only an address can be approved to a token.</p><h1 id="h-safetransferfrom" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">SafeTransferFrom</h1><pre data-type="codeBlock" text="
abstract contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Errors {		
        /// @inheritdoc IERC721
    function safeTransferFrom(address from, address to, uint256 tokenId) public {
        safeTransferFrom(from, to, tokenId, &quot;&quot;);
    }

    /// @inheritdoc IERC721
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public virtual {
        transferFrom(from, to, tokenId);
        ERC721Utils.checkOnERC721Received(_msgSender(), from, to, tokenId, data);
    }
}
"><code>
<span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">ERC721</span> <span class="hljs-keyword">is</span> <span class="hljs-title">Context</span>, <span class="hljs-title">ERC165</span>, <span class="hljs-title">IERC721</span>, <span class="hljs-title">IERC721Metadata</span>, <span class="hljs-title">IERC721Errors</span> </span>{		
        <span class="hljs-comment">/// @inheritdoc IERC721</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">safeTransferFrom</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> tokenId</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        safeTransferFrom(<span class="hljs-keyword">from</span>, to, tokenId, <span class="hljs-string">""</span>);
    }

    <span class="hljs-comment">/// @inheritdoc IERC721</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">safeTransferFrom</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> tokenId, <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">memory</span> data</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">virtual</span></span> </span>{
        transferFrom(<span class="hljs-keyword">from</span>, to, tokenId);
        ERC721Utils.checkOnERC721Received(_msgSender(), <span class="hljs-keyword">from</span>, to, tokenId, data);
    }
}
</code></pre><p>The safeTransferFrom apply four parameters.</p><p>In the safeTransferFrom function, it calls transferFrom first.</p><pre data-type="codeBlock" text="/// @inheritdoc IERC721
    function transferFrom(address from, address to, uint256 tokenId) public virtual {
        if (to == address(0)) {
            revert ERC721InvalidReceiver(address(0));
        }
        // Setting an &quot;auth&quot; arguments enables the `_isAuthorized` check which verifies that the token exists
        // (from != 0). Therefore, it is not needed to verify that the return value is not 0 here.
        address previousOwner = _update(to, tokenId, _msgSender());
        if (previousOwner != from) {
            revert ERC721IncorrectOwner(from, tokenId, previousOwner);
        }
    }
    
    function _update(address to, uint256 tokenId, address auth) internal virtual returns (address) {
        address from = _ownerOf(tokenId);

        // Perform (optional) operator check
        if (auth != address(0)) {
            _checkAuthorized(from, auth, tokenId);
        }

        // Execute the update
        if (from != address(0)) {
            // Clear approval. No need to re-authorize or emit the Approval event
            _approve(address(0), tokenId, address(0), false);

            unchecked {
                _balances[from] -= 1;
            }
        }

        if (to != address(0)) {
            unchecked {
                _balances[to] += 1;
            }
        }

        _owners[tokenId] = to;

        emit Transfer(from, to, tokenId);

        return from;
    }
    
    function _checkAuthorized(address owner, address spender, uint256 tokenId) internal view virtual {
        if (!_isAuthorized(owner, spender, tokenId)) {
            if (owner == address(0)) {
                revert ERC721NonexistentToken(tokenId);
            } else {
                revert ERC721InsufficientApproval(spender, tokenId);
            }
        }
    }
    
    /**
     * @dev Returns whether `spender` is allowed to manage `owner`&apos;s tokens, or `tokenId` in
     * particular (ignoring whether it is owned by `owner`).
     *
     * WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this
     * assumption.
     */
    function _isAuthorized(address owner, address spender, uint256 tokenId) internal view virtual returns (bool) {
        return
            spender != address(0) &amp;&amp;
            (owner == spender || isApprovedForAll(owner, spender) || _getApproved(tokenId) == spender);
    }
"><code><span class="hljs-comment">/// @inheritdoc IERC721</span>
    <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> tokenId</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">virtual</span></span> </span>{
        <span class="hljs-keyword">if</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-keyword">revert</span> ERC721InvalidReceiver(<span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>));
        }
        <span class="hljs-comment">// Setting an "auth" arguments enables the `_isAuthorized` check which verifies that the token exists</span>
        <span class="hljs-comment">// (from != 0). Therefore, it is not needed to verify that the return value is not 0 here.</span>
        <span class="hljs-keyword">address</span> previousOwner <span class="hljs-operator">=</span> _update(to, tokenId, _msgSender());
        <span class="hljs-keyword">if</span> (previousOwner <span class="hljs-operator">!</span><span class="hljs-operator">=</span> <span class="hljs-keyword">from</span>) {
            <span class="hljs-keyword">revert</span> ERC721IncorrectOwner(<span class="hljs-keyword">from</span>, tokenId, previousOwner);
        }
    }
    
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_update</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> to, <span class="hljs-keyword">uint256</span> tokenId, <span class="hljs-keyword">address</span> auth</span>) <span class="hljs-title"><span class="hljs-keyword">internal</span></span> <span class="hljs-title"><span class="hljs-keyword">virtual</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">address</span> <span class="hljs-keyword">from</span> <span class="hljs-operator">=</span> _ownerOf(tokenId);

        <span class="hljs-comment">// Perform (optional) operator check</span>
        <span class="hljs-keyword">if</span> (auth <span class="hljs-operator">!</span><span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>)) {
            _checkAuthorized(<span class="hljs-keyword">from</span>, auth, tokenId);
        }

        <span class="hljs-comment">// Execute the update</span>
        <span class="hljs-keyword">if</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-comment">// Clear approval. No need to re-authorize or emit the Approval event</span>
            _approve(<span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>), tokenId, <span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>), <span class="hljs-literal">false</span>);

            <span class="hljs-keyword">unchecked</span> {
                _balances[<span class="hljs-keyword">from</span>] <span class="hljs-operator">-</span><span class="hljs-operator">=</span> <span class="hljs-number">1</span>;
            }
        }

        <span class="hljs-keyword">if</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-keyword">unchecked</span> {
                _balances[to] <span class="hljs-operator">+</span><span class="hljs-operator">=</span> <span class="hljs-number">1</span>;
            }
        }

        _owners[tokenId] <span class="hljs-operator">=</span> to;

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

        <span class="hljs-keyword">return</span> <span class="hljs-keyword">from</span>;
    }
    
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_checkAuthorized</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> tokenId</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">virtual</span></span> </span>{
        <span class="hljs-keyword">if</span> (<span class="hljs-operator">!</span>_isAuthorized(owner, spender, tokenId)) {
            <span class="hljs-keyword">if</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-keyword">revert</span> ERC721NonexistentToken(tokenId);
            } <span class="hljs-keyword">else</span> {
                <span class="hljs-keyword">revert</span> ERC721InsufficientApproval(spender, tokenId);
            }
        }
    }
    
    <span class="hljs-comment">/**
     * @dev Returns whether `spender` is allowed to manage `owner`'s tokens, or `tokenId` in
     * particular (ignoring whether it is owned by `owner`).
     *
     * WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this
     * assumption.
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_isAuthorized</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> tokenId</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">virtual</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>
            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-operator">&#x26;</span><span class="hljs-operator">&#x26;</span>
            (owner <span class="hljs-operator">=</span><span class="hljs-operator">=</span> spender <span class="hljs-operator">|</span><span class="hljs-operator">|</span> isApprovedForAll(owner, spender) <span class="hljs-operator">|</span><span class="hljs-operator">|</span> _getApproved(tokenId) <span class="hljs-operator">=</span><span class="hljs-operator">=</span> spender);
    }
</code></pre><p>In transferFrom, it first checks if the to address is 0.</p><p>Then it calls <code>update()</code> to check if the caller has auth to control the NTF.</p><p>In <code>_checkAuthorized()</code> , the function check if the caller is the owner of NTF, or if the caller has been approved by the owner of NFT.</p><p>Then it calls <code>_approve(address(0), tokenId, address(0), false);</code> to clear the approve of the NFT. Because when the NTF has been transferred, the old approvers should be cleared to avoid old approvers can still control the NFT without the permission from new owner.</p><p>Then, it add 1 on the new owner’s balance, and reduce 1 on the old owner’s balance. Then it declares the NTF’s owner has been changed.</p><p>Finally, it calls <code>ERC721Utils.checkOnERC721Received</code> to check if the to address can accept the NFT. Notion that only the contract address should be checked.</p><pre data-type="codeBlock" text="if (to.code.length &gt; 0) {
            try IERC721Receiver(to).onERC721Received(operator, from, tokenId, data) returns (bytes4 retval) {
                if (retval != IERC721Receiver.onERC721Received.selector) {
                    // Token rejected
                    revert IERC721Errors.ERC721InvalidReceiver(to);
                }
            } catch (bytes memory reason) {
                if (reason.length == 0) {
                    // non-IERC721Receiver implementer
                    revert IERC721Errors.ERC721InvalidReceiver(to);
                } else {
                    assembly (&quot;memory-safe&quot;) {
                        revert(add(reason, 0x20), mload(reason))
                    }
                }
            }
        }
"><code><span class="hljs-keyword">if</span> (to.<span class="hljs-built_in">code</span>.<span class="hljs-built_in">length</span> <span class="hljs-operator">></span> <span class="hljs-number">0</span>) {
            <span class="hljs-keyword">try</span> IERC721Receiver(to).onERC721Received(operator, <span class="hljs-keyword">from</span>, tokenId, data) <span class="hljs-keyword">returns</span> (<span class="hljs-keyword">bytes4</span> retval) {
                <span class="hljs-keyword">if</span> (retval <span class="hljs-operator">!</span><span class="hljs-operator">=</span> IERC721Receiver.onERC721Received.<span class="hljs-built_in">selector</span>) {
                    <span class="hljs-comment">// Token rejected</span>
                    <span class="hljs-keyword">revert</span> IERC721Errors.ERC721InvalidReceiver(to);
                }
            } <span class="hljs-keyword">catch</span> (<span class="hljs-keyword">bytes</span> <span class="hljs-keyword">memory</span> reason) {
                <span class="hljs-keyword">if</span> (reason.<span class="hljs-built_in">length</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">0</span>) {
                    <span class="hljs-comment">// non-IERC721Receiver implementer</span>
                    <span class="hljs-keyword">revert</span> IERC721Errors.ERC721InvalidReceiver(to);
                } <span class="hljs-keyword">else</span> {
                    <span class="hljs-keyword">assembly</span> (<span class="hljs-meta-string">"memory-safe"</span>) {
                        <span class="hljs-keyword">revert</span>(<span class="hljs-built_in">add</span>(reason, <span class="hljs-number">0x20</span>), <span class="hljs-built_in">mload</span>(reason))
                    }
                }
            }
        }
</code></pre><p>Every contract which can receive NFT should achieve <code>onERC721Received</code> function and return the specific data- <code>bytes4(keccak256(&quot;onERC721Received(address,address,uint256,bytes)&quot;));</code></p><p>If the contract does not achieve the function, it will throw an error.</p><h1 id="h-setapprovalforall" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">setApprovalForAll</h1><pre data-type="codeBlock" text="/// @inheritdoc IERC721
    function setApprovalForAll(address operator, bool approved) public virtual {
        _setApprovalForAll(_msgSender(), operator, approved);
    }
    
    /**
     * @dev Approve `operator` to operate on all of `owner` tokens
     *
     * Requirements:
     * - operator can&apos;t be the address zero.
     *
     * Emits an {ApprovalForAll} event.
     */
    function _setApprovalForAll(address owner, address operator, bool approved) internal virtual {
        if (operator == address(0)) {
            revert ERC721InvalidOperator(operator);
        }
        _operatorApprovals[owner][operator] = approved;
        emit ApprovalForAll(owner, operator, approved);
    }
"><code><span class="hljs-comment">/// @inheritdoc IERC721</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setApprovalForAll</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> operator, <span class="hljs-keyword">bool</span> approved</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">virtual</span></span> </span>{
        _setApprovalForAll(_msgSender(), operator, approved);
    }
    
    <span class="hljs-comment">/**
     * @dev Approve `operator` to operate on all of `owner` tokens
     *
     * Requirements:
     * - operator can't be the address zero.
     *
     * Emits an {ApprovalForAll} event.
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_setApprovalForAll</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> owner, <span class="hljs-keyword">address</span> operator, <span class="hljs-keyword">bool</span> approved</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">if</span> (operator <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">revert</span> ERC721InvalidOperator(operator);
        }
        _operatorApprovals[owner][operator] <span class="hljs-operator">=</span> approved;
        <span class="hljs-keyword">emit</span> ApprovalForAll(owner, operator, approved);
    }
</code></pre><p>When some address x calls the setApprovalForAll, it can specify an address to control all NFTs of the owner address x.</p><p>This function do not need to check the ownership cause the owner is the caller, the caller do not have the motivation to attack itself.</p><h1 id="h-summary" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Summary</h1><p>In this article, we introduce all state-changing ****function in ERC-721.</p><p>We will introduce the view/pure function in ERC-721 in next article.</p>]]></content:encoded>
            <author>kevin-wang@newsletter.paragraph.com (KevinWang)</author>
        </item>
        <item>
            <title><![CDATA[Gas Optimization Tips]]></title>
            <link>https://paragraph.com/@kevin-wang/gas-optimization-tips</link>
            <guid>bds41B7WGN4w4gTuygaK</guid>
            <pubDate>Sat, 30 Aug 2025 09:53:29 GMT</pubDate>
            <description><![CDATA[In Ethereum, the execution of contract will cost gas fee. An excellent contract should cost gas fee as low as possible. In this article, I will summary some gas optimization tips.1 Storage OptimizationIn Ethereum, storage data is written in contract account, which will cost the most gas fee.1.1 Reduce writing storage dataWe can use memory to storage middle data, instead of always writing storage data.uint256 a = storageVar; // read storage a += 10; // memory operation storageVar = a; // write...]]></description>
            <content:encoded><![CDATA[<p>In Ethereum, the execution of contract will cost gas fee. An excellent contract should cost gas fee as low as possible.</p><p>In this article, I will summary some gas optimization tips.</p><h1 id="h-1-storage-optimization" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">1 Storage Optimization</h1><p>In Ethereum, storage data is written in contract account, which will cost the most gas fee.</p><h2 id="h-11-reduce-writing-storage-data" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">1.1 Reduce writing storage data</h2><p>We can use memory to storage middle data, instead of always writing storage data.</p><pre data-type="codeBlock" text="uint256 a = storageVar;  // read storage
a += 10;                  // memory operation
storageVar = a;           // write storage
"><code><span class="hljs-keyword">uint256</span> a <span class="hljs-operator">=</span> storageVar;  <span class="hljs-comment">// read storage</span>
a <span class="hljs-operator">+</span><span class="hljs-operator">=</span> <span class="hljs-number">10</span>;                  <span class="hljs-comment">// memory operation</span>
storageVar <span class="hljs-operator">=</span> a;           <span class="hljs-comment">// write storage</span>
</code></pre><h2 id="h-12-merge-variable" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">1.2 Merge Variable</h2><p>Solidity aligns storage slots on 32-byte boundaries, multiple uint8 or bool values can be packed into the same slot.</p><pre data-type="codeBlock" text="struct Packed {
    uint128 a;
    uint128 b;
}
"><code><span class="hljs-keyword">struct</span> <span class="hljs-title">Packed</span> {
    <span class="hljs-keyword">uint128</span> a;
    <span class="hljs-keyword">uint128</span> b;
}
</code></pre><h2 id="h-13-use-memory-instead-of-storage" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">1.3 Use memory instead of Storage</h2><p>Use memory instead of Storage except the storage variable is necessary.</p><h1 id="h-2-for-each-optimization" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">2 For-each Optimization</h1><p>Use mapping instead of for-each searching array.</p><p>Mapping does not occupy continuous storage space, and read/write operations are relatively inexpensive.</p><h1 id="h-3-function-call-optimization" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">3 Function call Optimization</h1><h2 id="h-31-short-circuit" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">3.1 Short circuit</h2><p>If there are other judgment conditions before function call, we can prioritize judgment of prerequisite conditions.</p><pre data-type="codeBlock" text="if (a &gt; 10 &amp;&amp; expensiveCheck()) { ... }
"><code><span class="hljs-keyword">if</span> (a <span class="hljs-operator">></span> <span class="hljs-number">10</span> <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span> expensiveCheck()) { ... }
</code></pre><h2 id="h-32-function-modifier" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">3.2 Function modifier</h2><p><code>External</code> is cheaper than <code>Public</code>.</p><p><code>Pure</code> and <code>View</code> not cost gas fee.</p><h1 id="h-4-data-type-optimization" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">4 Data type Optimization</h1><p>Use minimum sufficient data type. Like <code>uint8</code>, <code>uint16</code> are more storage space-efficient than <code>uint256</code>.</p><h1 id="h-5-event-optimization" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">5 Event Optimization</h1><h2 id="h-51-index" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">5.1 Index</h2><p>Use as little as possible indexed parameter.</p><p>Index will cost more gas fee.</p><h2 id="h-52-emit" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">5.2 Emit</h2><p>Avoid frequent <code>emit</code> large events</p><h1 id="h-6-contract-structure-optimization" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">6 Contract Structure Optimization</h1><h2 id="h-61-use-contract-library" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">6.1 Use contract library</h2><h2 id="h-62-inheritance-chain-flattening" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">6.2 Inheritance chain flattening</h2><p>Multi-level inheritance will increase deployment Gas.</p><h1 id="h-7-bytes-and-array" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">7 Bytes And Array</h1><h2 id="h-71-bytes-is-more-efficient-than-string" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">7.1 Bytes is more efficient than string</h2><h2 id="h-72-swap-and-pop" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">7.2 Swap And Pop</h2><p>Use swap-and-pop instead of dynamic deletion.</p><p>But this way will disorder the sequence.</p><pre data-type="codeBlock" text="function remove(uint index) public {
    arr[index] = arr[arr.length - 1];
    arr.pop();
}
"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">remove</span>(<span class="hljs-params"><span class="hljs-keyword">uint</span> index</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
    arr[index] <span class="hljs-operator">=</span> arr[arr.<span class="hljs-built_in">length</span> <span class="hljs-operator">-</span> <span class="hljs-number">1</span>];
    arr.<span class="hljs-built_in">pop</span>();
}
</code></pre><h1 id="h-8-unchecked" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">8 Unchecked</h1><p>Using <code>unchecked</code> to skip overflow checking can save gas fee.</p><pre data-type="codeBlock" text="unchecked { i++; }
"><code><span class="hljs-keyword">unchecked</span> { i<span class="hljs-operator">+</span><span class="hljs-operator">+</span>; }
</code></pre>]]></content:encoded>
            <author>kevin-wang@newsletter.paragraph.com (KevinWang)</author>
        </item>
        <item>
            <title><![CDATA[Learning from crypto zombies lesson 2]]></title>
            <link>https://paragraph.com/@kevin-wang/learning-from-crypto-zombies-lesson-2</link>
            <guid>TqVihSKFaxGlXkqtkUmk</guid>
            <pubDate>Sat, 30 Aug 2025 06:25:52 GMT</pubDate>
            <description><![CDATA[Hi all, this is my second crypto zombies lesson homework! https://share.cryptozombies.io/zh/lesson/2/share/kevin?id=Y3p8NjIzMTk2 In this section, I will show my new contract and the knowledge behind the code.pragma solidity ^0.4.19; contract ZombieFactory { event NewZombie(uint zombieId, string name, uint dna); uint dnaDigits = 16; uint dnaModulus = 10 ** dnaDigits; struct Zombie { string name; uint dna; } Zombie[] public zombies; mapping (uint => address) public zombieToOwner; mapping (addre...]]></description>
            <content:encoded><![CDATA[<p>Hi all, this is my second crypto zombies lesson homework!</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://share.cryptozombies.io/zh/lesson/2/share/kevin?id=Y3p8NjIzMTk2">https://share.cryptozombies.io/zh/lesson/2/share/kevin?id=Y3p8NjIzMTk2</a></p><p>In this section, I will show my new contract and the knowledge behind the code.</p><pre data-type="codeBlock" text="pragma solidity ^0.4.19;

contract ZombieFactory {

    event NewZombie(uint zombieId, string name, uint dna);

    uint dnaDigits = 16;
    uint dnaModulus = 10 ** dnaDigits;

    struct Zombie {
        string name;
        uint dna;
    }

    Zombie[] public zombies;

    mapping (uint =&gt; address) public zombieToOwner;
    mapping (address =&gt; uint) ownerZombieCount;

    function _createZombie(string _name, uint _dna) internal {
        uint id = zombies.push(Zombie(_name, _dna)) - 1;
        zombieToOwner[id] = msg.sender;
        ownerZombieCount[msg.sender]++;
        NewZombie(id, _name, _dna);
    }

    function _generateRandomDna(string _str) private view returns (uint) {
        uint rand = uint(keccak256(_str));
        return rand % dnaModulus;
    }

    function createRandomZombie(string _name) public {
        require(ownerZombieCount[msg.sender] == 0);
        uint randDna = _generateRandomDna(_name);
        randDna = randDna - randDna % 100;
        _createZombie(_name, randDna);
    }

}
"><code><span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.4.19;</span>

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

    <span class="hljs-function"><span class="hljs-keyword">event</span> <span class="hljs-title">NewZombie</span>(<span class="hljs-params"><span class="hljs-keyword">uint</span> zombieId, <span class="hljs-keyword">string</span> name, <span class="hljs-keyword">uint</span> dna</span>)</span>;

    <span class="hljs-keyword">uint</span> dnaDigits <span class="hljs-operator">=</span> <span class="hljs-number">16</span>;
    <span class="hljs-keyword">uint</span> dnaModulus <span class="hljs-operator">=</span> <span class="hljs-number">10</span> <span class="hljs-operator">*</span><span class="hljs-operator">*</span> dnaDigits;

    <span class="hljs-keyword">struct</span> <span class="hljs-title">Zombie</span> {
        <span class="hljs-keyword">string</span> name;
        <span class="hljs-keyword">uint</span> dna;
    }

    Zombie[] <span class="hljs-keyword">public</span> zombies;

    <span class="hljs-keyword">mapping</span> (<span class="hljs-keyword">uint</span> <span class="hljs-operator">=</span><span class="hljs-operator">></span> <span class="hljs-keyword">address</span>) <span class="hljs-keyword">public</span> zombieToOwner;
    <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">uint</span>) ownerZombieCount;

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_createZombie</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> _name, <span class="hljs-keyword">uint</span> _dna</span>) <span class="hljs-title"><span class="hljs-keyword">internal</span></span> </span>{
        <span class="hljs-keyword">uint</span> id <span class="hljs-operator">=</span> zombies.<span class="hljs-built_in">push</span>(Zombie(_name, _dna)) <span class="hljs-operator">-</span> <span class="hljs-number">1</span>;
        zombieToOwner[id] <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>;
        ownerZombieCount[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>]<span class="hljs-operator">+</span><span class="hljs-operator">+</span>;
        NewZombie(id, _name, _dna);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_generateRandomDna</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> _str</span>) <span class="hljs-title"><span class="hljs-keyword">private</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">uint</span></span>) </span>{
        <span class="hljs-keyword">uint</span> rand <span class="hljs-operator">=</span> <span class="hljs-keyword">uint</span>(<span class="hljs-built_in">keccak256</span>(_str));
        <span class="hljs-keyword">return</span> rand <span class="hljs-operator">%</span> dnaModulus;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createRandomZombie</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> _name</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        <span class="hljs-built_in">require</span>(ownerZombieCount[<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-number">0</span>);
        <span class="hljs-keyword">uint</span> randDna <span class="hljs-operator">=</span> _generateRandomDna(_name);
        randDna <span class="hljs-operator">=</span> randDna <span class="hljs-operator">-</span> randDna <span class="hljs-operator">%</span> <span class="hljs-number">100</span>;
        _createZombie(_name, randDna);
    }

}
</code></pre><pre data-type="codeBlock" text="pragma solidity ^0.4.19;
import &quot;./zombiefactory.sol&quot;;
contract KittyInterface {
  function getKitty(uint256 _id) external view returns (
    bool isGestating,
    bool isReady,
    uint256 cooldownIndex,
    uint256 nextActionAt,
    uint256 siringWithId,
    uint256 birthTime,
    uint256 matronId,
    uint256 sireId,
    uint256 generation,
    uint256 genes
  );
}
contract ZombieFeeding is ZombieFactory {

  address ckAddress = 0x06012c8cf97BEaD5deAe237070F9587f8E7A266d;
  KittyInterface kittyContract = KittyInterface(ckAddress);

  function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) public {
    require(msg.sender == zombieToOwner[_zombieId]);
    Zombie storage myZombie = zombies[_zombieId];
    _targetDna = _targetDna % dnaModulus;
    uint newDna = (myZombie.dna + _targetDna) / 2;
    if (keccak256(_species) == keccak256(&quot;kitty&quot;)) {
      newDna = newDna - newDna % 100 + 99;
    }
    _createZombie(&quot;NoName&quot;, newDna);
  }

  function feedOnKitty(uint _zombieId, uint _kittyId) public {
    uint kittyDna;
    (,,,,,,,,,kittyDna) = kittyContract.getKitty(_kittyId);
    feedAndMultiply(_zombieId, kittyDna, &quot;kitty&quot;);
  }

}
"><code><span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.4.19;</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">"./zombiefactory.sol"</span>;
<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">KittyInterface</span> </span>{
  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getKitty</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> _id</span>) <span class="hljs-title"><span class="hljs-keyword">external</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> isGestating,
    <span class="hljs-keyword">bool</span> isReady,
    <span class="hljs-keyword">uint256</span> cooldownIndex,
    <span class="hljs-keyword">uint256</span> nextActionAt,
    <span class="hljs-keyword">uint256</span> siringWithId,
    <span class="hljs-keyword">uint256</span> birthTime,
    <span class="hljs-keyword">uint256</span> matronId,
    <span class="hljs-keyword">uint256</span> sireId,
    <span class="hljs-keyword">uint256</span> generation,
    <span class="hljs-keyword">uint256</span> genes
  </span>)</span>;
}
<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">ZombieFeeding</span> <span class="hljs-keyword">is</span> <span class="hljs-title">ZombieFactory</span> </span>{

  <span class="hljs-keyword">address</span> ckAddress <span class="hljs-operator">=</span> <span class="hljs-number">0x06012c8cf97BEaD5deAe237070F9587f8E7A266d</span>;
  KittyInterface kittyContract <span class="hljs-operator">=</span> KittyInterface(ckAddress);

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">feedAndMultiply</span>(<span class="hljs-params"><span class="hljs-keyword">uint</span> _zombieId, <span class="hljs-keyword">uint</span> _targetDna, <span class="hljs-keyword">string</span> _species</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><span class="hljs-operator">=</span> zombieToOwner[_zombieId]);
    Zombie <span class="hljs-keyword">storage</span> myZombie <span class="hljs-operator">=</span> zombies[_zombieId];
    _targetDna <span class="hljs-operator">=</span> _targetDna <span class="hljs-operator">%</span> dnaModulus;
    <span class="hljs-keyword">uint</span> newDna <span class="hljs-operator">=</span> (myZombie.dna <span class="hljs-operator">+</span> _targetDna) <span class="hljs-operator">/</span> <span class="hljs-number">2</span>;
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">keccak256</span>(_species) <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-built_in">keccak256</span>(<span class="hljs-string">"kitty"</span>)) {
      newDna <span class="hljs-operator">=</span> newDna <span class="hljs-operator">-</span> newDna <span class="hljs-operator">%</span> <span class="hljs-number">100</span> <span class="hljs-operator">+</span> <span class="hljs-number">99</span>;
    }
    _createZombie(<span class="hljs-string">"NoName"</span>, newDna);
  }

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">feedOnKitty</span>(<span class="hljs-params"><span class="hljs-keyword">uint</span> _zombieId, <span class="hljs-keyword">uint</span> _kittyId</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
    <span class="hljs-keyword">uint</span> kittyDna;
    (,,,,,,,,,kittyDna) <span class="hljs-operator">=</span> kittyContract.getKitty(_kittyId);
    feedAndMultiply(_zombieId, kittyDna, <span class="hljs-string">"kitty"</span>);
  }

}
</code></pre><h1 id="h-inheritance" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Inheritance</h1><pre data-type="codeBlock" text="contract ZombieFeeding is ZombieFactory {}
"><code><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">ZombieFeeding</span> <span class="hljs-keyword">is</span> <span class="hljs-title">ZombieFactory</span> </span>{}
</code></pre><p>When we create a contract with “is”, it is called inheritance.</p><p>And in son contract, we can call function or member variables in father contract.</p><h1 id="h-address" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Address</h1><p>Hexadecimal literals that pass the address checksum test is address.</p><p>The msg.sender also return an address.</p><p>We can also get a contract on chain by address.</p><h1 id="h-interface" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Interface</h1><pre data-type="codeBlock" text="contract KittyInterface {
  function getKitty(uint256 _id) external view returns (
    bool isGestating,
    bool isReady,
    uint256 cooldownIndex,
    uint256 nextActionAt,
    uint256 siringWithId,
    uint256 birthTime,
    uint256 matronId,
    uint256 sireId,
    uint256 generation,
    uint256 genes
  );
}
"><code><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">KittyInterface</span> </span>{
  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getKitty</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> _id</span>) <span class="hljs-title"><span class="hljs-keyword">external</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> isGestating,
    <span class="hljs-keyword">bool</span> isReady,
    <span class="hljs-keyword">uint256</span> cooldownIndex,
    <span class="hljs-keyword">uint256</span> nextActionAt,
    <span class="hljs-keyword">uint256</span> siringWithId,
    <span class="hljs-keyword">uint256</span> birthTime,
    <span class="hljs-keyword">uint256</span> matronId,
    <span class="hljs-keyword">uint256</span> sireId,
    <span class="hljs-keyword">uint256</span> generation,
    <span class="hljs-keyword">uint256</span> genes
  </span>)</span>;
}
</code></pre><p>Interface looks like a common contract, but the function in interface don’t have body. The function in interface only has the declaration.</p><p>And we can call the contract by interface like this.</p><pre data-type="codeBlock" text="KittyInterface kittyContract = KittyInterface(ckAddress);
 (,,,,,,,,,kittyDna) = kittyContract.getKitty(_kittyId);
"><code>KittyInterface <span class="hljs-attr">kittyContract</span> = KittyInterface(ckAddress)<span class="hljs-comment">;</span>
 (,,,,,,,,,kittyDna) = kittyContract.getKitty(_kittyId)<span class="hljs-comment">;</span>
</code></pre><h1 id="h-keccak256" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">keccak256</h1><p>In solidity, we can only compare if the strings are equal by keccak256.</p><p>keccak256 is a hash algorithm.</p>]]></content:encoded>
            <author>kevin-wang@newsletter.paragraph.com (KevinWang)</author>
        </item>
        <item>
            <title><![CDATA[Learning from crypto zombies lesson 1]]></title>
            <link>https://paragraph.com/@kevin-wang/learning-from-crypto-zombies-lesson-1</link>
            <guid>54ICwFuWvoXoFMayakJz</guid>
            <pubDate>Fri, 29 Aug 2025 17:46:59 GMT</pubDate>
            <description><![CDATA[Hi all, I’m a developer working in web2. I want to learn web3 knowledge and become a developer in web3. In this artical, I will show my solidity learning stage. And this is my crypto zombie. You can click this link to see it. https://share.cryptozombies.io/zh/lesson/1/share/kevin?id=Y3p8NjIzMTk2 In this section, I will show my contract and the knowledge behind the code.pragma solidity ^0.4.19; contract ZombieFactory { event NewZombie(uint zombieId, string name, uint dna); uint dnaDigits = 16;...]]></description>
            <content:encoded><![CDATA[<p>Hi all, I’m a developer working in web2. I want to learn web3 knowledge and become a developer in web3. In this artical, I will show my solidity learning stage.</p><p>And this is my crypto zombie. You can click this link to see it.</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://share.cryptozombies.io/zh/lesson/1/share/kevin?id=Y3p8NjIzMTk2">https://share.cryptozombies.io/zh/lesson/1/share/kevin?id=Y3p8NjIzMTk2</a></p><p>In this section, I will show my contract and the knowledge behind the code.</p><pre data-type="codeBlock" text="pragma solidity ^0.4.19;

contract ZombieFactory {

    event NewZombie(uint zombieId, string name, uint dna);

    uint dnaDigits = 16;
    uint dnaModulus = 10 ** dnaDigits;

    struct Zombie {
        string name;
        uint dna;
    }

    Zombie[] public zombies;

    function _createZombie(string _name, uint _dna) private {
        uint id = zombies.push(Zombie(_name, _dna)) - 1;
        NewZombie(id, _name, _dna);
    }

    function _generateRandomDna(string _str) private view returns (uint) {
        uint rand = uint(keccak256(_str));
        return rand % dnaModulus;
    }

    function createRandomZombie(string _name) public {
        uint randDna = _generateRandomDna(_name);
        _createZombie(_name, randDna);
    }

}
"><code><span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.4.19;</span>

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

    <span class="hljs-function"><span class="hljs-keyword">event</span> <span class="hljs-title">NewZombie</span>(<span class="hljs-params"><span class="hljs-keyword">uint</span> zombieId, <span class="hljs-keyword">string</span> name, <span class="hljs-keyword">uint</span> dna</span>)</span>;

    <span class="hljs-keyword">uint</span> dnaDigits <span class="hljs-operator">=</span> <span class="hljs-number">16</span>;
    <span class="hljs-keyword">uint</span> dnaModulus <span class="hljs-operator">=</span> <span class="hljs-number">10</span> <span class="hljs-operator">*</span><span class="hljs-operator">*</span> dnaDigits;

    <span class="hljs-keyword">struct</span> <span class="hljs-title">Zombie</span> {
        <span class="hljs-keyword">string</span> name;
        <span class="hljs-keyword">uint</span> dna;
    }

    Zombie[] <span class="hljs-keyword">public</span> zombies;

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_createZombie</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> _name, <span class="hljs-keyword">uint</span> _dna</span>) <span class="hljs-title"><span class="hljs-keyword">private</span></span> </span>{
        <span class="hljs-keyword">uint</span> id <span class="hljs-operator">=</span> zombies.<span class="hljs-built_in">push</span>(Zombie(_name, _dna)) <span class="hljs-operator">-</span> <span class="hljs-number">1</span>;
        NewZombie(id, _name, _dna);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_generateRandomDna</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> _str</span>) <span class="hljs-title"><span class="hljs-keyword">private</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">uint</span></span>) </span>{
        <span class="hljs-keyword">uint</span> rand <span class="hljs-operator">=</span> <span class="hljs-keyword">uint</span>(<span class="hljs-built_in">keccak256</span>(_str));
        <span class="hljs-keyword">return</span> rand <span class="hljs-operator">%</span> dnaModulus;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createRandomZombie</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> _name</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        <span class="hljs-keyword">uint</span> randDna <span class="hljs-operator">=</span> _generateRandomDna(_name);
        _createZombie(_name, randDna);
    }

}
</code></pre><h1 id="h-version" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Version</h1><p>At the top of the contract, there is a version of solidity.</p><pre data-type="codeBlock" text="pragma solidity ^0.4.19;
"><code><span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.4.19;</span>
</code></pre><p>The version can help complier check if it’s version is match the code.</p><h1 id="h-type" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Type</h1><pre data-type="codeBlock" text="uint dnaDigits = 16;
"><code>uint <span class="hljs-attr">dnaDigits</span> = <span class="hljs-number">16</span><span class="hljs-comment">;</span>
</code></pre><p>Here is the type in solidity.</p><h2 id="h-booleans" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">booleans</h2><p>The value of booleans are constants true and false.</p><h2 id="h-integers" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">integers</h2><p>There are int and uint to distinguish signed or un signed.</p><p>And there are int8, int16, int24… to int256, the step is 8. So as uint.</p><p>int and uint is the aliases of int256 and uint256.</p><h2 id="h-string" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">string</h2><p>strings are written by quotes like “hello”</p><h1 id="h-operator" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Operator</h1><p>There are basic operators in solidity like + - * / %.</p><p>Especially, ** means exponentiation.</p><h1 id="h-struct" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Struct</h1><pre data-type="codeBlock" text="struct Zombie {
    string name;
    uint dna;
}
"><code><span class="hljs-keyword">struct</span> Zombie {
    <span class="hljs-built_in">string</span> name;
    <span class="hljs-built_in">uint</span> dna;
}
</code></pre><p>In solidity, we can define our own type by struct.</p><p>And we can also define member variables in the struct.</p><h1 id="h-array" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Array</h1><pre data-type="codeBlock" text="Zombie[] public zombies;
uint id = zombies.push(Zombie(_name, _dna)) - 1;
"><code>Zombie[] <span class="hljs-keyword">public</span> zombies;
<span class="hljs-keyword">uint</span> id <span class="hljs-operator">=</span> zombies.<span class="hljs-built_in">push</span>(Zombie(_name, _dna)) <span class="hljs-operator">-</span> <span class="hljs-number">1</span>;
</code></pre><p>If we need to define array, we can use [] behind the type like this.</p><p>The array variable contains the function push. Which can add an element in to the array and return the length of array now.</p><h1 id="h-function" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Function</h1><pre data-type="codeBlock" text="function _generateRandomDna(string _str) private view returns (uint) {
    uint rand = uint(keccak256(_str));
    return rand % dnaModulus;
}
"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_generateRandomDna</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> _str</span>) <span class="hljs-title"><span class="hljs-keyword">private</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">uint</span></span>) </span>{
    <span class="hljs-keyword">uint</span> rand <span class="hljs-operator">=</span> <span class="hljs-keyword">uint</span>(<span class="hljs-built_in">keccak256</span>(_str));
    <span class="hljs-keyword">return</span> rand <span class="hljs-operator">%</span> dnaModulus;
}
</code></pre><p>Function is a block of codes which can be executed.</p><p>The declaration of func is</p><pre data-type="codeBlock" text="function (&lt;parameter types&gt;) {internal|external} [pure|view|payable] [returns (&lt;return types&gt;)]
"><code><span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">&#x3C;parameter types></span>) </span>{<span class="hljs-keyword">internal</span><span class="hljs-operator">|</span><span class="hljs-keyword">external</span>} [<span class="hljs-keyword">pure</span><span class="hljs-operator">|</span><span class="hljs-keyword">view</span><span class="hljs-operator">|</span><span class="hljs-keyword">payable</span>] [<span class="hljs-keyword">returns</span> (<span class="hljs-operator">&#x3C;</span><span class="hljs-keyword">return</span> types<span class="hljs-operator">></span>)]
</code></pre><p>pure function can not achieve any variable in the contract.</p><p>and view function can only watch but can’t change the variable of contract.</p><h1 id="h-event" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Event</h1><pre data-type="codeBlock" text="event NewZombie(uint zombieId, string name, uint dna);
"><code><span class="hljs-function"><span class="hljs-keyword">event</span> <span class="hljs-title">NewZombie</span>(<span class="hljs-params"><span class="hljs-built_in">uint</span> zombieId, <span class="hljs-built_in">string</span> name, <span class="hljs-built_in">uint</span> dna</span>)</span>;
</code></pre><pre data-type="codeBlock" text="function _createZombie(string _name, uint _dna) private {
    uint id = zombies.push(Zombie(_name, _dna)) - 1;
    NewZombie(id, _name, _dna);
}
"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_createZombie</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> _name, <span class="hljs-keyword">uint</span> _dna</span>) <span class="hljs-title"><span class="hljs-keyword">private</span></span> </span>{
    <span class="hljs-keyword">uint</span> id <span class="hljs-operator">=</span> zombies.<span class="hljs-built_in">push</span>(Zombie(_name, _dna)) <span class="hljs-operator">-</span> <span class="hljs-number">1</span>;
    NewZombie(id, _name, _dna);
}
</code></pre><p>If we want do something when the solidity was executed, we can use event.</p><p>The javascript can listening the event in contract.</p>]]></content:encoded>
            <author>kevin-wang@newsletter.paragraph.com (KevinWang)</author>
        </item>
    </channel>
</rss>