<?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>thurendous</title>
        <link>https://paragraph.com/@thurendous</link>
        <description>Crypto enthusiast. If you think what I am doing is useful, buy me a coffee by collecting one of my article or you can follow me on twitter.</description>
        <lastBuildDate>Mon, 07 Sep 2026 19:20:37 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <image>
            <title>thurendous</title>
            <url>https://storage.googleapis.com/papyrus_images/8346d483481ea5d1f753479df7446ec328efdd0f7eb4c72cebd8d8b71bd3f4b4.png</url>
            <link>https://paragraph.com/@thurendous</link>
        </image>
        <copyright>All rights reserved</copyright>
        <item>
            <title><![CDATA[Why Crypto is the Future | Hello Web3]]></title>
            <link>https://paragraph.com/@thurendous/why-crypto-is-the-future-hello-web3</link>
            <guid>dy5tLQVFwNN2jbl8eIBN</guid>
            <pubDate>Sat, 20 May 2023 09:35:37 GMT</pubDate>
            <description><![CDATA[Crypto is the future​結論から言います。ぼくはクリプトが未来だと考えています。 その理由を語るには、結構な労力と時間が必要なのかもしれませんが、言語化することによって、自分の頭の整理にもなるので、ここで僕はそれに挑戦したいと思います。 少し想像してみてくださいね。現実世界のどんなものでも（サービス、不動産、債権、キャッシュ、買い物、国債、ゴールド、ホテルのいち日泊まる権利、などなどありとあらゆるもの）、また、バーチャル世界にあるどんなものでも（ゲームアイテム、音楽、バーチャル世界の土地、ゲームキャラのスキンなどなど）、インターネット上でボーダレスにミドルマンなしで、オープンに公平に取引ができる時代 国境など関係なしにスムーズに多文化多言語協力関係の組織を築けて、そして報酬を直接的に自分のアカウントでもらえる。なにか没頭できるようなことに関してグローバルに募集して組織を一瞬に作って何かをやったり、収益化できたりこれが僕が考えたブロックチェーンの近未来です。もちろん、様々な壁やハードルが立ちはだかっているのは間違いないです。けれど、それが何年かかるかわかりませんが...]]></description>
            <content:encoded><![CDATA[<h2 id="h-crypto-is-the-future" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Crypto is the future​</h2><p>結論から言います。ぼくはクリプトが未来だと考えています。</p><p>その理由を語るには、結構な労力と時間が必要なのかもしれませんが、言語化することによって、自分の頭の整理にもなるので、ここで僕はそれに挑戦したいと思います。</p><p>少し想像してみてくださいね。</p><blockquote><p>現実世界のどんなものでも（サービス、不動産、債権、キャッシュ、買い物、国債、ゴールド、ホテルのいち日泊まる権利、などなどありとあらゆるもの）、また、バーチャル世界にあるどんなものでも（ゲームアイテム、音楽、バーチャル世界の土地、ゲームキャラのスキンなどなど）、インターネット上でボーダレスにミドルマンなしで、オープンに公平に取引ができる時代</p><p>国境など関係なしにスムーズに多文化多言語協力関係の組織を築けて、そして報酬を直接的に自分のアカウントでもらえる。なにか没頭できるようなことに関してグローバルに募集して組織を一瞬に作って何かをやったり、収益化できたり</p></blockquote><p>これが僕が考えたブロックチェーンの近未来です。もちろん、様々な壁やハードルが立ちはだかっているのは間違いないです。けれど、それが何年かかるかわかりませんが、近いうちそれに近い形態になると思います。なぜなら、そういったインフラはすでにできてきて改善もどんどんされていっている時代なので、そうなっていくのは目に見えたからです。</p><p>また、自分が考えた世界に比べて実際にはもっと進んでいる可能性が結構高いと思います。なぜかというと、人間は線形的に物事を考えがちであり、今の状況がよりよい状況になるという想像しかできません。実際には今では考えたことのない状況になったりするのもあり得ます。自分が想像力に欠けるのも無理はありません。ただ、現時点に基づいて予測をしないと何も始まりませんよね。</p><p>結果を言ったのはいいけど、なんでそうなるんだ？と思うと思いますので、ここから述べていきます。言いたいことが山程あるので、記事はシリーズ化します。</p><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">リアルからバーチャルへ​</h2><p>大きな理由としては、人間社会はリアルからバーチャルへ遷移していることが大きな理由です。</p><h3 id="h-metaverse" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Metaverse​</h3><p>最近だと、メタバースというワードがかなり耳に入ってくる様になったのではないでしょうか。メタバースと聞くと、わけがわからないのかもしれませんが、自分の理解ですと、このワードはまだ意味が定まっていないと思います。あえて意見を言わせてもらうと、メタバースはいわゆるバーチャル世界そのものの定義になります。誰でも作れますし、すでにあるインターネットそのものも広義的にメタバースなのです。</p><p>例えば、すでに僕達のグーグルアカウントあるいはイーサリアムウォレットのアカウントとかがメタバースの僕達の分身と理解してもよいでしょう。ただ、このメタバースはまだまだ初歩的な段階なので、本当に使えるバーチャル世界と言えるのかというところが確かにあります。</p><h3 id="h-software-is-eating-the-world" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">&quot;Software is eating the world&quot;​</h3><p>英語圏ではとても有名な言葉があります。それはこの「Software is eating the world. (ソフトウェアは世界を飲み込んでいる)」という言葉です。</p><p>これは 2011 年に A16Z というとても先進的な視野を持つ<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://a16z.com/2011/08/20/why-software-is-eating-the-world/"> VC のファンダーが話した言葉</a>です。その後の世界はご存知の通り、彼が言った通りになり、ソフトウェアは世界を飲み込んでいきました。</p><h3 id="h-companies-market-cap-ranking" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Companies&apos; market cap ranking​</h3><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>上の画像でわかるように、その過程では世界時価総額ランキングの上位はほとんどインターネット企業、いわゆる FANG または GAFA と呼ばれる企業に独占されるようになりました。</p><p>一昔前日本企業があれだけ独占していたランキングですが、日本がインターネットの波を完全に逃したせいで、今やランキングの下位となっています。アメリカの企業がほとんどで、たまに中国や韓国の企業が現れて、31 位になって初めてトヨタが出てきています。世の中の時流はものづくり時代からインターネット時代になったということです。</p><p>こういった企業のサービスを使ったことがある方はわかると思いますが、とても役に立っていて、一度使うとなかなかそのエコシステムから抜け出せなくなります。このように、ソフトウェアが世界を飲み込んでいます。しかし、これでは終わらないのです。</p><p>これは見方を変えると、人類がバーチャル世界へ進んだ第一歩に過ぎず、まだまだ道のりは長いです。現在こういった大企業が作っている初歩的な「メタバース」の世界はこれはこれでインフォメーションをデジタル化することに成功していますが、まだお金というものは現実世界から切り離した形でデジタル化できていません。（例えば paypay とかはお金と同等なように思われますが、独立した形でお金というものではなく、結局は日本円の分身であり、paypay の運用会社に大きく依存した形です → 運用会社はその世界の神様です）</p><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">神様のいない（非中央集権的な）世界​</h3><p>ブロックチェーンはこれを解決してくれます。ブロックチェーンは今のインターネットにおけるなんでもコピーできてしまう問題を解決し、バーチャルなものにリアル世界と同じような誰にも関与されない希少性、改ざん耐性を与えて、初めてバーチャル世界を「世界」として成り立たせることができるのです。先程、神様といったのは例えばあなたの生きる世界に神様がどこかの人間になると、怖くありませんか？その人の決定で何もかも変わる可能性があります。極端な話、生存の権利さえも奪われるリスクが潜んでいます。そんな世界ってディストピアで嫌ですよね？</p><p>すでに気づいてるかと思いますが、今僕達はまさにこの神様がいる（中央集権的な）インターネット世界に住んでいます。youtuber さんはわけがなくチャンネル停止されるし、アマゾンでは明確な理由が与えられず出店停止処分になったりします。ツイッターだってトランプさんのアカウントがバンされたことで有名でしたね。</p><p>もちろん、悪さをしてバンされたらそれはそれで仕方ないのですが、ただ会社側の一任ですべてが決定されてしまうのは果たして正義なのかどうかは議論の余地があるのではないでしょうか？</p><p>実際にイーサリアムの創始者であるビタリック氏はワールドオブワークラフトの MMO ゲーム内の好きなキャラクタが弱体化されたことで嫌気が差したのがイーサリアムというブロックチェーンの始まりだとも言われています。神様のいない世界は人類史上なかったので、さぞかしビタリック氏は作りたかったんだろうね。</p><p>ブロックチェーンであれば、神様のいない世界が作れるという点が非常に大きいです。これによって万人平等で同じルールに則った世界が構築できる様になったといえます。</p><p>ただ、今はこの大きな課題解決の現在進行系であり、あれやこれの不具合や満足の行かない点がたくさんあるでしょう。</p><p>そういったときには、僕の意見としては未来志向がいいです。未来志向は何かというと、クレーマーにならず暖かく見守ってあげて一緒に成長するのがベストだと思います。クレーマーになるのは簡単であり、課題を解決する側に回って色々考えて行動することこそ社会が進化していく力となっていくので、結局はみんなウィンウィンになるわけです。</p><p>話がそれましたが、人間社会はリアルからバーチャルへという大きな方向性は間違いがなく、すでに自分たちの活動はたくさんインターネットへ移植しています。これが加速していきます。</p><h3 id="h-human-societys-gdp" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Human society&apos;s GDP​</h3><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.weforum.org/agenda/2017/09/over-2000-years-of-economic-history-in-one-chart"><em>出典</em></a></p><p>人類の歴史における 一人当たりの GDP は上のグラフを見て下さい。わかるかと思いますが、指数関数的に増加していることがわかります。これの主な要因には、一つとしてリアルな世界ではリアルな資源の開発ができる部分がたくさんあったことと、技術的な進歩が爆発的に増加したと思います。産業革命以後、人類はパンドラのボックスを開いたように、知の集合体として大きく成長し、もはや産業革命のときみたいに一種の技術進歩で大きく人類が前進するという状況ではなくなっています。</p><p>今現在だけでも、自分の認識している範囲ですと、5G、ブロックチェーン、AI、Iot など、様々な技術が雨後の筍のように現れてきて、同時に進化して融合しつつ、次の産業革命として人類社会を爆発的に前進させるでしょう。想像を絶するような世界がまた 10 年 20 年後には現れて人間社会のこれまでの知識、経験、哲学や価値観をすべて考え直さなければならないのかもしれません。今はこれだけ進化の速度が早くて、毎日が新たな歴史のページをめくっているようなものです。</p><h3 id="h-why-human-will-go-virtual" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Why human will go virtual​</h3><p>また、なぜバーチャルが良いのかという疑問もあろうかと思います。</p><p>昔マルクスの人口論でも有名ですが、人類の発展はいずれ現実世界の限界を迎えてしまい、減速してしまうでしょうという理論です。自分は人間社会の GDP はますます増加していくことは間違いないと思っています。なぜなら現実世界は制約がありますが、バーチャル空間は制約が少ないからです。</p><p>人間は大航海時代以来、影響範囲を拡大しようと、地球をたくさん探索し続け開発してきました。今や宇宙へ行こうとしています。ただ、宇宙開発はそう簡単にできるわけではありません。宇宙の開発を突破するには時間と空間というとてつもなく困難な壁がありました。そこで、この制限がかかっていないバーチャル空間の開発が容易なのではないかと普通は考えます。バーチャルな世界にいると、瞬間移動もできてスペースの問題も解決されます。</p><p>Web3 が来ると人類のバーチャル化が更に加速していきます。価値が容易にインターネット内でやり取りできるようになり、機械と機械がミドルマンなしで価値のやり取りができるようになります。少し予言しますが、将来はこの機械間の価値の交換がメインになるでしょう。いわゆるお金については、ますますプログラマブルマネー（コーディングで制御できるお金）になっていくわけです。</p><p>バーチャルな世界で生きている人間にとっては当然バーチャル世界ネイティブな資産が生まれてもおかしくないでしょう。それがクリプト（仮想通貨）です。</p><h2 id="h-why-people-cannot-understand-this-trend" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Why people cannot understand this trend?​</h2><p>この話はめちゃめちゃ重要で、なぜ気づいていない人々が多いのか？という疑問を抱くと思います。これについては、まあいろいろな理由があるでしょう。でもこれを知ってもらったあなたにはこのトレンドのことを覚えてほしいです。</p><p>技術というものは歴史において毎回何かを一新して、既得権益者の利益に触れます。そうすると必ず反発を受けます。</p><p>だけど、短期的には既得権益のほうが勝つかもしれませんが、長期的には勝てません。時代のトレンドというのは逆らうことがほぼ不可能なのです。</p><p>英語ではよく言われる言葉として以下があります。</p><blockquote><p>First they ignore you, then they laugh at you, then they fight you, then you win.</p></blockquote><p>これはクリプトの業界でもめちゃくちゃぴんとくる言葉です。「最初に彼らあなたを無視し、それからあざ笑わい、それから抗い、最終的にはあなたの勝利」というような感じで、歴史においては様々なトレンドがたどってきた運命なのです。</p><p>車の歴史もそうですし、発明された当初、めちゃくちゃ効率が悪くデザインも良くなかったので、馬車のほうが全然いいと思っていた人が少なからずいました。また、そのあとのインターネットも発明された当初は誰にも理解されず、ビル・ゲイツがテレビでインターネットを紹介していたときには観客と司会者の方から大いに笑われていました。今だから言えるのですが、当初のビル・ゲイツが想像した世界よりも遥かに進んだインターネット社会ができています。</p><blockquote><p>&quot;History Doesn’t Repeat Itself, but It Often Rhymes&quot; - Mark Twain</p></blockquote><p>Mark Twain 氏が言っている通りです。</p><p>そこで、今度はブロックチェーンの番です。「ディスられる、怒られる、軽蔑される、無視される、それでも進化し続けて社会を変えていき、我々の生き方も変えてくれる」、これがクリプトです。</p><p>だらだらと書いてしまいましたが、普段友人に聞かれて説明すると結構な時間をかけて説明できたりしますが、いざ書くとなるとうまく書けないんですね。まだ書ききれないほどありますので、また次回をお楽しみに！</p><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0"><em>免責事項</em>​</h3><p><em>本 website にかかれている内容はあくまで個人的な見解であり、Financial advice ではありません。</em></p>]]></content:encoded>
            <author>thurendous@newsletter.paragraph.com (thurendous)</author>
        </item>
        <item>
            <title><![CDATA[NFT、ERC721とはなんぞや（コード解説） | Hello Web3]]></title>
            <link>https://paragraph.com/@thurendous/nft-erc721-hello-web3</link>
            <guid>u0EeTG44GLZhtRYmbL5z</guid>
            <pubDate>Sat, 20 May 2023 09:27:37 GMT</pubDate>
            <description><![CDATA[Hello, everybody!TL;DRNFT は非代替性トークンのことシンプルにいうとデジタル所有権のことコードで理解しましょうBTC や ETH のようなトークンは FT と呼ばれ、代替性トークンのことです。特徴としては、お互いに交換可能で大きな違いはないことです（厳密には違いもありますが、ここではその議論をしない）。また、アート、コレクション、不動産などのようなお互い違いをかなり持っているようなものは非代替性トークンで代表されることがほとんどです。 イーサリアムでは EIP721 が提案されて、ERC721 のスタンダードが形成されました。EIP, ERC とは結論：EIP が ERC を含んでいる まず、理解しなければならないのは、ERC721 です。この２つの間にはなんの関係があるのでしょうか。EIP とは、Ethereum Improvement Proposals のことで、イーサリアムコミュニティが提案したプロトコルなどを改善するための提案のことです。EIP はイーサリアムの中の任意の分野の改善で、例えば新たな機能、ERC、プロトコル改善などがあります。 ER...]]></description>
            <content:encoded><![CDATA[<p>Hello, everybody!</p><h2 id="h-tldr" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">TL;DR</h2><ul><li><p>NFT は非代替性トークンのこと</p></li><li><p>シンプルにいうとデジタル所有権のこと</p></li><li><p>コードで理解しましょう</p></li></ul><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>BTC や ETH のようなトークンは FT と呼ばれ、代替性トークンのことです。特徴としては、お互いに交換可能で大きな違いはないことです（厳密には違いもありますが、ここではその議論をしない）。また、アート、コレクション、不動産などのようなお互い違いをかなり持っているようなものは非代替性トークンで代表されることがほとんどです。</p><p>イーサリアムでは EIP721 が提案されて、ERC721 のスタンダードが形成されました。</p><h2 id="h-eip-erc" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">EIP, ERC とは</h2><p>結論：EIP が ERC を含んでいる</p><p>まず、理解しなければならないのは、<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://eips.ethereum.org/EIPS/eip-721">ERC721</a> です。この２つの間にはなんの関係があるのでしょうか。EIP とは、Ethereum Improvement Proposals のことで、イーサリアムコミュニティが提案したプロトコルなどを改善するための提案のことです。EIP はイーサリアムの中の任意の分野の改善で、例えば新たな機能、ERC、プロトコル改善などがあります。</p><p>ERC とは、Ethereum Request For Comment のことで、イーサリアム上の各種アプリケーションのプロトコルとスタンダードのこととなっています。典型的な ERC20, ERC721、あるいは URI のスタンダード ERC67、あるいはウォレットのフォーマット EIP75, EIP85 などがある。</p><p>ERC スタンダードはイーサリアムの発展における重要な構成要素で、ERC20, ERC721, ERC223, ERC777 などのスタンダードがイーサリアムのエコシステムに多大な影響を与えていました。</p><h2 id="h-erc165" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">ERC165</h2><p>まず ERC165 について理解しましょう。 スマートコントラクトはインターフェースを宣言して他のスマートコントラクトがチェックするためにやっているのが ERC165 のことです。</p><p>シンプルにいうと、<code>ERC165</code> を通してとあるコントラクトが <code>ERC721</code>, <code>ERC1155</code> をサポートしているかチェックできるという仕組みです。</p><pre data-type="codeBlock" text="interface IERC165 {
    /**
     * @dev コントラクトが当該スタンダードの`interfaceId`を実装していればtrueを返す
     * 詳細はこちら：https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     *
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
"><code><span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IERC165</span> </span>{
    <span class="hljs-comment">/**
     * @dev コントラクトが当該スタンダードの`interfaceId`を実装していればtrueを返す
     * 詳細はこちら：https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     *
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">supportsInterface</span>(<span class="hljs-params"><span class="hljs-keyword">bytes4</span> interfaceId</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></span>)</span>;
}
</code></pre><p>次に実際には ERC721 がどのように <code>supportsInterface()</code>を実現したのか見てみましょう。</p><pre data-type="codeBlock" text="function supportsInterface(bytes4 interfaceId) external pure override returns (bool)
    {
        return
            interfaceId == type(IERC721).interfaceId ||
            interfaceId == type(IERC165).interfaceId;
    }
"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">supportsInterface</span>(<span class="hljs-params"><span class="hljs-keyword">bytes4</span> interfaceId</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">pure</span></span> <span class="hljs-title"><span class="hljs-keyword">override</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bool</span></span>)
    </span>{
        <span class="hljs-keyword">return</span>
            interfaceId <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-keyword">type</span>(IERC721).<span class="hljs-built_in">interfaceId</span> <span class="hljs-operator">|</span><span class="hljs-operator">|</span>
            interfaceId <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-keyword">type</span>(IERC165).<span class="hljs-built_in">interfaceId</span>;
    }
</code></pre><p>この関数<code>supportsInterface</code>は IERC721 あるいは IERC165 の interfaceId が引数として入力された場合に、<code>true</code>を返し、そうでない場合は<code>false</code>を返します。</p><h2 id="h-ierc721" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">IERC721</h2><p><code>IERC721</code>の中身を見てみましょう。 <code>IERC721</code>は<code>ERC721</code>のインターフェーススタンダードのコントラクトで、ERC721 が実現すべき一般的な関数を定義してます。<code>tokenId</code>を使って非代替性トークンを代表しています。アプルーブあるいはトランスファに際して、<code>tokenId</code>は必ず出番があります。しかし、ERC20 はトランスファにおける数量だけを定義すればよくて、tokenId はありません。</p><pre data-type="codeBlock" text="/**
 * @dev ERC721スタンダードのインターフェース
 */
interface IERC721 is IERC165 {
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    function balanceOf(address owner) external view returns (uint256 balance);

    function ownerOf(uint256 tokenId) external view returns (address owner);

    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes calldata data
    ) external;

    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    function approve(address to, uint256 tokenId) external;

    function setApprovalForAll(address operator, bool _approved) external;

    function getApproved(uint256 tokenId) external view returns (address operator);

    function isApprovedForAll(address owner, address operator) external view returns (bool);
}
"><code><span class="hljs-comment">/**
 * @dev ERC721スタンダードのインターフェース
 */</span>
<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IERC721</span> <span class="hljs-keyword">is</span> <span class="hljs-title">IERC165</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">event</span> <span class="hljs-title">Transfer</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> <span class="hljs-keyword">indexed</span> <span class="hljs-keyword">from</span>, <span class="hljs-keyword">address</span> <span class="hljs-keyword">indexed</span> to, <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">indexed</span> tokenId</span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">event</span> <span class="hljs-title">Approval</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> <span class="hljs-keyword">indexed</span> owner, <span class="hljs-keyword">address</span> <span class="hljs-keyword">indexed</span> approved, <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">indexed</span> tokenId</span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">event</span> <span class="hljs-title">ApprovalForAll</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> <span class="hljs-keyword">indexed</span> owner, <span class="hljs-keyword">address</span> <span class="hljs-keyword">indexed</span> operator, <span class="hljs-keyword">bool</span> approved</span>)</span>;

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">balanceOf</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> owner</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">uint256</span> balance</span>)</span>;

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ownerOf</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> tokenId</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">address</span> owner</span>)</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">calldata</span> data
    </span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span></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">external</span></span></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">external</span></span></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">external</span></span></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">external</span></span></span>;

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getApproved</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> tokenId</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">address</span> operator</span>)</span>;

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isApprovedForAll</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> owner, <span class="hljs-keyword">address</span> operator</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></span>)</span>;
}
</code></pre><h2 id="h-ierc721-event" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">IERC721 の event</h2><p>3 つの event を含まれています。<code>Transfer</code>、<code>Approval</code>は ERC20 にも存在します。</p><ul><li><p><code>Transfer</code>: トークントランスファのときに放出。送り元<code>from</code>、送り先<code>to</code>、<code>tokenId</code>。</p></li><li><p><code>Approvel</code>: アプルーブするときに放出。アプルーブする側のアドレス<code>owner</code>、アプルーブした先のアドレス<code>approved</code>、<code>tokenId</code>。</p></li><li><p><code>ApprovalForAll</code>: 一気に大量にアプルーブするときに放出するイベント。アプルーブする側のアドレス<code>owner</code>、アプルーブされる側のアドレス<code>operator</code>、アプルーブする場合<code>approved</code>は true で、逆に権限を剥奪する場合、<code>approved</code>は false にする</p></li></ul><h2 id="h-ierc721" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">IERC721 関数</h2><ul><li><p><code>balanceOf</code>: とあるアドレスの持っている NFT の数量を返す</p></li><li><p><code>ownerOf</code>: tokenId のオーナーを返す</p></li><li><p><code>transferFrom</code>: 普通のトランスファ、引数は <code>from</code> は送り元で、<code>to</code> は送り先、<code>tokenId </code>も必要</p></li><li><p><code>safeTransferFrom</code>:安全なトランスファ、もし受ける側はコントラクトの場合、<code>ERC721Receiver</code>の実装が求められる。引数は送り元の<code>from</code>、送り先の<code>to</code>、<code>tokenId</code></p></li><li><p><code>approve</code>: 他のアドレスにあなたの NFT を使用する権利を渡す。権利を付与するアドレスは<code>to</code>、そして<code>tokenId</code>も引数に</p></li><li><p><code>getApproved</code>: <code>tokenId</code>がどのアドレスに権限を付与したのか確認する</p></li><li><p><code>setApprovalFroAll</code>: 自分の持っているこのコントラクトのすべての NFT をとあるアドレスに対して全権移譲する</p></li><li><p><code>isApprovedForAll</code>: 全権移譲しているアドレスがあるか確認する</p></li><li><p>safeTransferFrom<code>: 安全なトランスファ関数のオーバーライド関数、引数に</code>data`が含まれている</p></li></ul><h2 id="h-ierc721receiver" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">IERC721Receiver</h2><p>コントラクトがもし ERC721 の実現をしていない場合、送られてきた NFT はブラックホールに送ったように、永遠に取り出せなくなります。これを防止するために、ERC721 は<code>safetransferFrom()</code>関数を実装している。ターゲットコントラクトが<code>IERCReceiver</code>インターフェースを実装している場合のみ、ERC721 トークンを受け取ることができます。そうでない場合は<code>revert</code>されます。IERC721Receiver インターフェースは一個の<code>onERC721Receiver()</code>関数しかありません。</p><pre data-type="codeBlock" text="// ERC721Receiverのインターフェース：　コントラクトはこれを実装して安全なトランスファを受けることができる
interface IERC721Receiver {
    function onERC721Received(
        address operator,
        address from,
        uint tokenId,
        bytes calldata data
    ) external returns (bytes4);
}
"><code><span class="hljs-comment">// ERC721Receiverのインターフェース：　コントラクトはこれを実装して安全なトランスファを受けることができる</span>
<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IERC721Receiver</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">onERC721Received</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span> operator,
        <span class="hljs-keyword">address</span> <span class="hljs-keyword">from</span>,
        <span class="hljs-keyword">uint</span> tokenId,
        <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">calldata</span> data
    </span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bytes4</span></span>)</span>;
}
</code></pre><p>次に<code>ERC721</code>がどうやって<code>_checkOnERC721Received</code>を使ってコントラクトが<code>onERC721Receiver()</code>関数を実装していることを確認しているのを見てみましょう。</p><pre data-type="codeBlock" text="function _checkOnERC721Received(
        address from,
        address to,
        uint tokenId,
        bytes memory _data
    ) private returns (bool) {
        if (to.isContract()) {
            return
                IERC721Receiver(to).onERC721Received(
                    msg.sender,
                    from,
                    tokenId,
                    _data
                ) == IERC721Receiver.onERC721Received.selector;
        } else {
            return true;
        }
    }
"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_checkOnERC721Received</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">uint</span> tokenId,
        <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">memory</span> _data
    </span>) <span class="hljs-title"><span class="hljs-keyword">private</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">if</span> (to.isContract()) {
            <span class="hljs-keyword">return</span>
                IERC721Receiver(to).onERC721Received(
                    <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>,
                    <span class="hljs-keyword">from</span>,
                    tokenId,
                    _data
                ) <span class="hljs-operator">=</span><span class="hljs-operator">=</span> IERC721Receiver.onERC721Received.<span class="hljs-built_in">selector</span>;
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
        }
    }
</code></pre><h2 id="h-ierc721metadata" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">IERC721Metadata</h2><p>IERC721Metadata は ERC721 の拡張インターフェイス。３つの metadata 用関数を用いている。</p><ul><li><p><code>name()</code>：トークン名を返す</p></li><li><p><code>symbol()</code>:トークン符号</p></li><li><p><code>tokenURI()</code>:tokenId を使って metadata の url をとってくる。ERC721 特有の関数</p></li></ul><pre data-type="codeBlock" text="interface Ierc721Metadata is IERC721 {
    function name() external view returns (string memory);

    function symbol() external view returns (string memory);

    function tokenURI(uint256 tokenId) external view returns (string memory);
}
"><code><span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">Ierc721Metadata</span> <span class="hljs-keyword">is</span> <span class="hljs-title">IERC721</span> </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">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">string</span> <span class="hljs-keyword">memory</span></span>)</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">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">string</span> <span class="hljs-keyword">memory</span></span>)</span>;

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">tokenURI</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> tokenId</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">string</span> <span class="hljs-keyword">memory</span></span>)</span>;
}
</code></pre><h2 id="h-erc721" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">ERC721 メインコントラクト</h2><p><code>ERC721</code> メインコントラクトは <code>IERC721</code>, <code>IERC165</code>, <code>IERC721Metadata</code> のすべての機能を定義した。4 つの状態変数、17 個の関数を含まれている。シンプルに実装されている。詳細はコメントを読んでください。</p><pre data-type="codeBlock" text="// SPDX-License-Identifier: MIT
// by 0xAA
pragma solidity ^0.8.4;

import &quot;./IERC165.sol&quot;;
import &quot;./IERC721.sol&quot;;
import &quot;./IERC721Receiver.sol&quot;;
import &quot;./IERC721Metadata.sol&quot;;
import &quot;./Address.sol&quot;;　// library
import &quot;./String.sol&quot;; // library

contract ERC721 is IERC721, IERC721Metadata{
    using Address for address; // Address libraryを使う（isContractを使うため）
    using Strings for uint256; // String library

    // Token名
    string public override name;
    // Tokenシンボル
    string public override symbol;
    // tokenId -&gt; owner address のマッピング
    mapping(uint =&gt; address) private _owners;
    // address -&gt; バランスのマッピング
    mapping(address =&gt; uint) private _balances;
    // tokenID -&gt; アプルーブされたアドレスのマッピング
    mapping(uint =&gt; address) private _tokenApprovals;
    //  owner -&gt; operatorアドレス -&gt; bool（権限渡した場合はtrue）
    mapping(address =&gt; mapping(address =&gt; bool)) private _operatorApprovals;

    /**
     * constructor, name, symbolを初期化する
     */
    constructor(string memory name_, string memory symbol_) {
        name = name_;
        symbol = symbol_;
    }

    // ERC165のsupportsInterface関数
    function supportsInterface(bytes4 interfaceId)
        external
        pure
        override
        returns (bool)
    {
        return
            interfaceId == type(IERC721).interfaceId ||
            interfaceId == type(IERC165).interfaceId ||
            interfaceId == type(IERC721Metadata).interfaceId;
    }

    // IERC721のbalanceOf関数、_balancesを使って調べたいアドレスの残高を返す
    function balanceOf(address owner) external view override returns (uint) {
        require(owner != address(0), &quot;owner = zero address&quot;);
        return _balances[owner];
    }

    // IERC721のownerOf関数、_owners変数を使ってtokenIdのownerを返す
    function ownerOf(uint tokenId) public view override returns (address owner) {
        owner = _owners[tokenId];
        require(owner != address(0), &quot;token doesn&apos;t exist&quot;);
    }

    // IERC721のisApprovedForAll、_operatorApprovals変数を
    // 使ってownerがoperatorに権限を移譲したかどうかをチェックする。
    // 権限移譲した場合はtrueを返す
    function isApprovedForAll(address owner, address operator)
        external
        view
        override
        returns (bool)
    {
        return _operatorApprovals[owner][operator];
    }

    // IERC721のsetApprovalForAllを実装。持っているトークンをすべてoperatorに権限を渡す(true),
    // あるいはoperatorの権限を剥奪する(false)。_setApprovalForAll関数を呼び出す。
    function setApprovalForAll(address operator, bool approved) external override {
        _operatorApprovals[msg.sender][operator] = approved;
        emit ApprovalForAll(msg.sender, operator, approved);
    }

    // 实现IERC721的getApproved，利用_tokenApprovals变量查询tokenId的授权地址。
    function getApproved(uint tokenId) external view override returns (address) {
        require(_owners[tokenId] != address(0), &quot;token doesn&apos;t exist&quot;);
        return _tokenApprovals[tokenId];
    }

    // _approve関数。_tokenApprovalsを書き換えて，toアドレスに tokenIdをいじる権限を渡す。
    // Approvalイベントを放出。
    function _approve(
        address owner,
        address to,
        uint tokenId
    ) private {
        _tokenApprovals[tokenId] = to;
        emit Approval(owner, to, tokenId);
    }

    // IERC721のapprove関数，tokenIdの権限を to アドレスに渡す。
    // 条件：toはownerではないこと，かつmsg.senderはownerあるいはapproveされたアドレス。
    // _approve関数を呼び出す
    function approve(address to, uint tokenId) external override {
        address owner = _owners[tokenId];
        require(
            msg.sender == owner || _operatorApprovals[owner][msg.sender],
            &quot;not owner nor approved for all&quot;
        );
        _approve(owner, to, tokenId);
    }

    //  spenderアドレスがtokenIdを使う権限があるかないかを調べる。（あるのはownerか
    // approveされたかのいずれだ。approveされた場合は通常のapproveあるいは
    // setApprovalForAllの2パターン）
    function _isApprovedOrOwner(
        address owner,
        address spender,
        uint tokenId
    ) private view returns (bool) {
        return (spender == owner ||
            _tokenApprovals[tokenId] == spender ||
            _operatorApprovals[owner][spender]);
    }

    /*
     * トランスファ関数。_balances、_ownerのバランスを調整して tokenId を from から toに
     * トランスファする。同時にTransferイベントを放出。
     * 前提条件:
     * 1. tokenId は from によって所有されている
     * 2. to はゼロアドレスでない
     * 条件を満たさない場合はrevert
     */
    function _transfer(
        address owner,
        address from,
        address to,
        uint tokenId
    ) private {
        require(from == owner, &quot;not owner&quot;);
        require(to != address(0), &quot;transfer to the zero address&quot;);

        _approve(owner, address(0), tokenId); // トランスファするので権限をリセットする

        _balances[from] -= 1;
        _balances[to] += 1;
        _owners[tokenId] = to;

        emit Transfer(from, to, tokenId);
    }

    // IERC721のtransferFrom関数の実装，セーフトランスファではないので、
    // この関数を使うのは推奨されていない。
    function transferFrom(
        address from,
        address to,
        uint tokenId
    ) external override {
        address owner = ownerOf(tokenId);
        require(
            _isApprovedOrOwner(owner, msg.sender, tokenId),
            &quot;not owner nor approved&quot;
        );
        _transfer(owner, from, to, tokenId);
    }

    /**
     * セーフトランスファ，安全にtokenIdをfromからtoへトランスファする。スマートコントラクトが
     * erc721に対応しているかどうかをチェックした上で、トランスファをするので、NFTが永遠に
     * ロックされる実態を回避する。_transfer、_checkOnERC721Received関数を呼び出す。
     * 条件：
     * from はゼロアドレスではない
     * to はゼロアドレスではない
     * tokenId が存在してしかもfromアドレスが所有
     * toがスマートコントラクトの場合、必ずIERC721Receiver-onERC721Receivedをサポートされる
     * ことが求められる
     */
    function _safeTransfer(
        address owner,
        address from,
        address to,
        uint tokenId,
        bytes memory _data
    ) private {
        _transfer(owner, from, to, tokenId);
        require(_checkOnERC721Received(from, to, tokenId, _data), &quot;not ERC721Receiver&quot;);
    }

    /**
     * IERC721のsafeTransferFromを実装。セーフトランスファ関数，_safeTransfer関数を呼び出している
     */
    function safeTransferFrom(
        address from,
        address to,
        uint tokenId,
        bytes memory _data
    ) public override {
        address owner = ownerOf(tokenId);
        require(
            _isApprovedOrOwner(owner, msg.sender, tokenId),
            &quot;not owner nor approved&quot;
        );
        _safeTransfer(owner, from, to, tokenId, _data);
    }

    // safeTransferFromのオーバライド関数、引数が違う
    function safeTransferFrom(
        address from,
        address to,
        uint tokenId
    ) external override {
        safeTransferFrom(from, to, tokenId, &quot;&quot;);
    }

    /**
     * mint関数。_balances、_ownersのバランスをいじることで、tokenIdをtoへトランスファする。
     * 同時にTransferイベントを放出する。
     * 現在の状態では、誰でもミントできるので、開発者は普通この関数を書き換える
     * 条件:
     * 1. tokenIdがまだ存在しない
     * 2. toはゼロアドレスでない
     */
    function _mint(address to, uint tokenId) internal virtual {
        require(to != address(0), &quot;mint to zero address&quot;);
        require(_owners[tokenId] == address(0), &quot;token already minted&quot;);

        _balances[to] += 1;
        _owners[tokenId] = to;

        emit Transfer(address(0), to, tokenId);
    }

    // バーン関数，_balances、_owners変数を調整してtokenIdをバーンする。同時にTransferイベントを放出
    // 条件：tokenId存在。
    function _burn(uint tokenId) internal virtual {
        address owner = ownerOf(tokenId);
        require(msg.sender == owner, &quot;not owner of token&quot;);

        _approve(owner, address(0), tokenId); // 権限を更新

        _balances[owner] -= 1;
        delete _owners[tokenId];

        emit Transfer(owner, address(0), tokenId);
    }

    // _checkOnERC721Received：IERC721Receiver-onERC721Received関数, 送り先はERC721互換かどうかをチェックするため
    function _checkOnERC721Received(
        address from,
        address to,
        uint tokenId,
        bytes memory _data
    ) private returns (bool) {
        if (to.isContract()) {
            return
                IERC721Receiver(to).onERC721Received(
                    msg.sender,
                    from,
                    tokenId,
                    _data
                ) == IERC721Receiver.onERC721Received.selector;
        } else {
            return true;
        }
    }

    /**
     * IERC721MetadataのtokenURI関数，metadataを返す
     */
    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
        require(_owners[tokenId] != address(0), &quot;Token Not Exist&quot;);

        string memory baseURI = _baseURI();
        return bytes(baseURI).length &gt; 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : &quot;&quot;;
    }

    /**
     * {tokenURI}のBaseURI。tokenURIはbaseURI、tokenIdをつないでできたもの。
     * 開発者がこの関数を書きかえる
     * 例えばBAYCのbaseURIはipfs://QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq/
     */
    function _baseURI() internal view virtual returns (string memory) {
        return &quot;&quot;;
    }
}
"><code><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-comment">// by 0xAA</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.4;</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">"./IERC165.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./IERC721.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./IERC721Receiver.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./IERC721Metadata.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./Address.sol"</span>;　<span class="hljs-comment">// library</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">"./String.sol"</span>; <span class="hljs-comment">// library</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">IERC721</span>, <span class="hljs-title">IERC721Metadata</span></span>{
    <span class="hljs-keyword">using</span> <span class="hljs-title">Address</span> <span class="hljs-title"><span class="hljs-keyword">for</span></span> <span class="hljs-title"><span class="hljs-keyword">address</span></span>; <span class="hljs-comment">// Address libraryを使う（isContractを使うため）</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">// String library</span>

    <span class="hljs-comment">// Token名</span>
    <span class="hljs-keyword">string</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> name;
    <span class="hljs-comment">// Tokenシンボル</span>
    <span class="hljs-keyword">string</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> symbol;
    <span class="hljs-comment">// tokenId -> owner address のマッピング</span>
    <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">private</span> _owners;
    <span class="hljs-comment">// address -> バランスのマッピング</span>
    <span class="hljs-keyword">mapping</span>(<span class="hljs-keyword">address</span> <span class="hljs-operator">=</span><span class="hljs-operator">></span> <span class="hljs-keyword">uint</span>) <span class="hljs-keyword">private</span> _balances;
    <span class="hljs-comment">// tokenID -> アプルーブされたアドレスのマッピング</span>
    <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">private</span> _tokenApprovals;
    <span class="hljs-comment">//  owner -> operatorアドレス -> bool（権限渡した場合はtrue）</span>
    <span class="hljs-keyword">mapping</span>(<span class="hljs-keyword">address</span> <span class="hljs-operator">=</span><span class="hljs-operator">></span> <span class="hljs-keyword">mapping</span>(<span class="hljs-keyword">address</span> <span class="hljs-operator">=</span><span class="hljs-operator">></span> <span class="hljs-keyword">bool</span>)) <span class="hljs-keyword">private</span> _operatorApprovals;

    <span class="hljs-comment">/**
     * constructor, name, symbolを初期化する
     */</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">// ERC165のsupportsInterface関数</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">supportsInterface</span>(<span class="hljs-params"><span class="hljs-keyword">bytes4</span> interfaceId</span>)
        <span class="hljs-title"><span class="hljs-keyword">external</span></span>
        <span class="hljs-title"><span class="hljs-keyword">pure</span></span>
        <span class="hljs-title"><span class="hljs-keyword">override</span></span>
        <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bool</span></span>)
    </span>{
        <span class="hljs-keyword">return</span>
            interfaceId <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-keyword">type</span>(IERC721).<span class="hljs-built_in">interfaceId</span> <span class="hljs-operator">|</span><span class="hljs-operator">|</span>
            interfaceId <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-keyword">type</span>(IERC165).<span class="hljs-built_in">interfaceId</span> <span class="hljs-operator">|</span><span class="hljs-operator">|</span>
            interfaceId <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-keyword">type</span>(IERC721Metadata).<span class="hljs-built_in">interfaceId</span>;
    }

    <span class="hljs-comment">// IERC721のbalanceOf関数、_balancesを使って調べたいアドレスの残高を返す</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">balanceOf</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> owner</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">override</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-built_in">require</span>(owner <span class="hljs-operator">!</span><span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>), <span class="hljs-string">"owner = zero address"</span>);
        <span class="hljs-keyword">return</span> _balances[owner];
    }

    <span class="hljs-comment">// IERC721のownerOf関数、_owners変数を使ってtokenIdのownerを返す</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ownerOf</span>(<span class="hljs-params"><span class="hljs-keyword">uint</span> tokenId</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">override</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">address</span> owner</span>) </span>{
        owner <span class="hljs-operator">=</span> _owners[tokenId];
        <span class="hljs-built_in">require</span>(owner <span class="hljs-operator">!</span><span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>), <span class="hljs-string">"token doesn't exist"</span>);
    }

    <span class="hljs-comment">// IERC721のisApprovedForAll、_operatorApprovals変数を</span>
    <span class="hljs-comment">// 使ってownerがoperatorに権限を移譲したかどうかをチェックする。</span>
    <span class="hljs-comment">// 権限移譲した場合はtrueを返す</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isApprovedForAll</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> owner, <span class="hljs-keyword">address</span> operator</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">override</span></span>
        <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bool</span></span>)
    </span>{
        <span class="hljs-keyword">return</span> _operatorApprovals[owner][operator];
    }

    <span class="hljs-comment">// IERC721のsetApprovalForAllを実装。持っているトークンをすべてoperatorに権限を渡す(true),</span>
    <span class="hljs-comment">// あるいはoperatorの権限を剥奪する(false)。_setApprovalForAll関数を呼び出す。</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">external</span></span> <span class="hljs-title"><span class="hljs-keyword">override</span></span> </span>{
        _operatorApprovals[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>][operator] <span class="hljs-operator">=</span> approved;
        <span class="hljs-keyword">emit</span> ApprovalForAll(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, operator, approved);
    }

    <span class="hljs-comment">// 实现IERC721的getApproved，利用_tokenApprovals变量查询tokenId的授权地址。</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getApproved</span>(<span class="hljs-params"><span class="hljs-keyword">uint</span> tokenId</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">override</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-built_in">require</span>(_owners[tokenId] <span class="hljs-operator">!</span><span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>), <span class="hljs-string">"token doesn't exist"</span>);
        <span class="hljs-keyword">return</span> _tokenApprovals[tokenId];
    }

    <span class="hljs-comment">// _approve関数。_tokenApprovalsを書き換えて，toアドレスに tokenIdをいじる権限を渡す。</span>
    <span class="hljs-comment">// Approvalイベントを放出。</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_approve</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span> owner,
        <span class="hljs-keyword">address</span> to,
        <span class="hljs-keyword">uint</span> tokenId
    </span>) <span class="hljs-title"><span class="hljs-keyword">private</span></span> </span>{
        _tokenApprovals[tokenId] <span class="hljs-operator">=</span> to;
        <span class="hljs-keyword">emit</span> Approval(owner, to, tokenId);
    }

    <span class="hljs-comment">// IERC721のapprove関数，tokenIdの権限を to アドレスに渡す。</span>
    <span class="hljs-comment">// 条件：toはownerではないこと，かつmsg.senderはownerあるいはapproveされたアドレス。</span>
    <span class="hljs-comment">// _approve関数を呼び出す</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">uint</span> tokenId</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">override</span></span> </span>{
        <span class="hljs-keyword">address</span> owner <span class="hljs-operator">=</span> _owners[tokenId];
        <span class="hljs-built_in">require</span>(
            <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> owner <span class="hljs-operator">|</span><span class="hljs-operator">|</span> _operatorApprovals[owner][<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>],
            <span class="hljs-string">"not owner nor approved for all"</span>
        );
        _approve(owner, to, tokenId);
    }

    <span class="hljs-comment">//  spenderアドレスがtokenIdを使う権限があるかないかを調べる。（あるのはownerか</span>
    <span class="hljs-comment">// approveされたかのいずれだ。approveされた場合は通常のapproveあるいは</span>
    <span class="hljs-comment">// setApprovalForAllの2パターン）</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_isApprovedOrOwner</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span> owner,
        <span class="hljs-keyword">address</span> spender,
        <span class="hljs-keyword">uint</span> tokenId
    </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">bool</span></span>) </span>{
        <span class="hljs-keyword">return</span> (spender <span class="hljs-operator">=</span><span class="hljs-operator">=</span> owner <span class="hljs-operator">|</span><span class="hljs-operator">|</span>
            _tokenApprovals[tokenId] <span class="hljs-operator">=</span><span class="hljs-operator">=</span> spender <span class="hljs-operator">|</span><span class="hljs-operator">|</span>
            _operatorApprovals[owner][spender]);
    }

    <span class="hljs-comment">/*
     * トランスファ関数。_balances、_ownerのバランスを調整して tokenId を from から toに
     * トランスファする。同時にTransferイベントを放出。
     * 前提条件:
     * 1. tokenId は from によって所有されている
     * 2. to はゼロアドレスでない
     * 条件を満たさない場合はrevert
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_transfer</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span> owner,
        <span class="hljs-keyword">address</span> <span class="hljs-keyword">from</span>,
        <span class="hljs-keyword">address</span> to,
        <span class="hljs-keyword">uint</span> tokenId
    </span>) <span class="hljs-title"><span class="hljs-keyword">private</span></span> </span>{
        <span class="hljs-built_in">require</span>(<span class="hljs-keyword">from</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> owner, <span class="hljs-string">"not owner"</span>);
        <span class="hljs-built_in">require</span>(to <span class="hljs-operator">!</span><span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>), <span class="hljs-string">"transfer to the zero address"</span>);

        _approve(owner, <span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>), tokenId); <span class="hljs-comment">// トランスファするので権限をリセットする</span>

        _balances[<span class="hljs-keyword">from</span>] <span class="hljs-operator">-</span><span class="hljs-operator">=</span> <span class="hljs-number">1</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-comment">// IERC721のtransferFrom関数の実装，セーフトランスファではないので、</span>
    <span class="hljs-comment">// この関数を使うのは推奨されていない。</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">uint</span> tokenId
    </span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">override</span></span> </span>{
        <span class="hljs-keyword">address</span> owner <span class="hljs-operator">=</span> ownerOf(tokenId);
        <span class="hljs-built_in">require</span>(
            _isApprovedOrOwner(owner, <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, tokenId),
            <span class="hljs-string">"not owner nor approved"</span>
        );
        _transfer(owner, <span class="hljs-keyword">from</span>, to, tokenId);
    }

    <span class="hljs-comment">/**
     * セーフトランスファ，安全にtokenIdをfromからtoへトランスファする。スマートコントラクトが
     * erc721に対応しているかどうかをチェックした上で、トランスファをするので、NFTが永遠に
     * ロックされる実態を回避する。_transfer、_checkOnERC721Received関数を呼び出す。
     * 条件：
     * from はゼロアドレスではない
     * to はゼロアドレスではない
     * tokenId が存在してしかもfromアドレスが所有
     * toがスマートコントラクトの場合、必ずIERC721Receiver-onERC721Receivedをサポートされる
     * ことが求められる
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_safeTransfer</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span> owner,
        <span class="hljs-keyword">address</span> <span class="hljs-keyword">from</span>,
        <span class="hljs-keyword">address</span> to,
        <span class="hljs-keyword">uint</span> tokenId,
        <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">memory</span> _data
    </span>) <span class="hljs-title"><span class="hljs-keyword">private</span></span> </span>{
        _transfer(owner, <span class="hljs-keyword">from</span>, to, tokenId);
        <span class="hljs-built_in">require</span>(_checkOnERC721Received(<span class="hljs-keyword">from</span>, to, tokenId, _data), <span class="hljs-string">"not ERC721Receiver"</span>);
    }

    <span class="hljs-comment">/**
     * IERC721のsafeTransferFromを実装。セーフトランスファ関数，_safeTransfer関数を呼び出している
     */</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">uint</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">override</span></span> </span>{
        <span class="hljs-keyword">address</span> owner <span class="hljs-operator">=</span> ownerOf(tokenId);
        <span class="hljs-built_in">require</span>(
            _isApprovedOrOwner(owner, <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, tokenId),
            <span class="hljs-string">"not owner nor approved"</span>
        );
        _safeTransfer(owner, <span class="hljs-keyword">from</span>, to, tokenId, _data);
    }

    <span class="hljs-comment">// safeTransferFromのオーバライド関数、引数が違う</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">uint</span> tokenId
    </span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">override</span></span> </span>{
        safeTransferFrom(<span class="hljs-keyword">from</span>, to, tokenId, <span class="hljs-string">""</span>);
    }

    <span class="hljs-comment">/**
     * mint関数。_balances、_ownersのバランスをいじることで、tokenIdをtoへトランスファする。
     * 同時にTransferイベントを放出する。
     * 現在の状態では、誰でもミントできるので、開発者は普通この関数を書き換える
     * 条件:
     * 1. tokenIdがまだ存在しない
     * 2. toはゼロアドレスでない
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_mint</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> to, <span class="hljs-keyword">uint</span> tokenId</span>) <span class="hljs-title"><span class="hljs-keyword">internal</span></span> <span class="hljs-title"><span class="hljs-keyword">virtual</span></span> </span>{
        <span class="hljs-built_in">require</span>(to <span class="hljs-operator">!</span><span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>), <span class="hljs-string">"mint to zero address"</span>);
        <span class="hljs-built_in">require</span>(_owners[tokenId] <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>), <span class="hljs-string">"token already minted"</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">address</span>(<span class="hljs-number">0</span>), to, tokenId);
    }

    <span class="hljs-comment">// バーン関数，_balances、_owners変数を調整してtokenIdをバーンする。同時にTransferイベントを放出</span>
    <span class="hljs-comment">// 条件：tokenId存在。</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_burn</span>(<span class="hljs-params"><span class="hljs-keyword">uint</span> tokenId</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">address</span> owner <span class="hljs-operator">=</span> ownerOf(tokenId);
        <span class="hljs-built_in">require</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> owner, <span class="hljs-string">"not owner of token"</span>);

        _approve(owner, <span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>), tokenId); <span class="hljs-comment">// 権限を更新</span>

        _balances[owner] <span class="hljs-operator">-</span><span class="hljs-operator">=</span> <span class="hljs-number">1</span>;
        <span class="hljs-keyword">delete</span> _owners[tokenId];

        <span class="hljs-keyword">emit</span> Transfer(owner, <span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>), tokenId);
    }

    <span class="hljs-comment">// _checkOnERC721Received：IERC721Receiver-onERC721Received関数, 送り先はERC721互換かどうかをチェックするため</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_checkOnERC721Received</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">uint</span> tokenId,
        <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">memory</span> _data
    </span>) <span class="hljs-title"><span class="hljs-keyword">private</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">if</span> (to.isContract()) {
            <span class="hljs-keyword">return</span>
                IERC721Receiver(to).onERC721Received(
                    <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>,
                    <span class="hljs-keyword">from</span>,
                    tokenId,
                    _data
                ) <span class="hljs-operator">=</span><span class="hljs-operator">=</span> IERC721Receiver.onERC721Received.<span class="hljs-built_in">selector</span>;
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
        }
    }

    <span class="hljs-comment">/**
     * IERC721MetadataのtokenURI関数，metadataを返す
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">tokenURI</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> tokenId</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">override</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span></span>) </span>{
        <span class="hljs-built_in">require</span>(_owners[tokenId] <span class="hljs-operator">!</span><span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>), <span class="hljs-string">"Token Not Exist"</span>);

        <span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span> baseURI <span class="hljs-operator">=</span> _baseURI();
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">bytes</span>(baseURI).<span class="hljs-built_in">length</span> <span class="hljs-operator">></span> <span class="hljs-number">0</span> ? <span class="hljs-keyword">string</span>(<span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encodePacked</span>(baseURI, tokenId.toString())) : <span class="hljs-string">""</span>;
    }

    <span class="hljs-comment">/**
     * {tokenURI}のBaseURI。tokenURIはbaseURI、tokenIdをつないでできたもの。
     * 開発者がこの関数を書きかえる
     * 例えばBAYCのbaseURIはipfs://QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq/
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_baseURI</span>(<span class="hljs-params"></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">string</span> <span class="hljs-keyword">memory</span></span>) </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">""</span>;
    }
}
</code></pre><h2 id="h-free-mint-ape" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">free mint の APE を作ろう</h2><p>それでは、free mint の APE を作りましょうか。totalSupply を 10000 個にして、mint 関数や baseURI を書き換えるだけで済みます。</p><p>baseURI()の設定を BAYS と全く同じようにすることで、BAYC の猿が表示されるはずです。</p><pre data-type="codeBlock" text="
// SPDX-License-Identifier: MIT
// by 0xAA
pragma solidity ^0.8.4;

import &quot;./ERC721.sol&quot;;

contract OmaenoApe is ERC721{
    uint public MAX_APES = 10000; // 総数

    // コンストラクタ
    constructor(string memory name_, string memory symbol_) ERC721(name_, symbol_){
    }

    //BAYCのbaseURIはipfs://QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq/
    function _baseURI() internal pure override returns (string memory) {
        return &quot;ipfs://QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq/&quot;;
    }

    // mint関数
    function mint(address to, uint tokenId) external {
        require(tokenId &gt;= 0 &amp;&amp; tokenId &lt; MAX_APES, &quot;tokenId out of range&quot;);
        _mint(to, tokenId);
    }
}
"><code>
<span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-comment">// by 0xAA</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.4;</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">"./ERC721.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">OmaenoApe</span> <span class="hljs-keyword">is</span> <span class="hljs-title">ERC721</span></span>{
    <span class="hljs-keyword">uint</span> <span class="hljs-keyword">public</span> MAX_APES <span class="hljs-operator">=</span> <span class="hljs-number">10000</span>; <span class="hljs-comment">// 総数</span>

    <span class="hljs-comment">// コンストラクタ</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 class="hljs-title">ERC721</span>(<span class="hljs-params">name_, symbol_</span>)</span>{
    }

    <span class="hljs-comment">//BAYCのbaseURIはipfs://QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq/</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_baseURI</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">internal</span></span> <span class="hljs-title"><span class="hljs-keyword">pure</span></span> <span class="hljs-title"><span class="hljs-keyword">override</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span></span>) </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">"ipfs://QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq/"</span>;
    }

    <span class="hljs-comment">// mint関数</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">mint</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> to, <span class="hljs-keyword">uint</span> tokenId</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>{
        <span class="hljs-built_in">require</span>(tokenId <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> tokenId <span class="hljs-operator">&#x3C;</span> MAX_APES, <span class="hljs-string">"tokenId out of range"</span>);
        _mint(to, tokenId);
    }
}
</code></pre><p>それでは remix を開いてコードを書きましょう。</p><h2 id="h-erc721" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">ERC721 を発行しよう</h2><p>ERC721 スタンダードがあれば、ブロックチェーンにて NFT を発行することは非常にシンプルになります。 今、上記のコードができたので、remix にて発行しましょう。</p><p>実際の手順はまたの機会で書きます。</p><h2 id="h-erc165-erc721" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">ERC165 と ERC721</h2><p>NFT を NFT についてコントロールできないコントラクトへ送付してしまうと、永遠に消失してしまうため、これを防ぐために<code>ERC721TokenReceiver</code>インターフェイスの実装が求められます。</p><pre data-type="codeBlock" text="interface ERC721TokenReceiver {
    function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes _data) external returns(bytes4);
}
"><code><span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">ERC721TokenReceiver</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">onERC721Received</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _operator, <span class="hljs-keyword">address</span> _from, <span class="hljs-keyword">uint256</span> _tokenId, <span class="hljs-keyword">bytes</span> _data</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span>(<span class="hljs-params"><span class="hljs-keyword">bytes4</span></span>)</span>;
}
</code></pre><p>実はこのインターフェイスとは、この <code>onERC721REceived</code> 関数のことです。この関数を実装していれば、NFT を処理する能力があるという宣言になります。</p><p><strong>THE END</strong></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure>]]></content:encoded>
            <author>thurendous@newsletter.paragraph.com (thurendous)</author>
        </item>
        <item>
            <title><![CDATA[EVM ディープダイブ - super coder への道 🥷 💻Part 2 | Hello Web3]]></title>
            <link>https://paragraph.com/@thurendous/evm-super-coder-part-2-hello-web3</link>
            <guid>FDaBGE3gAhiaukOs1TnN</guid>
            <pubDate>Sun, 14 May 2023 04:42:26 GMT</pubDate>
            <description><![CDATA[Hello, everybody!Never Give Up以前書いた時から、EVM について理解できてきているので、当時は読みづらかった技術系の文章もすらすら読めるようになりました。そこで EVM のことあるいは他のなにかで頑張っているあなたももしかして何かができずに悩んでいるのかもしれません。 ここで行っておきますが、僕もそうだったので、安心してください。そのうち理解できるようになるだろう。 ちなみに、こちらの画像をみてごらん。 本当に経験した人しかわからないと思いますし、経験したとしてももう一度経験すると、やはり信じられない気持ちになると思うよね。 何がどうなっても、続けることが一番大切。遅くてもいい理想と現実「続けてても意味ない」最初の第一歩が一番むずいけどね三日坊主 VS 続ける今回は、メモリーについて説明する。 Part 1 では、EVM がどのようにバイトコードのどこを狙って run させるかを見てきた。 それは、外部の calldata を入力してきてコントラクトのどの関数を呼んでいるかを判別して run すべきバイトコードの箇所を決めていることがわかった。 これ...]]></description>
            <content:encoded><![CDATA[<p>Hello, everybody!</p><h2 id="h-never-give-up" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Never Give Up</h2><p>以前書いた時から、EVM について理解できてきているので、当時は読みづらかった技術系の文章もすらすら読めるようになりました。そこで EVM のことあるいは他のなにかで頑張っているあなたももしかして何かができずに悩んでいるのかもしれません。</p><p>ここで行っておきますが、僕もそうだったので、安心してください。そのうち理解できるようになるだろう。</p><p>ちなみに、こちらの画像をみてごらん。</p><p>本当に経験した人しかわからないと思いますし、経験したとしてももう一度経験すると、やはり信じられない気持ちになると思うよね。</p><p>何がどうなっても、続けることが一番大切。</p><ul><li><p>遅くてもいい</p></li></ul><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><ul><li><p>理想と現実</p></li></ul><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><ul><li><p>「続けてても意味ない」</p></li></ul><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><ul><li><p>最初の第一歩が一番むずいけどね</p></li></ul><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><ul><li><p>三日坊主 VS 続ける</p></li></ul><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><hr><p>今回は、メモリーについて説明する。</p><p>Part 1 では、EVM がどのようにバイトコードのどこを狙って run させるかを見てきた。 それは、外部の calldata を入力してきてコントラクトのどの関数を呼んでいるかを判別して run すべきバイトコードの箇所を決めていることがわかった。</p><p>これを理解することで、関数の署名・call stack・calldata・EVM のオペコード について理解が進んだと思う。</p><p>Part 2 では、EVM におけるメモリーについて色々見ていこう。</p><h2 id="h-memory" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Memory</h2><p>Part1 のコードを思いだしてみて。<code>1_Storage.sol</code>というコントラクトがあった。</p><pre data-type="codeBlock" text="pragma solidity &gt;=0.7.0 &lt;0.9.0;

contract Storage {
    uint256 number;

    function store(uint256 num) public {
        number = num;
    }

    function retrieve() public view returns (uint256) {
        return number;
    }
}
"><code><span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> >=0.7.0 &#x3C;0.9.0;</span>

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Storage</span> </span>{
    <span class="hljs-keyword">uint256</span> number;

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">store</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> num</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        number <span class="hljs-operator">=</span> num;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">retrieve</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span></span>) </span>{
        <span class="hljs-keyword">return</span> number;
    }
}
</code></pre><p>これのバイトコードを生成すると、こうなっている。</p><pre data-type="codeBlock" text="608060405234801561001057600080fd....
"><code>608060405234801561001057600080fd....
</code></pre><p>今回はこの部分にフォーカスして説明したいと思う。一番最初の 5bytes だ。</p><pre data-type="codeBlock" text="60 80                       =   PUSH1 0x80
60 40                       =   PUSH1 0x40
52                          =   MSTORE
"><code>60 <span class="hljs-attr">80</span>                       =   PUSH1 <span class="hljs-number">0</span>x80
60 <span class="hljs-attr">40</span>                       =   PUSH1 <span class="hljs-number">0</span>x40
<span class="hljs-attr">52</span>                          =   MSTORE
</code></pre><p>これが聞いたことあるがかもしれないけど、いわゆる「free memory pointer」だ。</p><p>これを理解するには、まずはコントラクトのメモリーを理解しなければならない。</p><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">メモリのデータ構造</h2><p>コントラクトのメモリはシンプルにいうと、byte の array だ。32bytes(256bit)あるいは 1byte(8bit)の単位として保存される。読まれるときには、32bytes(256bit)単位ごとになる。下記の画像は話した内容を具現化したもの。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>この機能は３つの opcode に左右されている。</p><ul><li><p><code>MSTORE(x, y)</code>: 32 byte(256 bit) の値 y をメモリのロケーションの x に保存</p></li><li><p><code>MLOAD(x)</code>: 32 byte(256 bit) のメモリの場所をロケーション x から読み出し、スタックに入れる</p></li><li><p><code>MSOTRE8(x, y)</code>: 1 byte (8 bit)の値 y をメモリロケーションの x に保存する</p></li></ul><p>メモリロケーションのことはどこからメモリを読み取る/書き込むかを決めていると考えてよい。もし、1byte より多く読み取る/書き込むことをしたいのであれば、そのまま継続すればよいだけの話になる。</p><h2 id="h-evm-playground" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">EVM playground</h2><p>この <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.evm.codes/playground?fork=shanghai">EVM playground</a> はあなたの理解の手助けができるだろう。Run をクリックして、右上の矢印をクリックしてみよう。矢印ボタンはコードの稼働プロセスをたどっていってくれる。スタック、メモリはどうなっているのかもわかる。すごく直感的なツールだと感心する。</p><pre data-type="codeBlock" text="// MSTORE 32 bytes 0x11...1 at memory location 0
PUSH32 0x1111111111111111111111111111111111111111111111111111111111111111
PUSH1 0x00
MSTORE

// MSTORE8 1 byte 0x22 at memory location 32 (0x20 in hex)
PUSH1 0x22
PUSH1 0x20
MSTORE8

// MSTORE8 1 byte 0x33 at memory location 33 (0x21 in hex)
PUSH1 0x33
PUSH1 0x21
MSTORE8

// MLOAD 32 bytes to the call stack from memory location 0 ie 0-32 bytes of memory
PUSH1 0x00
MLOAD

// MLOAD 32 bytes to the call stack from memory location 32 ie 32-64 bytes of memory
PUSH1 0x20
MLOAD

// MLOAD 32 to the call stack from memory location 33 ie 33-65 bytes of memory
PUSH1 0x21
MLOAD
"><code><span class="hljs-comment">// MSTORE 32 bytes 0x11...1 at memory location 0</span>
PUSH32 <span class="hljs-number">0x1111111111111111111111111111111111111111111111111111111111111111</span>
PUSH1 <span class="hljs-number">0x00</span>
MSTORE

<span class="hljs-comment">// MSTORE8 1 byte 0x22 at memory location 32 (0x20 in hex)</span>
PUSH1 <span class="hljs-number">0x22</span>
PUSH1 <span class="hljs-number">0x20</span>
MSTORE8

<span class="hljs-comment">// MSTORE8 1 byte 0x33 at memory location 33 (0x21 in hex)</span>
PUSH1 <span class="hljs-number">0x33</span>
PUSH1 <span class="hljs-number">0x21</span>
MSTORE8

<span class="hljs-comment">// MLOAD 32 bytes to the call stack from memory location 0 ie 0-32 bytes of memory</span>
PUSH1 <span class="hljs-number">0x00</span>
MLOAD

<span class="hljs-comment">// MLOAD 32 bytes to the call stack from memory location 32 ie 32-64 bytes of memory</span>
PUSH1 <span class="hljs-number">0x20</span>
MLOAD

<span class="hljs-comment">// MLOAD 32 to the call stack from memory location 33 ie 33-65 bytes of memory</span>
PUSH1 <span class="hljs-number">0x21</span>
MLOAD
</code></pre><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/650a7edd3a39f16a2960fcb49fd898e5ae8c3eca5e8ea911b50418586b31a9d7.webp" 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>opcode についても、英語だが説明文がついている。</p><p>やってみて変だなと思うことはないのか？ まず、MSTORE8 を使って 1 byte の 0x22 をメモリの 0x20 に書き込んでいるつもりだが、何故かメモリはここから、</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/0b1fd645f91f726bd2c57ed8ab9fe8b92b7549a2362c15b7aab2d891c9c37ac5.webp" 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>こう変わるんだ。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/0282dcac7d6fdbfb8d0da5492e3f7004f5af8af16f4bc48ebe7178ce7d3e5c9f.webp" 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>この余分なゼロってなんだと思うだろう。</p><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">メモリの拡張​</h2><p>コントラクトがメモリへなにかを書き込む際、byte 数に従ってガス代を支払っている。これが opcode のコストと言う。もし、これまでメモリへ書き込んだことがない場所へ書き込む場合、追加的にメモリ拡張のコストがかかる。</p><p>これまで書き込んだことがない箇所へ書き込む場合、メモリは 32bytes(256bit)拡張されることになる。</p><blockquote><p>メモリのコストの増え方に関しては、最初の 724bytes は線形的に増加するが、それ以降は二次指数関数的になる。</p></blockquote><p>上の例では、まず 0x00 のロケーションへ 32 bytes 書き込んだが、そこからさらに書き込むとなると、メモリ拡張をしなければならず、結果的に、メモリは 64 bytes になった。</p><p>メモリにある保存領域の最初のデフォルト値はゼロ。だから 2200000000000000000000000000000000000000000000000000000000000000 がメモリに追加された。</p><h2 id="h-byte-array" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">メモリは byte の Array だから​</h2><p>次に注意しないといけないのは、メモリロケーションの 33(0x21)から MLOAD したときに、下記の値が返された。</p><pre data-type="codeBlock" text="3300000000000000000000000000000000000000000000000000000000000000
"><code></code></pre><p>32 bytes ずつ読み込んでいなくても、読み込めるということであった。</p><p>memory はただの byte array なので、どこの場所からでも読み込めることを覚えて下さい。32bytes の制限は特になく、どこからでも byte 単位から読み込める。</p><blockquote><p>関数内でのみ新たにメモリを作成することができます。それは新たにインスタンス化された複雑な型（例えば <code>new int[...]</code> など）であったり、ストレージ参照変数からコピーされたものであったりします。</p></blockquote><p>現在、我々はデータ構造について理解できたので、free memory の話へ戻ろう。</p><h2 id="h-free-memory-pointer" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Free Memory Pointer</h2><p>Free Memory Pointer とは、簡単にいうとメモリロケーションのポインターであり、Free Memory がどこからスタートすべきなのかを記録している。言い換えると、メモリのロケーションはどこまで書き込まれていて、どこから書き込むべきなのかを記録している。</p><p>これはコントラクトがメモリを上書きするのを防ぐためでもある。</p><p>変数がメモリへ書き込むときに、コントラクトはまず Free Memory Pointer を参照し、どこから書き込むべきかを決めないといけない。それから Free Memory Pointer をアップデートし、最新のメモリの「境界値」あるいは「オフセット」を記録する。</p><pre data-type="codeBlock" text="  newFreeMemoryPointer = freeMemoryPointer + dataSizeBytes
"><code>  <span class="hljs-attr">newFreeMemoryPointer</span> = freeMemoryPointer + dataSizeBytes
</code></pre><h2 id="h-bytecode" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Bytecode​</h2><p>先程にも言及したように、Free Memory Pointer は最初の runtime bytecode のこの部分によって定義される。</p><pre data-type="codeBlock" text="60 80                       =   PUSH1 0x80
60 40                       =   PUSH1 0x40
52                          =   MSTORE
"><code>60 <span class="hljs-attr">80</span>                       =   PUSH1 <span class="hljs-number">0</span>x80
60 <span class="hljs-attr">40</span>                       =   PUSH1 <span class="hljs-number">0</span>x40
<span class="hljs-attr">52</span>                          =   MSTORE
</code></pre><p>これは基本的に何を言っているかというと、Free Memory Pointer はメモリロケーションの 0x40(64 in decimal)で、値は 0x80(128 in decimal)となる。</p><p>すぐに疑問に思うのは、なぜこの数字なのということだろう。</p><p>答え：</p><blockquote><p>0x00 - 0x3f (64 bytes): scratch space</p><p>0x40 - 0x5f (32 bytes): free memory pointer</p><p>0x60 - 0x7f (32 bytes): zero slot</p></blockquote><p>0x40 は solidity が定義した一番最初の Free Memory Pointer のメモリロケーションだ。値 0x80 は単に最初の 4 つの 32 bytes のポジションを記録している。</p><p>これらの予約されたメモリについて</p><ul><li><p>Scrach space: inline assembly のハッシングメソッドとして使っても良い</p></li><li><p>Free memroy pointer: 今のメモリのサイズ、free memory のスタートロケーション、最初は 0x80</p></li><li><p>The zero slot: 動的な Memory Array の初期値であり、どんなときにでも書き込まれることはない</p></li></ul><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">コントラクトのメモリ</h2><p>リアルなコントラクトのメモリについて見ていくとしようか。</p><p>非常にシンプルなコントラクトを作成した。こいつの名は <code>MemoryLane</code>。たった一個の関数を持っており、２つの Array を持っている。それから b[0]に値 1 を付与する。</p><p>3 行程度のコードだけど、かなり多くのことが起きているよ。</p><pre data-type="codeBlock" text="// SPDX-License-Identifier: MIT

pragma solidity ^0.8.3;

contract MemoryLane {
    function memoryLane() public pure {
        bytes32[5] memory a;
        bytes32[5] memory b;
        b[0] = bytes32(uint256(1));
    }
}
"><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.3;</span>

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">MemoryLane</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">memoryLane</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">pure</span></span> </span>{
        <span class="hljs-keyword">bytes32</span>[<span class="hljs-number">5</span>] <span class="hljs-keyword">memory</span> a;
        <span class="hljs-keyword">bytes32</span>[<span class="hljs-number">5</span>] <span class="hljs-keyword">memory</span> b;
        b[<span class="hljs-number">0</span>] <span class="hljs-operator">=</span> <span class="hljs-keyword">bytes32</span>(<span class="hljs-keyword">uint256</span>(<span class="hljs-number">1</span>));
    }
}
</code></pre><p>上記のコードをもう一度 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://remix.ethereum.org/">remix</a> へ投入。</p><p>それから、コンパイルし、デプロイしてください。</p><p><code>memoryLane()</code>関数を run して、debugging mode へ入ってください。</p><p>opcode を少しずつ見ていこう。</p><p>少し簡単なバージョンを<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.evm.codes/playground?unit=Wei&amp;codeType=Mnemonic&amp;code=%27Vg*%28_I...1W0GJ_%21%21%21%21z00FK22WJQ0Y22z20F8K33W33Q1Y33z21F8d%28v0Z0-Jq00Xd%28vJZJ-64q20Xdv33Z33-65q21Xpp%27%7EN+locatioCzG1_wppVv7o7hBcall+stack+from%7EuIIIIq%28+ofNzp%5Cnj+bytegSTOREdw%29*_+0xZ9BY9Chex%7DzXpM%29W+at%7EV%2F%2F+MQ+%7B0x2N+memoryKwg8+1j_J32I11GpPUSHFpMgCn+Be+9+i7+t*+J%29LOAD%28js%21uu%01%21%28%29*79BCFGIJKNQVWXYZ_dgjpquvwz%7E_&amp;fork=shanghai">EVM playground</a>へ入れている。その opcode はそのようになっている。</p><p>この簡単なバージョンは opcode を順番に構成し、JUMP などのメモリ操作と関連しないことを除外した。いろいろコメントもしているので、参照してほしい。</p><p>このコードは 6 部分から構成されていて、これから dive in する。</p><p>play ground を使うことを強くおすすめする。</p><h2 id="h-free-memory-pointer-initialisation-evm-playground-lines-1-15" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Free Memory Pointer Initialisation (EVM Playground Lines 1-15)</h2><p>まず、“free memory pointer initialisation”からやっていく。上記でもあったように、0x80(128 in decimal)をスタックに入れる。これは free memory pointer の値として保存される。Solidity の memory のレイアウトを決めている。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>この段階では、まだメモリにはなにもない。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>続いて free memory pointer のロケーションの 0x40(64 in decimal)をプッシュする。</p><p>最後に、MSTORE を使って、0x40 ロケーションに 0x80 の値を記録。</p><p>この後、スタックには何もなく、メモリになにかを残せたことになる。メモリは 16 進数になっており、数字ごとに 4bit のデータを記録している。</p><p>今となって、192 の 16 進数の数字となっている（数字 2 桁 = 1 byte = 8 bit）。</p><p>先程の内容を思い出してください。最初の 64bytes は scrach space で、次の 32bytes は free memory pointer になる。これはまさに下記の状態。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><h2 id="h-memory-allocation-variable-a-and-free-memory-pointer-update-evm-playground-lines-16-34" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Memory Allocation Variable “a” &amp; Free Memory Pointer Update (EVM Playground Lines 16-34)</h2><p>残りの部分については、簡単にするために一旦最後の飛ばしてハイレベルの概要を見てみよう。</p><p>次のメモリに関して、変数<code>a</code>(bytes32[5])のことを配置して free memory pointer をアップデートするということをしなければならないのがわかる。</p><p>コンパイラは array size によってどれくらいのスペースが必要か決定する。</p><blockquote><p>メモリ array の要素の占める領域は 32 bytes の倍数になる。これは <code>bytes1[]</code>に対しても通用する。ただし、<code>bytes</code> や <code>string</code> は違う。</p></blockquote><p>array のサイズ ×32bytes でどれくらいのメモリを食うかわかる。</p><p>この場合、5 * 32 bytes で、0xa0 (160)になるのだ。したがってその値は stack にプッシュされ、現在の free memory pointer に保存された。</p><p>この後、前の free memory pointer の値と足し算をして、値 0x120 (288)が生成された。この値が free memory pointer に保存された。</p><p>stack には変数<code>a</code>メモリをロケーション 0x80 にキープして後から参照できるようにしている。<code>0xffff</code>は JUMP のロケーションを意味しており、関係ないので当面は無視してよい(stack の underflow を防ぐためにある)。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><h2 id="h-memory-initialisation-variable-a-evm-playground-lines-35-95" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Memory Initialisation Variable “a” (EVM Playground Lines 35-95)</h2><p>今ではメモリに保存されて free memory pointer がアップデートされた。ここからは変数<code>a</code>のメモリにおける初期化をする。変数は宣言されて値代入していないので、ゼロ値になっているはず。</p><p>これをするためには、EVM の CALLDATACOPY を使って実施する。この opcode は３つの引数が必要：</p><ul><li><p>memoryOffset（メモリロケーションへコピーする場所）</p></li><li><p>calldataOffset（calldata における byte offset のこと）</p></li><li><p>size（コピーする byte size）</p></li></ul><p>今回の場合、memoryOffset は<code>a</code>のメモリロケーション 0x80。</p><p>calldataOffset は実際の calldata のサイズ、なぜならそもそも calldata の copy がいらない。メモリをゼロ値で初期化したい。結果的にサイズが 0xa0 あるいは 160 bytes になる。</p><p>ここで、メモリが 288 bytes になったとわかる(zero slot も含めて)。stack は今もう一度変数のメモリロケーションと JUMP ロケーションを持っている状態。</p><p>（その間に細かい操作については、何度も pop しているのがあるが、個人的にはまだなぞで、わかる方なら教えて下さい）</p><h2 id="h-memory-allocation-variable-b-and-free-memory-pointer-update-evm-playground-lines-96-112" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Memory Allocation Variable “b” &amp; Free Memory Pointer Update (EVM Playground Lines 96-112)</h2><p>ここでの操作は上記の流れと非常に似ているが、ただし、今回は<code>bytes32[2] memory b</code>となる。</p><p>free memory pointer を 0x160(352 in decimal)にアップデートする(前の free memory pointer 288 + 新しい変数のサイズ 64 bytes)。</p><p>注意としては、free memory pointer はメモリにて 0x160 にアップデートされ、そこで現在は変数<code>b</code>のメモリロケーション(0x120)をスタックに入れてある。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><h2 id="h-memory-initialisation-variable-b-evm-playground-lines-113-162" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Memory Initialisation Variable “b” (EVM Playground Lines 113-162)</h2><p>続いて変数<code>b</code>初期化について説明する。</p><p>現在、メモリは 352bytes へ拡張された。スタックにはメモリロケーションを 2 個持っている。</p><h2 id="h-assign-value-to-b0-evm-playground-lines-163-207" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Assign Value to <code>b[0]</code> (EVM Playground Lines 163-207)</h2><p>やっと最後の段階に来れた。正直にいって難しかった。</p><p>ここでは、array <code>b</code> の index <code>0</code>に値を付与したい。</p><p>コードでは b[0] = 1 となっている。</p><p>まず、この値が stack に突っ込まれる。その後、bit shift が起きるが、これ移動したのは 0 で何も変わりはないことを意味する。</p><p>次に array の index には 0x00 へ書き込まれ、0 positon へ書き込むことを意味する。その際に、array length の 2 を超えていないことをチェック。もし条件をクリアできない場合、異なるバイトコードのポジションへ飛び、エラーハンドリングの部分へ飛ばされる。</p><p>MUL、ADD opcode はメモリいにおいて値が書き込まれる場所を決めている。</p><pre data-type="codeBlock" text="0x20 (32 in decimal) * 0x00 (0 in decimal) = 0x00
"><code><span class="hljs-number">0x20</span> (<span class="hljs-number">32</span> <span class="hljs-keyword">in</span> <span class="hljs-built_in">decimal</span>) * <span class="hljs-number">0x00</span> (<span class="hljs-number">0</span> <span class="hljs-keyword">in</span> <span class="hljs-built_in">decimal</span>) = <span class="hljs-number">0x00</span>
</code></pre><p>メモリの array は 32 byte 単位であることを思い出してほしい。こちらは 0x00 になるので、offset は不要でそのまま 0 のポジションから書着込む。</p><pre data-type="codeBlock" text="0x00 + 0x120 = 0x120 (288 in decimal)
"><code>0x00 + <span class="hljs-attr">0x120</span> = <span class="hljs-number">0</span>x120 (<span class="hljs-number">288</span> in decimal)
</code></pre><p>ADD は offset の値をメモリにある変数 b のロケーションを定義するように使われた。offset は今回 0 なので、そのまま、free memory pointer の位置に書き込むこととなる。</p><p>一番最後に、MSTORE を使って値 0x01 をメモリロケーションの 0x120 へ書き込む。そして、スタックにあるすべての要素を pop し、終了。</p><p>これでメモリは<code>b[0] = 1</code>となっている。下から 3 行目のところに 1 という数字が入っているのがわかる。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>今回の記事はここまで！Bye！</p><h2 id="h-reference" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Reference​</h2><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://noxx.substack.com/p/evm-deep-dives-the-path-to-shadowy-d6b?s=r">https://noxx.substack.com/p/evm-deep-dives-the-path-to-shadowy-d6b?s=r</a></p>]]></content:encoded>
            <author>thurendous@newsletter.paragraph.com (thurendous)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/4a6e46ab96c8433c8df450687c2174350bbb25be50838362a2fe6b62a1717a92.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[CEIとは : Checks Effects Interactions]]></title>
            <link>https://paragraph.com/@thurendous/cei-checks-effects-interactions</link>
            <guid>97oPJrTzHQ3KbG8hqSQu</guid>
            <pubDate>Wed, 10 May 2023 16:34:21 GMT</pubDate>
            <description><![CDATA[EVM のインタラクションについては、外部のコントラクトを呼び出すときに、主導権は全部外部のコントラクトが握ることとなり、危険がケースがある。もしその外部のコントラクトは悪意のあるコントラクトの場合、悪用されるリスクにさらされる。マネープリントEVM(Ethereum Virtual Machine) の世界では、Re-entrancy の攻撃というのがある。 まさにこの攻撃手法が取られることがある。 攻撃のコントラクトはコントラクトに何度も入り込んで、チェックする条件が反映される前になんども同じ操作をされてしまうというやり口である。本来なら一度のみ呼ばれるものが何度もチェックを抜けて呼ばれると予期しない挙動になったりして、資産が盗まれたりする。 この攻撃手法は昔の The DAO 事件がやられた手法でもある。歴史に残る大事件だ。 他のソフトウェア環境では起こらないよう脆弱性だ。これは新しい開発者だとやりがちなミスになる。 このような状況において、Checks-Effects-Interactions を適用してください。外部のコントラクトを呼び出すのは避けられないRe-entr...]]></description>
            <content:encoded><![CDATA[<p>EVM のインタラクションについては、外部のコントラクトを呼び出すときに、主導権は全部外部のコントラクトが握ることとなり、危険がケースがある。もしその外部のコントラクトは悪意のあるコントラクトの場合、悪用されるリスクにさらされる。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/593b08a587527cb60aa00512667fc84a50d55a02fabb06ed644ad1b610211ed7.png" alt="マネープリント" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">マネープリント</figcaption></figure><p>EVM(Ethereum Virtual Machine) の世界では、Re-entrancy の攻撃というのがある。</p><p>まさにこの攻撃手法が取られることがある。</p><p>攻撃のコントラクトはコントラクトに何度も入り込んで、チェックする条件が反映される前になんども同じ操作をされてしまうというやり口である。本来なら一度のみ呼ばれるものが何度もチェックを抜けて呼ばれると予期しない挙動になったりして、資産が盗まれたりする。</p><p>この攻撃手法は昔の <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.gemini.com/cryptopedia/the-dao-hack-makerdao">The DAO 事件</a>がやられた手法でもある。歴史に残る大事件だ。</p><p>他のソフトウェア環境では起こらないよう脆弱性だ。これは新しい開発者だとやりがちなミスになる。</p><p>このような状況において、Checks-Effects-Interactions を適用してください。</p><ul><li><p>外部のコントラクトを呼び出すのは避けられない</p></li><li><p>Re-entrancy 攻撃を避けたい</p></li></ul><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">実装</h2><ul><li><p>まず、check</p></li></ul><p>関数を呼び出してまず実行する条件をチェック（例えば十分な資金をもっているか）。</p><ul><li><p>次、effect</p></li></ul><p>その次にすべての状態変数を更新すべき</p><ul><li><p>最後、interaction</p></li></ul><p>最後に外部のコントラクトとのインタラクションをすべき。内部の状態が完全に更新された後に、初めて外部のコントラクトを呼び出す。</p><p>この順番さえ守れば、Re-entrancy 攻撃は最初の関門をくぐりぬけれなくなります。</p><p>もし、最後に状態の変更をするとなると、状態変更される前に何回も同じ関数の部分が呼び出されてしまい、Re-entrancy 攻撃の罠にハマってしまう。</p><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">実例</h2><pre data-type="codeBlock" text="pragma solidity 0.8.13;


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

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

    function withdraw() public payable{
        require(balances[msg.sender] &gt; 0, &quot;Insufficiant balance&quot;);
        payable(msg.sender).call{value: balances[msg.sender]}(&quot;&quot;);
        balances[msg.sender] = 0;
    }

    function updateContractBalance() public{
        contractBalance = address(this).balance;
    }
}
"><code><span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> 0.8.13;</span>


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

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

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">withdraw</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span></span>{
        <span class="hljs-built_in">require</span>(balances[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">></span> <span class="hljs-number">0</span>, <span class="hljs-string">"Insufficiant balance"</span>);
        <span class="hljs-keyword">payable</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>).<span class="hljs-built_in">call</span>{<span class="hljs-built_in">value</span>: balances[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>]}(<span class="hljs-string">""</span>);
        balances[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">=</span> <span class="hljs-number">0</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updateContractBalance</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span></span>{
        contractBalance <span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>).<span class="hljs-built_in">balance</span>;
    }
}
</code></pre><p>このコードは一見して大丈夫なように見えるが、<code>withdraw()</code>関数の 2 行目に十分な資産があるかを確認している。次にアセットをユーザーへ送付している。最後にバランスを更新している。</p><p>これは check-effect-interaction のルールを守っていない。</p><ul><li><p>check: <code>require(balances[msg.sender] &gt; 0, &quot;Insufficiant balance&quot;);</code></p></li><li><p>interaction: <code>payable(msg.sender).call{value: balances[msg.sender]}(&quot;&quot;);</code></p></li><li><p>effect: <code>balances[msg.sender] = 0;</code></p></li></ul><p>となっており、effect と interaction の順番が逆。</p><p>その結果、Re-entrancy 攻撃が可能となる。</p><p>具体的なスキームはこのような感じ：</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/88e30e577ccbfb5eef0d626da2b0567538b1977100f4efe35375f4a9aebb1daf.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>adjust funds の前に、何回も何回も資産が抜き出されて、最後に資金が底をつくことになるだろう。</p><p>Attacker のコードは以下：</p><pre data-type="codeBlock" text="pragma solidity 0.8.13;


contract reentrancyAttack{

    address public victim;
    uint256 public amount;
    uint256 public counter;

    constructor(address _victim) payable{
        victim = _victim;
        amount = msg.value;
    }

    receive() external payable{ // イーサ受け取り用のreceive関数
        counter++;
        attack();
    }

    function payIn() public returns (bool success){
        (bool success, bytes memory data) = payable(victim).call{value: amount}(abi.encodeWithSignature(&quot;payIn()&quot;));
    }

    function withdrawAttack() public{
        if(counter &lt; 4){
            // もう一度withdrawを呼ぶ用
            payable(victim).call(abi.encodeWithSignature(&quot;withdraw()&quot;));
        }
    }
}
"><code><span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> 0.8.13;</span>


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

    <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> victim;
    <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">public</span> amount;
    <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">public</span> counter;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _victim</span>) <span class="hljs-title"><span class="hljs-keyword">payable</span></span></span>{
        victim <span class="hljs-operator">=</span> _victim;
        amount <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">receive</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span></span>{ <span class="hljs-comment">// イーサ受け取り用のreceive関数</span>
        counter<span class="hljs-operator">+</span><span class="hljs-operator">+</span>;
        attack();
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">payIn</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bool</span> success</span>)</span>{
        (<span class="hljs-keyword">bool</span> success, <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">memory</span> data) <span class="hljs-operator">=</span> <span class="hljs-keyword">payable</span>(victim).<span class="hljs-built_in">call</span>{<span class="hljs-built_in">value</span>: amount}(<span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encodeWithSignature</span>(<span class="hljs-string">"payIn()"</span>));
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">withdrawAttack</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span></span>{
        <span class="hljs-keyword">if</span>(counter <span class="hljs-operator">&#x3C;</span> <span class="hljs-number">4</span>){
            <span class="hljs-comment">// もう一度withdrawを呼ぶ用</span>
            <span class="hljs-keyword">payable</span>(victim).<span class="hljs-built_in">call</span>(<span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encodeWithSignature</span>(<span class="hljs-string">"withdraw()"</span>));
        }
    }
}
</code></pre><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">ソリューション</h3><p>その対策としては、実はものすごくシンプルに<code>withdraw()</code>の第 3, 4 行を逆転させて、修正を加える。</p><pre data-type="codeBlock" text=" function withdraw() public payable{
    // check
    require(balances[msg.sender] &gt; 0, &quot;Insufficiant balance&quot;);
    // effect
    uint256 payBalance = balances[msg.sender];
    balances[msg.sender] = 0;
    // interaction
    (bool success, bytes memory data) = payable(msg.sender).call{value: payBalance}(&quot;&quot;);
        if(!success){ // catch the case where the send was unsuccesful
            balances[msg.sender] = payBalance;
        }
}
"><code> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">withdraw</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span></span>{
    <span class="hljs-comment">// check</span>
    <span class="hljs-built_in">require</span>(balances[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">></span> <span class="hljs-number">0</span>, <span class="hljs-string">"Insufficiant balance"</span>);
    <span class="hljs-comment">// effect</span>
    <span class="hljs-keyword">uint256</span> payBalance <span class="hljs-operator">=</span> balances[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>];
    balances[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">=</span> <span class="hljs-number">0</span>;
    <span class="hljs-comment">// interaction</span>
    (<span class="hljs-keyword">bool</span> success, <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">memory</span> data) <span class="hljs-operator">=</span> <span class="hljs-keyword">payable</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>).<span class="hljs-built_in">call</span>{<span class="hljs-built_in">value</span>: payBalance}(<span class="hljs-string">""</span>);
        <span class="hljs-keyword">if</span>(<span class="hljs-operator">!</span>success){ <span class="hljs-comment">// catch the case where the send was unsuccesful</span>
            balances[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">=</span> payBalance;
        }
}
</code></pre><p>もし、success が false の場合、バランスを元通りに戻す操作をしている。 <code>// interaction</code> の行において re-enterancy されても、すでにバランスはゼロなので、revert されて問題がない。</p><p>普段私は主にこちらのサイトに記事をパブリッシュしています。よかったら見てみてね。</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://omaeno.xyz/blog/EVM-deep-dive-part1">https://omaeno.xyz/blog/EVM-deep-dive-part1</a></p><p>それでは、Bye!</p><p><strong>THE END</strong></p>]]></content:encoded>
            <author>thurendous@newsletter.paragraph.com (thurendous)</author>
        </item>
        <item>
            <title><![CDATA[EVM ディープダイブ - super coder への道 🥷 💻Part 1]]></title>
            <link>https://paragraph.com/@thurendous/evm-super-coder-part-1</link>
            <guid>CsPGfUEPZ0gvFIfDu2eR</guid>
            <pubDate>Tue, 09 May 2023 14:26:46 GMT</pubDate>
            <description><![CDATA[First Principle という言葉を耳にされたことはないだろうか。それは奥深く物事の基礎を理解した上で、よりよい発想を生まれることをいっている概念だ。 スマートコントラクトの世界では、EVM とその周りにあるアルゴリズム、データ構造に関しては、まさにこの First Principle である。Solidity あるいはスマートコントラクトはこの基礎の上に作る構造物なのだ。EVM のことを理解せずにはグレートな solidity dev と称するにはまだ早いと言ってよいだろう。基礎：Solidity → Bytecode → Opcodeまず、基礎的な部分について一定程度の知識を有することを前提としている。おさらい：Bytecode & ABI: バイトコードとは EVM 上で実行可能なコードで、ABI とはこの EVM バイトコードとやり取りができるための interface。Solidity コードはまずバイトコードへコンパイルしてから、イーサリアムブロックチェーンへ乗せるという流れになる。バイトコードは実は色々なオペコードを意味している。今回は基本的な solidi...]]></description>
            <content:encoded><![CDATA[<p>First Principle という言葉を耳にされたことはないだろうか。それは奥深く物事の基礎を理解した上で、よりよい発想を生まれることをいっている概念だ。</p><p>スマートコントラクトの世界では、EVM とその周りにあるアルゴリズム、データ構造に関しては、まさにこの First Principle である。Solidity あるいはスマートコントラクトはこの基礎の上に作る構造物なのだ。EVM のことを理解せずにはグレートな solidity dev と称するにはまだ早いと言ってよいだろう。</p><h2 id="h-solidity-bytecode-opcode" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">基礎：Solidity → Bytecode → Opcode</h2><p>まず、基礎的な部分について一定程度の知識を有することを前提としている。</p><ul><li><p>おさらい：</p><ul><li><p>Bytecode &amp; ABI: バイトコードとは EVM 上で実行可能なコードで、ABI とはこの EVM バイトコードとやり取りができるための interface。</p></li><li><p>Solidity コードはまずバイトコードへコンパイルしてから、イーサリアムブロックチェーンへ乗せるという流れになる。バイトコードは実は色々なオペコードを意味している。</p></li></ul></li></ul><p>今回は基本的な solidity コントラクトについてのバイトコードの一部を一緒にみていき、EVM がどのように関数を選んでいるかを見よう。</p><p>コントラクトのバイトコードはコントラクトからコンパイルされたもので、コントラクトにはいくつかもの関数があるだろう。</p><p>よくある質問は、デプロイした後、EVM はどのようにバイトコードのどの部分を実行すべきかがわかったのかというのがある。</p><p>今回はそれについて詳しく見ていきましょう。</p><h2 id="h-1storagesol" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">1_Storage.sol コントラクト</h2><pre data-type="codeBlock" text="pragma solidity &gt;=0.7.0 &lt;0.9.0;

contract Storage {
    uint256 number;

    function store(uint256 num) public {
        number = num;
    }

    function retrieve() public view returns (uint256) {
        return number;
    }
}
"><code><span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> >=0.7.0 &#x3C;0.9.0;</span>

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Storage</span> </span>{
    <span class="hljs-keyword">uint256</span> number;

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">store</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> num</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        number <span class="hljs-operator">=</span> num;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">retrieve</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span></span>) </span>{
        <span class="hljs-keyword">return</span> number;
    }
}
</code></pre><p>今回のコントラクトは上記のものとなる。コントラクトには二個の関数がある。<code>store()</code>と <code>retrieve()</code>。</p><p>runtime のバイトコードは以下の通り：</p><pre data-type="codeBlock" text="608060405234801561001057600080fd5b50600436106100365760003560e01c80632e64cec11461003b5780636057361d14610059575b600080fd5b610043610075565b60405161005091906100d9565b60405180910390f35b610073600480360381019061006e919061009d565b61007e565b005b60008054905090565b8060008190555050565b60008135905061009781610103565b92915050565b6000602082840312156100b3576100b26100fe565b5b60006100c184828501610088565b91505092915050565b6100d3816100f4565b82525050565b60006020820190506100ee60008301846100ca565b92915050565b6000819050919050565b600080fd5b61010c816100f4565b811461011757600080fd5b5056fea2646970667358221220404e37f487a89a932dca5e77faaf6ca2de3b991f93d230604b1b8daaef64766264736f6c63430008070033
"><code>608060405234801561001057600080fd5b50600436106100365760003560e01c80632e64cec11461003b5780636057361d14610059575b600080fd5b610043610075565b60405161005091906100d9565b60405180910390f35b610073600480360381019061006e919061009d565b61007e565b005b60008054905090565b8060008190555050565b60008135905061009781610103565b92915050565b6000602082840312156100b3576100b26100fe565b5b60006100c184828501610088565b91505092915050565b6100d3816100f4565b82525050565b60006020820190506100ee60008301846100ca565b92915050565b6000819050919050565b600080fd5b61010c816100f4565b811461011757600080fd5b5056fea2646970667358221220404e37f487a89a932dca5e77faaf6ca2de3b991f93d230604b1b8daae<span class="hljs-type">f64</span>766264736f6c63430008070033
</code></pre><p>今回フォーカスするのは以下の部分：</p><pre data-type="codeBlock" text="60003560e01c80632e64cec11461003b5780636057361d1461005957
"><code></code></pre><p>この部分は全体のバイトコードから抜き取ったもの。</p><p>関数のセレクタのロジックが含まれている。</p><p>言い遅れたが、EVM のオペコードに関しては、<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.ethervm.io/">ここ</a>から確認できる。</p><p>オペコードは 1 byte の長さになる。そうすると自然に 256 パターンがあると分ると思う。</p><p>しかし、実際には 140 子のオペコードしか存在しない。</p><p>以下はバイトコードを関係するオペコードへ変換したもの。</p><pre data-type="codeBlock" text="60 00                       =   PUSH1 0x00
35                          =   CALLDATALOAD
60 e0                       =   PUSH1 0xe0
1c                          =   SHR
80                          =   DUP1
63 2e64cec1                 =   PUSH4 0x2e64cec1
14                          =   EQ
61 003b                     =   PUSH2 0x003b
57                          =   JUMPI
80                          =   DUP1
63 6057361d                 =   PUSH4 0x6057361d
14                          =   EQ
61 0059                     =   PUSH2 0x0059
57                          =   JUMPI
"><code>60 <span class="hljs-attr">00</span>                       =   PUSH1 <span class="hljs-number">0</span>x00
<span class="hljs-attr">35</span>                          =   CALLDATALOAD
60 <span class="hljs-attr">e0</span>                       =   PUSH1 <span class="hljs-number">0</span>xe0
<span class="hljs-attr">1c</span>                          =   SHR
<span class="hljs-attr">80</span>                          =   DUP1
63 <span class="hljs-attr">2e64cec1</span>                 =   PUSH4 <span class="hljs-number">0</span>x2e64cec1
<span class="hljs-attr">14</span>                          =   EQ
61 <span class="hljs-attr">003b</span>                     =   PUSH2 <span class="hljs-number">0</span>x003b
<span class="hljs-attr">57</span>                          =   JUMPI
<span class="hljs-attr">80</span>                          =   DUP1
63 <span class="hljs-attr">6057361d</span>                 =   PUSH4 <span class="hljs-number">0</span>x6057361d
<span class="hljs-attr">14</span>                          =   EQ
61 <span class="hljs-attr">0059</span>                     =   PUSH2 <span class="hljs-number">0</span>x0059
<span class="hljs-attr">57</span>                          =   JUMPI
</code></pre><h2 id="h-calldata" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">スマコンの関数呼び出しや Calldata</h2><p>オペコードへダイブする前に、コントラクトの関数の呼び出しについて復習しよう。</p><p>関数の呼び出しの前に、calldata に、関数の署名、そして続いて引数も入れる。</p><p>Solidity のコードに表現してもらうと、こうなるだろう。</p><pre data-type="codeBlock" text="event FunctionCalldata(bytes);
bytes memory functionCalldata = abi.encodeWithSignature(&apos;store(uint256)&apos;, 10);
emit FunctionCalldata(functionCalldata);
address(storageContract).call(functionCalldata);
"><code><span class="hljs-function"><span class="hljs-keyword">event</span> <span class="hljs-title">FunctionCalldata</span>(<span class="hljs-params"><span class="hljs-keyword">bytes</span></span>)</span>;
<span class="hljs-keyword">bytes</span> <span class="hljs-keyword">memory</span> functionCalldata <span class="hljs-operator">=</span> <span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encodeWithSignature</span>(<span class="hljs-string">'store(uint256)'</span>, <span class="hljs-number">10</span>);
<span class="hljs-keyword">emit</span> FunctionCalldata(functionCalldata);
<span class="hljs-keyword">address</span>(storageContract).<span class="hljs-built_in">call</span>(functionCalldata);
</code></pre><p>今回の場合、僕は store 関数を呼び、10 引数として代入したい。</p><pre data-type="codeBlock" text="0x6057361d000000000000000000000000000000000000000000000000000000000000000a
"><code></code></pre><p>上の長い数字の配列は abi.encodeWithSignature(”store(uint256)”,10)の結果。</p><p>関数シグネチャーは４バイトの Keccak ハッシュ値によって定義されている「0x6057361d」。</p><pre data-type="codeBlock" text="keccak256(“store(uint256)”) →  first 4 bytes = 6057361d

keccak256(“retrieve()”) → first 4 bytes = 2e64cec1
"><code><span class="hljs-built_in">keccak256</span>(“store(<span class="hljs-keyword">uint256</span>)”) →  first <span class="hljs-number">4</span> <span class="hljs-keyword">bytes</span> <span class="hljs-operator">=</span> 6057361d

<span class="hljs-built_in">keccak256</span>(“retrieve()”) → first <span class="hljs-number">4</span> <span class="hljs-keyword">bytes</span> <span class="hljs-operator">=</span> 2e64cec1
</code></pre><p>先程の calldata を見ると、全部で 36bytes あった。最初の 4bytes: <code>6057361d</code>は関数のセレクタ関連で、<code>store(uint256)</code>と関係する。</p><p>ご自身ではッシュしてみて →<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://emn178.github.io/online-tools/keccak_256.html">ここ</a></p><pre data-type="codeBlock" text="6057361d = function signature (4 bytes)

000000000000000000000000000000000000000000000000000000000000000a = uint256 input (32 bytes)
"><code>6057361d <span class="hljs-operator">=</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">signature</span> (<span class="hljs-params"><span class="hljs-number">4</span> <span class="hljs-keyword">bytes</span></span>)

000000000000000000000000000000000000000000000000000000000000000<span class="hljs-title">a</span> = <span class="hljs-title"><span class="hljs-keyword">uint256</span></span> <span class="hljs-title">input</span> (<span class="hljs-params"><span class="hljs-number">32</span> <span class="hljs-keyword">bytes</span></span>)
</span></code></pre><p>以上、calldata の準備だった。</p><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">オペコード＆スタック</h2><p>それでは、EVM レベルへダイブしていこう。スタックについて理解しておく必要がある。わからない場合は<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.youtube.com/watch?v=FNZ5o9S9prU">これ</a>を見て。</p><p>先程のオペコードはこれ：</p><pre data-type="codeBlock" text="60 00                       =   PUSH1 0x00
35                          =   CALLDATALOAD
60 e0                       =   PUSH1 0xe0
1c                          =   SHR
80                          =   DUP1
63 2e64cec1                 =   PUSH4 0x2e64cec1
14                          =   EQ
61 003b                     =   PUSH2 0x003b
57                          =   JUMPI
80                          =   DUP1
63 6057361d                 =   PUSH4 0x6057361d
14                          =   EQ
61 0059                     =   PUSH2 0x0059
57                          =   JUMPI
"><code>60 <span class="hljs-attr">00</span>                       =   PUSH1 <span class="hljs-number">0</span>x00
<span class="hljs-attr">35</span>                          =   CALLDATALOAD
60 <span class="hljs-attr">e0</span>                       =   PUSH1 <span class="hljs-number">0</span>xe0
<span class="hljs-attr">1c</span>                          =   SHR
<span class="hljs-attr">80</span>                          =   DUP1
63 <span class="hljs-attr">2e64cec1</span>                 =   PUSH4 <span class="hljs-number">0</span>x2e64cec1
<span class="hljs-attr">14</span>                          =   EQ
61 <span class="hljs-attr">003b</span>                     =   PUSH2 <span class="hljs-number">0</span>x003b
<span class="hljs-attr">57</span>                          =   JUMPI
<span class="hljs-attr">80</span>                          =   DUP1
63 <span class="hljs-attr">6057361d</span>                 =   PUSH4 <span class="hljs-number">0</span>x6057361d
<span class="hljs-attr">14</span>                          =   EQ
61 <span class="hljs-attr">0059</span>                     =   PUSH2 <span class="hljs-number">0</span>x0059
<span class="hljs-attr">57</span>                          =   JUMPI
</code></pre><p>PUSH1 は 1byte のデータをスタックへ入れることを意味する。そうすると、スタックはこうなる</p><pre data-type="codeBlock" text="PUSH1 0x00    | 0 |
"><code>PUSH1 <span class="hljs-number">0x00</span>    <span class="hljs-operator">|</span> <span class="hljs-number">0</span> <span class="hljs-operator">|</span>
</code></pre><p>続いて CALLDATALOAD は最初の stack(0)の値をポップさせる。この 0 値を input として使用し、offset として使う。スタックアイテムのサイズは 32bytes なのに対し、今回の calldata は 36bytes になっている。プッシュする値は msg.data[i : i+32]で、i は今回の input 値となる。これは毎回プッシュする値が 32bytes になることを保証できる。同時に、どの部分にもアクセルできる。</p><p>今回の場合、offset はなかったので、32bytes の calldata の値をスタックに push した。さきほど用意した calldata はこれ。やっと出番がきた。</p><p><code>0x6057361d000000000000000000000000000000000000000000000000000000000000000a</code>。</p><p>というのは、最後の<code>0000000a</code>が除外された 32bytes が今回の入力となる。</p><pre data-type="codeBlock" text="CALLDATALOAD    | 0x6057361d0...00 |
"><code>CALLDATALOAD    <span class="hljs-operator">|</span> <span class="hljs-number">0x6057361d0</span>...00 <span class="hljs-operator">|</span>
</code></pre><p>次に PUSH1 を使って hex value の 0xe0 をスタックに入れる。これは十進数だと 224。</p><pre data-type="codeBlock" text="PUSH1 0xe0      |       224        |
                | 0x6057361d0...00 |
"><code>PUSH1 <span class="hljs-number">0xe0</span>      <span class="hljs-operator">|</span>       <span class="hljs-number">224</span>        <span class="hljs-operator">|</span>
                <span class="hljs-operator">|</span> <span class="hljs-number">0x6057361d0</span>...00 <span class="hljs-operator">|</span>
</code></pre><p>SHR を使ってライトシフトさせる。今回は最初のアイテムである 224 を取り出し、input として扱う。スタックにある二番目のアイテムをどれくらい右へライトシフトさせるかを定義している。256 - 244 = 32 bit とわかるように、最後には 4bytes のセレクタが call stack に残る。</p><pre data-type="codeBlock" text="SHR    | 0x6057361d |
"><code>SHR    <span class="hljs-operator">|</span> <span class="hljs-number">0x6057361d</span> <span class="hljs-operator">|</span>
</code></pre><p>DUP1 を使ってスタックの一番上の値をコピーする。</p><pre data-type="codeBlock" text="DUP1    | 0x6057361d |
        | 0x6057361d |
"><code>DUP1    <span class="hljs-operator">|</span> <span class="hljs-number">0x6057361d</span> <span class="hljs-operator">|</span>
        <span class="hljs-operator">|</span> <span class="hljs-number">0x6057361d</span> <span class="hljs-operator">|</span>
</code></pre><p>PUSH4 を使って 4byte の関数のシグネチャーの<code>retrieve()</code> (0x2e64cec1) をスタックにプッシュする。</p><pre data-type="codeBlock" text="PUSH4 0x2e64cec1        | 0x2e64cec1 |
                | 0x6057361d |
            	| 0x6057361d |
"><code>PUSH4 <span class="hljs-number">0x2e64cec1</span>        <span class="hljs-operator">|</span> <span class="hljs-number">0x2e64cec1</span> <span class="hljs-operator">|</span>
                <span class="hljs-operator">|</span> <span class="hljs-number">0x6057361d</span> <span class="hljs-operator">|</span>
            	<span class="hljs-operator">|</span> <span class="hljs-number">0x6057361d</span> <span class="hljs-operator">|</span>
</code></pre><p>EQ は二個の値をスタックから出し、イコールなのかどうかをチェックする。もしイコールなら 1（true） をスタックにプッシュ、そうでない場合は 0（false） をプッシュする。</p><pre data-type="codeBlock" text="EQ    		　　　|      0     |
        　　　| 0x6057361d |
"><code>EQ    		　　　<span class="hljs-operator">|</span>      <span class="hljs-number">0</span>     <span class="hljs-operator">|</span>
        　　　<span class="hljs-operator">|</span> <span class="hljs-number">0x6057361d</span> <span class="hljs-operator">|</span>
</code></pre><p>次に PUSH2 を使って二個の値をプッシュ。（0x003b, 十進数だと 59）</p><p>ここでは、59 が出たのはプログラムカウンターがバイトコードに次の実行コマンドはどこにあるのかを確認しているから。この 59 は retrieve()がスタート地点は 59 を意味している。</p><pre data-type="codeBlock" text="PUSH2 0x003b    |     59     |
        |      0     |
        | 0x6057361d |
"><code>PUSH2 <span class="hljs-number">0x003b</span>    <span class="hljs-operator">|</span>     <span class="hljs-number">59</span>     <span class="hljs-operator">|</span>
        <span class="hljs-operator">|</span>      <span class="hljs-number">0</span>     <span class="hljs-operator">|</span>
        <span class="hljs-operator">|</span> <span class="hljs-number">0x6057361d</span> <span class="hljs-operator">|</span>
</code></pre><p>JUMPI は”jump if”を意味する。二個の値をポップさせ、一個目の値は 59 で、二個目は 0。二個目の値は bool 値でこの jump を実行すべきかを確定している。1 = true, 0 = false。</p><p>もし true の場合、プログラムカウンターはアップデートされ実行はそちらへ jump する。今回は false なので、スキップ。</p><pre data-type="codeBlock" text="JUMPI    | 0x6057361d |
"><code>JUMPI    <span class="hljs-operator">|</span> <span class="hljs-number">0x6057361d</span> <span class="hljs-operator">|</span>
</code></pre><p>DUP1 again</p><pre data-type="codeBlock" text="DUP1    | 0x6057361d |
        | 0x6057361d |
"><code>DUP1    <span class="hljs-operator">|</span> <span class="hljs-number">0x6057361d</span> <span class="hljs-operator">|</span>
        <span class="hljs-operator">|</span> <span class="hljs-number">0x6057361d</span> <span class="hljs-operator">|</span>
</code></pre><p>PUSH4 は 4byte の値をスタックにプッシュする</p><pre data-type="codeBlock" text="PUSH4 0x6057361d    | 0x6057361d |
        　　　　　　　　| 0x6057361d |
        　　　　　　　　| 0x6057361d |
"><code>PUSH4 <span class="hljs-number">0x6057361d</span>    <span class="hljs-operator">|</span> <span class="hljs-number">0x6057361d</span> <span class="hljs-operator">|</span>
        　　　　　　　　<span class="hljs-operator">|</span> <span class="hljs-number">0x6057361d</span> <span class="hljs-operator">|</span>
        　　　　　　　　<span class="hljs-operator">|</span> <span class="hljs-number">0x6057361d</span> <span class="hljs-operator">|</span>
</code></pre><p>また EQ して、今回は true なので。シグネチャーが合った。</p><pre data-type="codeBlock" text="EQ　　　　　　　　　　|      1     |
　　　　　　　　　　　　　　| 0x6057361d |
"><code>EQ　　　　　　　　　　<span class="hljs-operator">|</span>      <span class="hljs-number">1</span>     <span class="hljs-operator">|</span>
　　　　　　　　　　　　　　<span class="hljs-operator">|</span> <span class="hljs-number">0x6057361d</span> <span class="hljs-operator">|</span>
</code></pre><p>JUMPI、今回は true なんで jump を実行する。プログラムカウンターは 89 で、バイトコードの違う場所へ移動。</p><pre data-type="codeBlock" text="PUSH2 0x0059    |     89     |
        |      1     |
        | 0x6057361d |
"><code>PUSH2 <span class="hljs-number">0x0059</span>    <span class="hljs-operator">|</span>     <span class="hljs-number">89</span>     <span class="hljs-operator">|</span>
        <span class="hljs-operator">|</span>      <span class="hljs-number">1</span>     <span class="hljs-operator">|</span>
        <span class="hljs-operator">|</span> <span class="hljs-number">0x6057361d</span> <span class="hljs-operator">|</span>
</code></pre><p>この場所に JUMPDEST オペコードがある。これがないと失敗する。</p><pre data-type="codeBlock" text="JUMPI      | 0x6057361d |
"><code>JUMPI      <span class="hljs-operator">|</span> <span class="hljs-number">0x6057361d</span> <span class="hljs-operator">|</span>
</code></pre><p>そこで終わり。これでオペコードの実行は<code>store(uint156)</code>の場所へ移動できた。</p><p>今回は二個の関数しかないものの、たとえ 20 個の関数があったとしても、プロセスは一緒。</p><p>この<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.evm.codes/playground?unit=Wei&amp;callData=0x6057361d000000000000000000000000000000000000000000000000000000000000000a&amp;codeType=Mnemonic&amp;code=%27%210%7E0KCALLDATALOAD%7E2z2qw%21E0%7E3KSHR%7E5z2qwDUP1%7E6%28X4_2E64CEC1%7E7KEQ%7E12z5qwX2_3B%7E13%28*I%7E16z3qwDUP1%7E17KX4_6057361D%7E18KEQ%7E23z5qwX2_59%7E24K*I%7E27z3qwkY+wX30_0%7E28KwZGV59z31q%211%7E60+%7BG%7DW%7DKwkYwX26_0%7E62z2qKZstore%7Buint256V89z27q%210+ZContinueW.KK%27%7E+ZOffset+z+%7Bprevious+instruFoccupies+w%5Cnq%29s%7DwkZThes-ar-just+paddingNenabl-usNgetN_+0xZ%2F%2F+Yprogram+counter+59+%26+89XPUSHW+funFexecution...V%7D%29codew*DEST%7EN+to%28wwGretrieve%7BFction+-e+*JUMP%29+byte%28+K%21X1_%01%21%28%29*-FGKNVWXYZ_kqwz%7E_&amp;fork=merge">リンク</a>は非常におすすめ。触ってみると吉。</p><p>EVMのスタック・メモリ・ストレージをシミュレートしてくれる。</p><p>日本語圏にはこういった記事が少ないと思いますので、もし役に立ったのであれば幸いだと思います。今後も記事を作成していきますので、よろしくお願いします。</p><p>普段私は主にこちらのサイトに記事をパブリッシュしています。</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://omaeno.xyz/blog/EVM-deep-dive-part1">https://omaeno.xyz/blog/EVM-deep-dive-part1</a></p><h2 id="h-reference" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Reference</h2><p>This is a translated article. All rights reserved for the original author.</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://noxx.substack.com/p/evm-deep-dives-the-path-to-shadowy">https://noxx.substack.com/p/evm-deep-dives-the-path-to-shadowy</a></p>]]></content:encoded>
            <author>thurendous@newsletter.paragraph.com (thurendous)</author>
        </item>
    </channel>
</rss>