<?xml version="1.0" encoding="utf-8" ?><rss version="2.0" xmlns:tt="http://teletype.in/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>Alzheimer🤬</title><generator>teletype.in</generator><description><![CDATA[Alzheimer🤬]]></description><image><url>https://img1.teletype.in/files/4d/e6/4de6b99d-0aa5-48fa-b515-d6590f4582f2.png</url><title>Alzheimer🤬</title><link>https://teletype.in/@alzheimer</link></image><link>https://teletype.in/@alzheimer?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=alzheimer</link><atom:link rel="self" type="application/rss+xml" href="https://teletype.in/rss/alzheimer?offset=0"></atom:link><atom:link rel="next" type="application/rss+xml" href="https://teletype.in/rss/alzheimer?offset=10"></atom:link><atom:link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></atom:link><pubDate>Mon, 06 Apr 2026 20:07:23 GMT</pubDate><lastBuildDate>Mon, 06 Apr 2026 20:07:23 GMT</lastBuildDate><item><guid isPermaLink="true">https://teletype.in/@alzheimer/3Rphh5fXM7u</guid><link>https://teletype.in/@alzheimer/3Rphh5fXM7u?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=alzheimer</link><comments>https://teletype.in/@alzheimer/3Rphh5fXM7u?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=alzheimer#comments</comments><dc:creator>alzheimer</dc:creator><title>The Best GitHub: лучшие советы и полная настройка</title><pubDate>Wed, 01 Mar 2023 08:00:13 GMT</pubDate><media:content medium="image" url="https://img2.teletype.in/files/d0/c5/d0c5c06e-39a3-4898-a534-14b759f4ac97.png"></media:content><description><![CDATA[<img src="https://uploads.sitepoint.com/wp-content/uploads/2021/12/1638885720github-create-repo.png"></img>Файл README находится в репозитории GitHub, имя которого совпадает с именем пользователя вашей учетной записи GitHub. Чтобы создать репозиторий, выполните следующие действия:]]></description><content:encoded><![CDATA[
  <h2 id="creatinggithubprofilereadme">Создание профиля GitHub README 👋</h2>
  <p id="l61J">Файл README находится в репозитории GitHub, имя которого совпадает с именем пользователя вашей учетной записи GitHub. Чтобы создать репозиторий, выполните следующие действия:</p>
  <ul id="GZsn">
    <li id="squz">Войдите в <a href="https://github.com/" target="_blank">GitHub</a> .</li>
    <li id="XxGY">Нажмите значок <strong>+</strong> в правом верхнем углу страницы и выберите <strong>«Новый репозиторий»</strong> .</li>
  </ul>
  <figure id="7KIj" class="m_column">
    <img src="https://uploads.sitepoint.com/wp-content/uploads/2021/12/1638885720github-create-repo.png" width="1900" />
  </figure>
  <ul id="ui6T">
    <li id="iYvh">Откроется страница Создать <em>новый репозиторий</em> . В поле <strong>Имя репозитория</strong> введите имя пользователя вашей учетной записи GitHub. После ввода имени пользователя GitHub отображает сообщение о том, что вы собираетесь создать специальный репозиторий GitHub.</li>
  </ul>
  <figure id="FAt2" class="m_column">
    <img src="https://uploads.sitepoint.com/wp-content/uploads/2021/12/1638950865github-repo-name.png" width="1552" />
  </figure>
  <ul id="dznc">
    <li id="lGT7">Установите флажок <strong>«Общедоступный»</strong> в разделе «Тип репозитория», чтобы сделать файл README профиля GitHub видимым для всех, кто посещает страницу профиля GitHub. Если вы не хотите, чтобы пользователи видели README вашего профиля GitHub, пока он еще находится в разработке, вы можете выбрать <strong>Private</strong> . Когда вы закончите разработку README, обязательно измените видимость на <strong>Public</strong> .</li>
    <li id="etiy">Установите флажок <strong>Добавить файл README</strong> . Это добавит <code>README.md</code>файл, в который мы добавим содержимое профиля. Значения полей должны выглядеть примерно так, как показано на рисунке ниже.</li>
  </ul>
  <figure id="6WHh" class="m_column">
    <img src="https://uploads.sitepoint.com/wp-content/uploads/2021/12/1638951049create-repo-fields.png" width="1128" />
  </figure>
  <ul id="ktwz">
    <li id="wwFC">Нажмите на кнопку <strong>«Создать репозиторий»</strong> . Специальный репозиторий успешно создан. Перейдите в репозиторий, который вы только что создали, и вы увидите файл, <code>README.md</code>добавленный в репозиторий.</li>
  </ul>
  <figure id="YabJ" class="m_column">
    <img src="https://uploads.sitepoint.com/wp-content/uploads/2021/12/1638951228repo-created.png" width="1893" />
  </figure>
  <p id="wSwE">В следующих нескольких разделах мы добавим содержимое в наш <code>README.md</code>файл. Мы будем использовать файловый редактор GitHub для записи и предварительного просмотра изменений. Вы можете использовать любой другой удобный текстовый редактор.</p>
  <p id="8QGW">Чтобы использовать редактор файлов GitHub, откройте <code>README.md</code>и щелкните <em>значок «Редактировать этот файл»</em> (значок карандаша) в правом верхнем углу страницы. Подробнее о редактировании файлов GitHub можно прочитать в официальной документации GitHub по <a href="https://docs.github.com/en/repositories/working-with-files/managing-files/editing-files" target="_blank">редактированию файлов</a> .</p>
  <h2 id="addingbannergifandaboutmesection">Добавление GIF-баннера и раздела «Обо мне» </h2>
  <figure id="vj6K" class="m_column" data-caption-align="center">
    <img src="https://miro.medium.com/max/700/1*cxueL722-cuMCKlrfAWuwQ.gif" width="1920" />
    <figcaption>Заголовок профиля GitHub</figcaption>
  </figure>
  <ul id="Eyzv">
    <li id="d853">Первое, что вы можете увидеть, это анимированный заголовок с текстом «Привет всем!» Для этого я использовал <a href="https://github.com/kyechan99/capsule-render" target="_blank"><strong>репозиторий GitHub для капсульного рендеринга . </strong></a>Я наткнулся на этот замечательный ресурс, когда искал способы украсить ваш репозиторий GitHub. Вы можете добавлять фоновые изображения и текст поверх них, а также, кто не любит анимацию! Он очень прост в использовании и хорошо задокументирован в репозитории. Вот моя конфигурация рендера.</li>
  </ul>
  <pre id="QOHP">&lt;p align=&quot;center&quot;&gt;  &lt;img src=&quot;https://capsule-render.vercel.app/api?text=Hey Everyone!🕹️&amp;animation=fadeIn&amp;type=waving&amp;color=gradient&amp;height=100&quot;/&gt;&lt;/p&gt;</pre>
  <ul id="go4w">
    <li id="b63f">После вставки простого заголовка, чтобы предоставить ссылки на мои различные учетные записи, такие как LinkedIn, Medium, Dev.to, а также на мой сайт-портфолио, я хотел сделать это минималистичным и бестекстовым способом. Итак, я решил использовать иконки. Существует множество доступных онлайн-инструментов, которые предоставляют тысячи бесплатных иконок для использования. Я использовал <a href="https://www.iconfinder.com/" target="_blank"><strong>IconFinder </strong></a>и лично мне понравилось. Есть много других популярных опций, которые вы можете использовать, например <a href="https://shields.io/" target="_blank"><strong>Shields.io</strong></a> , <a href="https://github.com/Ileriayo/markdown-badges" target="_blank"><strong>markdown-badges</strong></a> , <a href="https://www.vectorlogo.zone/index.html" target="_blank"><strong>vector-logo-zone</strong></a> , <a href="https://simpleicons.org/" target="_blank"><strong>simple-icons</strong></a> и т. д.</li>
  </ul>
  <p id="7b65">Просто нужно импортировать исходный файл значка в формате png в <em><strong>тег &lt;img&gt;</strong> ,</em> как показано ниже <em>:</em></p>
  <pre id="NRiy">&lt;a href=&quot;https://www.instagram.com/thepiyushmalhotra/&quot;&gt;  &lt;img height=&quot;50&quot; src=&quot;https://user-images.githubusercontent.com/46517096/166974368-9798f39f-1f46-499c-b14e-81f0a3f83a06.png&quot;/&gt;&lt;/a&gt;</pre>
  <ul id="PQJo">
    <li id="d550">Теперь самое интересное — добавить эту великолепную гифку! GIF-файлы делают наш профиль более <strong>динамичным и привлекательным</strong> . Честно говоря, вы можете разместить любую GIF, которую хотите. Это может быть популярный мем, гифка о программировании, культовая сцена из фильма или телешоу или что-то, что немного рассказывает людям о ваших увлечениях. В моем случае это аниме, так что я выбрал его. Популярные веб-сайты для обмена gif-файлами, такие как <a href="https://giphy.com/" target="_blank"><strong>Giphy </strong></a>и <a href="https://tenor.com/" target="_blank"><strong>Tenor</strong></a>, можно использовать для извлечения любого понравившегося вам gif-файла, и это работает так же, как добавление значков, просто скопируйте адрес изображения и вставьте его в атрибут «src<em>» тега &lt;img&gt;</em> .</li>
  </ul>
  <h2 id="5389">Раздел «Обо мне» 👨‍💻</h2>
  <p id="f542">Это раздел, о котором я говорил ранее, где большинство разработчиков используют шаблон, показанный выше. Если вы хотите, чтобы ваш профиль выделялся, я бы посоветовал также изменить аспекты дизайна этого раздела. Я пошел дальше и использовал формат <strong>YAML</strong> при редактировании файла readme, чтобы информация читалась как <strong><em>код</em></strong> при предварительном просмотре профиля.</p>
  <figure id="ojEy" class="m_custom" data-caption-align="center">
    <img src="https://miro.medium.com/max/700/1*_g1X-OaK3vLysA-tJrMMfA.png" width="700" />
    <figcaption>Раздел «Обо мне»</figcaption>
  </figure>
  <p id="56cb">Это добавляет нотку профессионализма, а также в качестве бонуса выглядит аккуратно! Чтобы отобразить этот формат, просто оберните текст, как показано ниже, и все готово:</p>
  <pre id="DVPs">&#x60;&#x60;&#x60;yaml * ЗДЕСЬ ИДЕТ ВАШ ТЕКСТ * &#x60;&#x60;&#x60;</pre>
  <h2 id="ac6a">Инструменты и технические вещи 🧰</h2>
  <p id="dd89">В этом разделе вы можете продемонстрировать свои навыки и перечислить инструменты и технологии, с которыми вы знакомы. Я всегда предпочитаю <strong>минималистичный и четкий</strong> дизайн загроможденным данным, поэтому на этот раз я также выбрал значки. Мы, люди, предпочитаем информацию через визуальные носители гораздо больше, чем что-либо еще, верно?</p>
  <p id="af1d">Вы можете использовать все, что я упомянул выше, например <a href="https://www.iconfinder.com/" target="_blank"><strong>IconFinder</strong></a> , <a href="https://shields.io/" target="_blank"><strong>Shields.io</strong></a> , <a href="https://github.com/Ileriayo/markdown-badges" target="_blank"><strong>markdown-badges</strong></a> , <a href="https://www.vectorlogo.zone/index.html" target="_blank"><strong>vector-logo-zone</strong></a> , <a href="https://simpleicons.org/" target="_blank"><strong>simple-icons</strong></a> и т. д. Но для этого раздела я бы лично рекомендовал <a href="https://devicon.dev/" target="_blank"><strong>DevIcon</strong></a> . В отличие от других ресурсов, DevIcon создан для предоставления значков, связанных исключительно с языками программирования и инструментами разработки, что делает его идеальным.</p>
  <figure id="P2Yb" class="m_custom" data-caption-align="center">
    <img src="https://miro.medium.com/max/700/1*ck4ZAQKAPreK2CFe7uBw7A.png" width="700" />
    <figcaption>Раздел навыков GitHub</figcaption>
  </figure>
  <p id="07ff">Просто скопируйте источник изображения SVG с веб-сайта DevIcon и вставьте его в тег &lt;p&gt;, <strong>чтобы</strong> отобразить несколько значков!</p>
  <pre id="Kqnk">&lt;h2&gt; 🚀 &amp;nbsp;Some Tools I Have Used and Learned&lt;/h2&gt;&lt;p align=&quot;left&quot;&gt;&lt;img src=&quot;https://cdn.jsdelivr.net/gh/devicons/devicon/icons/vscode/vscode-original.svg&quot; alt=&quot;vscode&quot; width=&quot;45&quot; height=&quot;45&quot;/&gt;&lt;img src=&quot;https://cdn.jsdelivr.net/gh/devicons/devicon/icons/bash/bash-original.svg&quot; alt=&quot;bash&quot; width=&quot;45&quot; height=&quot;45&quot;/&gt;&lt;img src=&quot;https://cdn.jsdelivr.net/gh/devicons/devicon/icons/php/php-original.svg&quot; alt=&quot;php&quot; width=&quot;45&quot; height=&quot;45&quot;/&gt;&lt;/p&gt;</pre>
  <h2 id="7794">Ваша история GitHub 📈</h2>
  <p id="d0ec">Наконец, в конце файла README вашего профиля вы можете указать практически что угодно. Некоторые разработчики размещают то, что сейчас играет, в своем <a href="https://github.com/kittinan/spotify-github-profile" target="_blank"><strong>профиле Spotify</strong></a> , некоторые добавляют свою <a href="https://github.com/anuraghazra/github-readme-stats" target="_blank"><strong>статистику GitHub</strong></a> , а некоторые добавляют забавную маленькую игру в змейку на вашем графике вкладов GitHub, как я, и я покажу вам, ребята, как разместить!</p>
  <figure id="OefT" class="m_custom" data-caption-align="center">
    <img src="https://miro.medium.com/max/700/1*D_gkcGSi6tO4o_dKVHcRow.gif" width="700" />
    <figcaption>Статистика на GitHub</figcaption>
  </figure>
  <p id="2e3c">Я начну с двух статистических карточек GitHub ReadMe. Один показывает мое общее количество звезд, коммитов и пулреквестов и т. д. А другой отображает мои наиболее используемые языки программирования в процентах. Вы, ребята, можете получить эти карты из популярного репозитория <a href="https://github.com/anuraghazra/github-readme-stats" target="_blank"><strong>GitHub ReadMe Stats Repo</strong></a> , и самое приятное в них то, что они полностью настраиваются с различными настройками и темами!</p>
  <p id="69b4">Далее, вероятно, моя любимая вещь из всех элементов моего профиля. Создание <strong>игры «Змейка» из вашего графика вкладов GitHub</strong> . Его довольно легко настроить, и он выглядит очень удовлетворительно, когда змея поглощает ваш график коммитов.</p>
  <p id="d578">Чтобы настроить его для вашего профиля, мы собираемся использовать то, что называется GitHub Actions. GitHub Actions — это инструменты CI/CD в GitHub, с помощью которых вы можете инициировать рабочие процессы, которые автоматически запускают, развертывают и создают ваши материалы.</p>
  <pre id="Hq9d">![Snake animation]( https://github.com/thepiyushmalhotra/thepiyushmalhotra/blob/output/github-contribution-grid-snake.svg )</pre>
  <ul id="lfEU">
    <li id="b2ca">Первый шаг — скопировать эту строку выше и добавить ее в файл README вашего профиля. Не забудьте изменить имя пользователя на свое, а не на мое.</li>
    <li id="a1d9">Теперь нам нужно создать рабочий процесс GitHub, чтобы график вклада в анимации змеи обновлялся в соответствии с заданием cron, которое мы настроим.</li>
    <li id="d0c8">Перейдите на вкладку «<strong><em>Действия</em></strong>» в репозитории README и создайте новый рабочий процесс. Это создаст новую папку в вашем репозитории с именем «<strong><em>.github/workflows</em></strong>», а после этого внутри нее будет создан новый файл с именем «<strong><em>main.yml</em></strong>».</li>
  </ul>
  <figure id="mtcd" class="m_custom" data-caption-align="center">
    <img src="https://miro.medium.com/max/700/1*WzLn--jNcIuUTN8Y1QfDZA.png" width="700" />
    <figcaption>Настройте новый рабочий процесс</figcaption>
  </figure>
  <figure id="RSnc" class="m_custom" data-caption-align="center">
    <img src="https://miro.medium.com/max/700/1*8b05PnlQ2XGSnpt7ZY0aug.png" width="700" />
    <figcaption>файл main.yml</figcaption>
  </figure>
  <ul id="RTZr">
    <li id="9e81">Удалите все внутри только что созданного файла main.yml и добавьте в него этот код ниже:</li>
  </ul>
  <pre id="NI4S">name: Generate Datason:  schedule: # execute every 12 hours    - cron: &quot;* */12 * * *&quot;  workflow_dispatch:jobs:  build:    name: Jobs to update datas    runs-on: ubuntu-latest    steps:      # Snake Animation      - uses: Platane/snk@master        id: snake-gifwith:          github_user_name: thepiyushmalhotra          svg_out_path: dist/github-contribution-grid-snake.svg      - uses: crazy-max/ghaction-github-pages@v2.1.3        with:          target_branch: output          build_dir: dist        env:          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}</pre>
  <ul id="vE8D">
    <li id="0ee8">Не забудьте заменить мое имя пользователя на ваше. Здесь мы используем <strong><em>cronjob</em></strong> , который обновляется каждые 12 часов, поэтому всякий раз, когда у вас есть новый коммит, он будет добавлен в вашу анимацию змеи.</li>
    <li id="0611">Последний шаг — вернуться на страницу «<strong><em>Действия</em></strong>» файла README, щелкнуть только что созданный рабочий процесс «<strong><em>Создать данные</em></strong>» или любое имя, которое вы ему дадите, и нажать кнопку «<strong><em>Запустить рабочий процесс</em></strong>».</li>
  </ul>
  <figure id="3cKk" class="m_custom" data-caption-align="center">
    <img src="https://miro.medium.com/max/700/1*sirkSkcYLraQPm9wBKVJBA.png" width="700" />
    <figcaption>Запустите свой рабочий процесс</figcaption>
  </figure>
  <p id="4e31">И вуаля! Теперь ваш график вклада Snake в GitHub активен. Наслаждайтесь просмотром, как эта змея съедает вашу тяжелую работу! Чтобы завершить все это, я просто добавил еще одну анимацию рендеринга капсулы в нижний колонтитул, которая выглядела хорошо, как вы можете видеть в GIF выше.</p>
  <p id="8934">Я также упомянул дополнительный список ресурсов для ваших индивидуальных потребностей в дизайне:</p>
  <ul id="m08Y">
    <li id="4999"><a href="https://github.com/abhisheknaiidu/awesome-github-profile-readme" target="_blank"><strong><em>Awesome-GitHub-Profile-Readme</em></strong></a> — список замечательных файлов Readme от многих талантливых разработчиков!</li>
    <li id="8125"><a href="https://rahuldkjain.github.io/gh-profile-readme-generator/" target="_blank"><strong><em>GitHub Readme Generator</em></strong></a> — простой способ быстро создать базовый шаблон дизайна для вашего профиля.</li>
    <li id="db3f">Узнайте больше о <a href="https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions" target="_blank"><strong><em>действиях GitHub</em></strong></a> , если вы заинтересованы в автоматизации.</li>
    <li id="b188">Создавайте различные <a href="https://github.com/lowlighter/metrics" target="_blank"><strong><em>метрики GitHub</em></strong></a> , которые можно встраивать где угодно.</li>
    <li id="3923">Если вам нужен быстрый и простой способ создания cronjobs и узнать о них больше, то <a href="https://crontab.guru/" target="_blank"><strong><em>Crontab Guru</em></strong></a> — довольно хороший ресурс, и вы узнаете точное время, когда будет выполняться ваш рабочий процесс.</li>
  </ul>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@alzheimer/standard-diamond</guid><link>https://teletype.in/@alzheimer/standard-diamond?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=alzheimer</link><comments>https://teletype.in/@alzheimer/standard-diamond?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=alzheimer#comments</comments><dc:creator>alzheimer</dc:creator><title>Как внедрить стандарт Diamond</title><pubDate>Wed, 22 Feb 2023 11:20:12 GMT</pubDate><media:content medium="image" url="https://img3.teletype.in/files/a9/df/a9df84c7-f8ea-4bfb-95ae-57fedf83e9b1.png"></media:content><description><![CDATA[<img src="https://img4.teletype.in/files/fa/ce/face3538-12d5-4517-8021-532813c9783e.jpeg"></img>Diamond Standard, EIP-2535, был создан Ником Маджем как стандартизированная архитектура для реализации смарт-контрактов через прокси. В этой статье мы рассмотрим плюсы использования Diamond Standard и принципы его работы.]]></description><content:encoded><![CDATA[
  <figure id="PtuO" class="m_column">
    <img src="https://img4.teletype.in/files/fa/ce/face3538-12d5-4517-8021-532813c9783e.jpeg" width="1280" />
  </figure>
  <p id="ad2b">Diamond Standard, EIP-2535, был создан Ником Маджем как стандартизированная архитектура для реализации смарт-контрактов через прокси. В этой статье мы рассмотрим плюсы использования Diamond Standard и принципы его работы.</p>
  <h1 id="3a50">Общий обзор</h1>
  <p id="a0ee">Алмазный стандарт работает путем развертывания контракта под названием <code>Diamond.sol</code>. <code>Diamond.sol</code>, затем вызывает другие смарт-контракты через <code>delegatecall()</code>. Это позволяет <code>Diamond.sol</code>выполнять код вызываемого контракта в контексте <code>Diamond.sol</code>. Все контракты, которые вызываются с помощью, <code>delegatecall()</code>называются фасетами. Фасеты можно заменять, удалять и добавлять с течением времени, что позволяет разработчикам создавать модульные приложения на блокчейнах, совместимых с EVM. Алмазный стандарт требует от вас реализации <code>DiamondLoupeFacet.sol</code>. <code>DiamondLoupeFacet.sol</code>отвечает за документирование других аспектов вашего протокола. <code>DiamondLoupeFacet.sol</code>обеспечивает прозрачность, позволяя пользователям видеть адреса и функции фасетов. Еще одно требование Алмазного стандарта <code>DiamondCutFacet.sol</code>. <code>DiamondCutFacet.sol</code>отвечает за все обновления вашего приложения.<code>DiamondCutFacet.sol</code>также генерирует события при вызове, обеспечивая другой уровень прозрачности для пользователей протокола. Хотя это и не является обязательным требованием, <code>LibDiamond.sol</code>это библиотека, которая предоставляет множество вспомогательных функций для написания приложения с помощью стандарта Diamond. При создании приложения с помощью Diamond Standard вы можете использовать один из двух способов сохранения переменных состояния. Их называют <code>App Storage</code>и <code>Diamond Storage</code>. Мы рассмотрим все компоненты Diamond Standard более подробно в оставшейся части статьи.</p>
  <p id="c405">Алмазный стандарт имеет три различных варианта реализации. К счастью, если вы решите, что выбрали неправильную реализацию, можно обновить приложение до другой реализации. <code>diamond-1</code>является самой базовой реализацией. Сложность <code>diamond-1</code>проще всего понять, а затраты на газ самые низкие. Не рекомендуется вызывать <code>DiamondLoupeFacet.sol</code>функции по цепочке с <code>diamond-1</code>(или <code>diamond-2</code>) из-за высоких затрат на газ. <code>diamond-3</code>, с другой стороны, выбирает оптимизацию <code>DiamondLoupeFacet.sol</code>функций вызова в цепочке. Компромисс заключается в том, что звонки обходятся дороже <code>DiamondCutFacet.sol</code>. <code>diamond-2</code>очень похоже на<code>diamond-1</code>, но оптимизирует затраты на газ по сравнению со сложностью для понимания. Вам, как разработчику, решать, какая из этих реализаций лучше всего подходит для вашего приложения.</p>
  <p id="4f83">Из-за сложности Diamond Standard рекомендуется следовать общему шаблону при создании приложений. Я свяжу эти шаблоны внизу статьи вместе с дополнительными материалами для чтения.</p>
  <h1 id="9ec4">Зачем использовать Алмазный стандарт?</h1>
  <p id="96bb">Основная критика стандарта Diamond — его сложность (надеюсь, я смогу помочь решить эту проблему). Несмотря на сложность, Diamond Standard обеспечивает следующие преимущества:</p>
  <ul id="wyBC">
    <li id="7b53">Практических ограничений на размер вашего приложения нет. Все смарт-контракты имеют максимальный размер 24 КБ. Поскольку Diamond Standard использует <code>Diamond.sol</code>свои <code>delegatecall()</code>грани, размер контракта остается относительно небольшим.</li>
    <li id="b591">Вы используете только один адрес для множества функций. Опять же, благодаря <code>delegatecall()</code>, вы можете добавить все необходимые функции в один смарт-контракт. Это включает в себя реализацию токенов с тем же адресом, что и ваш протокол.</li>
    <li id="7557">Он обеспечивает организованный способ обновления ваших смарт-контрактов. Это может помочь аудиторам понять и защитить ваше приложение.</li>
    <li id="0cbe">Это позволяет вам постепенно обновлять свои смарт-контракты. Вместо повторного развертывания всего контракта вы можете просто добавить, заменить или удалить фасет, чтобы обеспечить желаемую функциональность вашего приложения.</li>
    <li id="0a0c">Это обеспечивает высокий уровень прозрачности для вашего прокси-контракта. Как упоминалось ранее, <code>DiamondLoupeFacet.sol</code>позволяет пользователям видеть, где находятся ваши функции в блокчейне и что они выполняют. Посетите <a href="https://louper.dev/" target="_blank">https://louper.dev/</a> , чтобы проанализировать функциональность смарт-контрактов, использующих преимущества Diamond Standard.</li>
    <li id="6130">Практически нет ограничений на количество аспектов, которые можно использовать в вашем приложении. Единственный способ, которым вы не сможете добавить больше фасетов в свой протокол, — это <code>Diamond.sol</code>нехватка места для хранения данных фасетов. Для этого потребуется смехотворно большое количество граней, вплоть до того, что это практически невозможно.</li>
    <li id="4939">Фасеты могут быть повторно использованы несколькими <code>Diamond.sol</code>контрактами. Это позволяет экономить на газе при развертывании приложений, которые заимствуют функциональные возможности.</li>
    <li id="9893">При желании вы можете запустить оптимизатор с более высокими настройками. Оптимизатор Solidity помогает оптимизировать затраты газа при вызове внешних функций. Однако это увеличивает байт-код развертывания контракта. Это может привести к тому, что ваш смарт-контракт превысит максимальный размер смарт-контракта. Поскольку вы можете развертывать столько аспектов, сколько хотите, вы можете настроить оптимизатор на столько запусков, сколько пожелаете, не беспокоясь о том, что ваш контракт слишком велик.</li>
  </ul>
  <p id="b38a">Есть много причин, по которым вы хотели бы использовать Diamond Standard в своем приложении, но не забывайте слишком усложнять свое приложение. Если ваш протокол может работать с одним смарт-контрактом и ни одно из вышеперечисленных преимуществ не применимо к вашему приложению, нет необходимости использовать Diamond Standard. В конечном итоге это только усложнит ваше приложение и увеличит расходы на газ. Однако, если вы находитесь в ситуации, когда вам нужен шаблон прокси для вашего приложения, я лично рекомендую использовать Diamond Standard.</p>
  <h1 id="2496">Хранилище приложений и алмазное хранилище</h1>
  <p id="3389">Архитектура переменных состояния — один из наиболее важных аспектов вашего блокчейн-приложения. Я решил сначала рассмотреть этот раздел, чтобы дать вам хорошее представление о том, как переменные состояния управляются с помощью Diamond Standard. Очевидно, что прокси в значительной степени полагаются на <code>delegatecall()</code>выполнение кода из ваших фасетных контрактов в контексте вашего основного контракта ( <code>Diamond.sol</code>). Поскольку все хранилище наших переменных состояния хранится в <code>Diamond.sol</code>, нам нужно убедиться, что наши переменные не перезаписывают друг друга. Прежде чем мы рассмотрим правильный способ организации наших переменных состояния, давайте рассмотрим пример неправильного способа управления переменными состояния.</p>
  <p id="ITjQ"></p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="htiO">pragma solidity^0.8.17;0.8.17;</p>
    <p id="zC00">contract Main {<br /> uint256 public verySpecialVar;<br /> uint256 public notSoSpecialVar;<br /> // delegate calls SpecialVarManager to update verySpecialVar<br /> function setVerySpecialVar(address _specialVarManager) external {<br /> _specialVarManager.delegatecall(<br /> abi.encodeWithSignature(&quot;writeSpecialVar()&quot;)<br /> );<br /> }<br /> // delegate calls NotSpecialVarManager to update notSoSpecialVar<br /> function setNotSoSpecialVar(address _notSpecialVarManager) external {<br /> _notSpecialVarManager.delegatecall(<br /> abi.encodeWithSignature(&quot;writeNotSpecialVar()&quot;)<br /> );<br /> }</p>
    <p id="zA4m">}<br />contract SpecialVarManager {<br /> uint256 verySpecialVar;<br /> function writeSpecialVar() external {<br /> verySpecialVar = 100;<br /> }<br />}<br />contract NotSpecialVarManager {<br /> uint256 notSoSpecialVar;<br /> function writeNotSpecialVar() external {<br /> notSoSpecialVar = 50;<br /> }<br />}</p>
  </section>
  <p id="9f2d">Если вы позвоните, <code>setVerySpecialVar()</code>вы увидите, <code>verySpecialVar</code>что был обновлен до 100! Теперь давайте позвоним <code>setNotSoSpecialVar</code>и посмотрим, что произойдет. Мы видим, <code>notSoSpecialVar</code>что он все еще не инициализирован и равен 0. Если мы проверим, то <code>verySpecialVar</code>увидим, что сейчас он установлен на 50. Почему? Ну, в схеме хранения <code>NotSpecialVarManager</code>нет <code>verySpecialVar</code>. Поэтому, когда мы вызываем <code>writeNotSpecialVar()</code>via, <code>delegatecall()</code>мы сообщаем <code>Main</code>об обновлении слота хранения с 0 до 50. Solidity не заботится о том, как вы называете свои переменные; он смотрит только на положение слота для хранения.</p>
  <p id="90bd">Имея это в виду, нам нужен способ организовать наши переменные состояния, чтобы мы не перезаписывали наши слоты хранения. Первый способ сделать это — с помощью Diamond Storage.</p>
  <p id="b8d1">Diamond Storage использует количество слотов для хранения Solidity в смарт-контракте (2²⁵⁶). Теория, лежащая в основе Diamond Storage, заключается в том, что, поскольку слотов для хранения так много, что если мы хэшируем уникальное значение, мы получим случайный слот для хранения, который почти наверняка не будет конфликтовать с другим слотом для хранения. Это может показаться рискованным, но на самом деле это тот же процесс, который Solidity использует для хранения отображений и динамических массивов. Diamond Storage дает возможность вашим фасетам сохранять переменные состояния, специфичные для их контракта, а также позволяет фасетам совместно использовать переменные состояния, если это необходимо.</p>
  <p id="fec1">Поскольку сложность Diamond Standard требует небольшой настройки, для этих примеров хранения я не буду использовать Diamond Standard. Основная цель этого раздела — понять принципы хранения переменных состояния. Реализация в Diamond Standard в основном такая же.</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="Zt1P">pragma solidity^0.8.17;0.8.17;</p>
    <p id="z5SU">library SharedLib {<br /> // struct that with state variable<br /> struct DiamondStorage {<br /> uint256 sharedVar;<br /> }<br /> // returns a storage variable with our state variable<br /> function diamondStorage() internal pure returns(DiamondStorage storage ds) {<br /> // gets a &quot;random&quot; storage positon by hashing a string<br /> bytes32 storagePosition = keccak256(abi.encode(&quot;Diamond.Storage.SharedLib&quot;));<br /> // assigns our struct storage slot to storage position<br /> assembly {<br /> ds.slot := storagePosition<br /> }</p>
    <p id="eCW0">}<br />}<br />// not the actual Diamond Standard<br />contract PseudoDiamond {<br /> // delegate calls Facet1 to update sharedVar<br /> function writeToSharedVar(address _facet1, uint256 _value) external {<br /> // writes via delegate call<br /> _facet1.delegatecall(<br /> abi.encodeWithSignature(&quot;writeShared(uint256)&quot;, _value)<br /> );<br /> }<br /> // delegate calls Facet2 to read sharedVar<br /> function readSharedVar(address _facet2) external returns (uint256) {<br /> // returns result of delegate call<br /> (bool success, bytes memory _valueBytes) = _facet2.delegatecall(<br /> abi.encodeWithSignature(&quot;readShared()&quot;)<br /> );<br /> // since return value is bytes array we use assembly to retrieve our uint<br /> bytes32 _value;<br /> assembly {<br /> let location := _valueBytes<br /> _value := mload( add(location, 0x20) )<br /> }<br /> return uint256(_value);<br /> }<br />}<br />contract Facet1 {<br /> function writeShared(uint256 _value) external {<br /> // initializes the storage struct by calling library function<br /> SharedLib.DiamondStorage storage ds = SharedLib.diamondStorage();<br /> // writes to shared variable<br /> ds.sharedVar = _value;</p>
    <p id="E9Zz">}<br />}<br />contract Facet2 {</p>
    <p id="4Q6w">function readShared() external view returns (uint256) {<br /> // initializes the storage struct by calling library function<br /> SharedLib.DiamondStorage storage ds = SharedLib.diamondStorage();</p>
    <p id="MI1r">// returns shared variable<br /> return ds.sharedVar;</p>
    <p id="qFnS">}<br />}</p>
  </section>
  <p id="182e">Если вы позвоните <code>PseudoDiamond.writeSharedVar()</code>, то <code>PseudoDiamond.readSharedVar()</code>увидите свое значение. Используя библиотеку и индексируя «случайный» слот для хранения, мы можем обмениваться переменными между двумя смарт-контрактами. Когда мы используем <code>delegatecall()</code>оба аспекта, он смотрит на позицию хранения структуры <code>DiamondStorage</code>для доступа к этой переменной. Благодаря явной связи между аспектами того, где мы хотим хранить наши данные, мы предотвращаем коллизии переменных состояния. Если вы хотите иметь переменные состояния только для одного из ваших аспектов, вы можете просто создать библиотеку, аналогичную <code>SharedLib</code>, и реализовать ее только в этом конкретном аспекте.</p>
  <p id="96ed">Хранилище приложений работает немного по-другому. Вы создаете файл Solidity, а внутри этого файла создаете структуру с именем <code>AppStorage</code>. Затем вы помещаете в эту структуру столько переменных состояния, сколько хотите, включая другие структуры. Затем первое, что вы делаете внутри своих смарт-контрактов, — это инициализируете их <code>AppStorage</code>. Это устанавливает слот хранения 0 в начало структуры. Это создает удобочитаемое общее состояние между контрактами. Давайте посмотрим на пример!</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="Vzam">pragma solidity^0.8.17;</p>
    <p id="0HEV">// struct with state variable<br />struct StateVars {<br /> uint256 sharedVar;<br />}<br />// our app storage struct<br />struct AppStorage {<br /> StateVars state;<br />}<br />// not the actual Diamond Standard<br />contract PseudoDiamond {<br /> AppStorage s;<br /> // delegate calls Facet1 to update sharedVar<br /> function writeToSharedVar(address _facet1, uint256 _value) external {<br /> // writes via delegate call<br /> _facet1.delegatecall(<br /> abi.encodeWithSignature(&quot;writeShared(uint256)&quot;, _value)<br /> );<br /> }<br /> // delegate calls Facet2 to read sharedVar<br /> function readSharedVar(address _facet2) external returns (uint256) {<br /> // returns result of delegate call<br /> (bool success, bytes memory _valueBytes) = _facet2.delegatecall(<br /> abi.encodeWithSignature(&quot;readShared()&quot;)<br /> );<br /> // since return value is bytes array we use assembly to retrieve our uint<br /> bytes32 _value;<br /> assembly {<br /> let location := _valueBytes<br /> _value := mload( add(location, 0x20) )<br /> }<br /> return uint256(_value);<br /> }<br />}<br />contract Facet1 {<br /> AppStorage s;<br /> function writeShared(uint256 _value) external {<br /> // writes to our state variable in storage<br /> s.state.sharedVar = _value;<br /> }<br />}<br />contract Facet2 {<br /> AppStorage s;</p>
    <p id="Ggnk"> function readShared() external view returns (uint256) {<br /> // returns state variable from app storage<br /> return s.state.sharedVar;<br /> }<br />}</p>
  </section>
  <p id="51cd">Если вы посмотрите на значение в слоте хранения 0 для <code>PseudoDiamond</code>, вы увидите 100, что является нашим значением! Важное замечание о App Storage: если вам нужно обновить AppStorage после развертывания, обязательно добавьте новые переменные состояния в конец AppStorage, чтобы предотвратить коллизии хранилища. Лично я предпочитаю App Storage для организации Diamond Storage, но оба они выполняют свою работу. Также стоит отметить, что Diamond Storage и App Storage не являются эксклюзивными. Даже если вы используете App Storage для управления переменными состояния <code>LibDiamond.sol</code>, используйте Diamond Storage для управления данными аспектов.</p>
  <h1 id="a1e5">Diamond.sol</h1>
  <p id="f9ab">Как упоминалось ранее, <code>Diamond.sol</code>это смарт-контракт, который вызывается при взаимодействии с вашим приложением. Если это помогает думать об этом таким образом, <code>Diamond.sol</code>«управляет» остальной частью вашего приложения. Все фасетные функции будут казаться <code>Diamond.sol</code>собственными функциями .</p>
  <p id="d9dd">Давайте сначала посмотрим, что происходит в конструкторе <code>diamond-1</code>.</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="HaXe">// This is used in diamond constructor<br />// more arguments are added to this struct<br />// this avoids stack too deep errors<br />struct DiamondArgs {<br /> address owner;<br /> address init;<br /> bytes initCalldata;<br />}</p>
    <p id="442F">contract Diamond { <br /> constructor(IDiamondCut.FacetCut[] memory _diamondCut, DiamondArgs memory _args) payable {<br /> LibDiamond.setContractOwner(_args.owner);<br /> LibDiamond.diamondCut(_diamondCut, _args.init, _args.initCalldata);<br /> // Code can be added here to perform actions and set state variables.<br /> }<br /> // rest of code<br />}</p>
  </section>
  <p id="izMN">Во-первых, вне контракта у нас есть структура, которая форматирует наши данные. Затем мы передаем эту структуру в качестве параметра вместе с другой структурой, которая выглядит так:</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="gxfE">struct FacetCut {<br /> address facetAddress;address facetAddress;<br /> FacetCutAction action;<br /> bytes4[] functionSelectors;<br />}</p>
  </section>
  <p id="63f9"><code>FacetCut</code>предоставляет адрес фасета, действие, которое мы хотим выполнить с фасетом (добавить, заменить или удалить), и селекторы функций для функций фасета. Затем мы устанавливаем владельца контракта и добавляем любые данные фасета, предоставленные Diamond. Позже мы более подробно рассмотрим, как это работает. После этого, если мы захотим, мы можем инициализировать переменные состояния. Имейте в виду, что вы никогда не должны выполнять какие-либо назначения переменных состояния в конструкторе фасета, потому что он будет выполнять эту операцию внутри смарт-контракта фасета, а не <code>Diamond.sol</code>.</p>
  <p id="9dbe">Пока все выглядит довольно просто, поэтому давайте посмотрим, что происходит в конструкторе для <code>diamond-2</code>и <code>diamond-3</code>.</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="i4I3">contract Diamond { </p>
    <p id="Qugv"> constructor(address _contractOwner, address _diamondCutFacet) payable { <br /> LibDiamond.setContractOwner(_contractOwner);<br /> // Add the diamondCut external function from the diamondCutFacet<br /> IDiamondCut.FacetCut[] memory cut = new IDiamondCut.FacetCut[](1);<br /> bytes4[] memory functionSelectors = new bytes4[](1);<br /> functionSelectors[0] = IDiamondCut.diamondCut.selector;<br /> cut[0] = IDiamondCut.FacetCut({<br /> facetAddress: _diamondCutFacet,<br /> action: IDiamondCut.FacetCutAction.Add,<br /> functionSelectors: functionSelectors<br /> });<br /> LibDiamond.diamondCut(cut, address(0), &quot;&quot;); <br /> }<br /> // rest of code<br />}</p>
  </section>
  <p id="1663">На этот раз мы передаем только владельца контракта и адрес <code>DiamondCutFacet.sol</code>. Далее мы назначаем владельца Алмаза. После этого мы добавляем <code>diamondCut()</code>функцию, чтобы мы могли добавить больше аспектов. Мы делаем это, сначала инициализируя массив памяти одним элементом типа struct <code>FacetCut</code>, который мы видели ранее. Затем мы инициализируем другой массив одним элементом. На этот раз это массив <code>bytes4</code>, и он используется для хранения <code>diamondCut()</code>селектора функций . Затем мы назначаем селектор функции массиву, вызывая функцию интерфейса Diamond Cut <code>diamondCut</code>и получая ее селектор. После этого мы можем назначить <code>cut[0]</code>. Мы используем адрес <code>DiamondCutFacet.sol</code>, add (потому что мы хотим добавить эту грань к нашему Алмазу) и массив селекторов функций. Наконец, мы фактически добавляем<code>diamondCut</code>. Это много незнания того, что происходит под капотом, поэтому, если это поможет, вы можете перечитать этот раздел после того, как мы пройдемся по <code>DiamondCut.sol</code>. Пока просто поймите, что мы добавляем фасеты в конструкторе.</p>
  <p id="c8a5">Последняя часть — <code>Diamond.sol</code>это <code>fallback()</code>функция. Вот как мы будем называть наши грани в Diamond Standard. Он выглядит почти одинаково во всех трех реализациях Diamond Standard, так что давайте рассмотрим его!</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="15ai">// Find facet for function that is called and execute the<br />// function if a facet is found and return any value.<br />fallback() external payable {<br /> LibDiamond.DiamondStorage storage ds;<br /> bytes32 position = LibDiamond.DIAMOND_STORAGE_POSITION;<br /> // get diamond storage<br /> assembly {<br /> ds.slot := position<br /> }<br /> // get facet from function selector<br /> address facet = address(bytes20(ds.facets[msg.sig]));<br /> require(facet != address(0), &quot;Diamond: Function does not exist&quot;);<br /> // Execute external function from facet using delegatecall and return any value.<br /> assembly {<br /> // copy function selector and any arguments<br /> calldatacopy(0, 0, calldatasize())<br /> // execute function call using the facet<br /> let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0)<br /> // get any return value<br /> returndatacopy(0, 0, returndatasize())<br /> // return any return value or error back to the caller<br /> switch result<br /> case 0 {<br /> revert(0, returndatasize())<br /> }<br /> default {<br /> return(0, returndatasize())<br /> }<br /> }<br />}</p>
  </section>
  <p id="f3Vs">Первое, что мы делаем, это инициализируем Diamond Storage. Здесь мы будем хранить данные нашего фасета. Далее, где находится разница в <code>fallback()</code>s. Мы смотрим <code>diamond-2</code>выше. Во всех трех мы проверяем, существует ли адрес фасета.<br />Вот как мы регистрируемся <code>diamond-1</code>:</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="wnac">// get facet from function selector<br />address facet = ds.facetAddressAndSelectorPosition[msg.sig].facetAddress;<br />if(facet == address(0)) {<br /> revert FunctionNotFound(msg.sig);<br />}</p>
  </section>
  <p id="SpDC">Вот как мы регистрируемся <code>diamond-3</code>:</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="cMaU">// get facet from function selector<br />address facet = ds.selectorToFacetAndPosition[msg.sig].facetAddress;<br />require(facet != address(0), &quot;Diamond: Function does not exist&quot;);</p>
  </section>
  <p id="6a63">Основное различие в трех реализациях заключается в том, что <code>diamond-2</code>мы храним селекторы в сопоставлении 32-байтовых слотов памяти.</p>
  <p id="e37b">Наконец, мы используем Yul для <code>delegatecall()</code>наших аспектов, копируя данные вызова, которые были отправлены на <code>Diamond.sol</code>, и проверяя, был ли вызов успешным.</p>
  <p id="d13c">На этом наш раздел о <code>Diamond.sol</code>. Далее мы рассмотрим, что происходило, когда мы звонили <code>diamondCut()</code>.</p>
  <h1 id="2ca4">DiamondCut.sol</h1>
  <p id="60b9">Как мы уже обсуждали, <code>DiamondCut.sol</code>отвечает за добавление, удаление и замену граней в нашем Алмазе. Все три реализации используют несколько иной подход, но достигают одной и той же цели. Давайте посмотрим, как <code>diamond-1</code>работает.</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="yfih">contract DiamondCutFacet is IDiamondCut {<br /> /// @notice Add/replace/remove any number of functions and optionally execute/// @notice Add/replace/remove any number of functions and optionally execute<br /> /// a function with delegatecall<br /> /// @param _diamondCut Contains the facet addresses and function selectors<br /> /// @param _init The address of the contract or facet to execute _calldata<br /> /// @param _calldata A function call, including function selector and arguments<br /> /// _calldata is executed with delegatecall on _init<br /> function diamondCut(<br /> FacetCut[] calldata _diamondCut,<br /> address _init,<br /> bytes calldata _calldata<br /> ) external override {<br /> LibDiamond.enforceIsContractOwner();<br /> LibDiamond.diamondCut(_diamondCut, _init, _calldata);<br /> }<br />}</p>
  </section>
  <p id="a950">Как видите, этот контракт сильно зависит от <code>LibDiamond.sol</code>. Все, что мы делаем, исходя из общего обзора, — это проверяем, что владелец контракта сделал этот вызов, а затем вызываем <code>diamondCut()</code>. Давайте посмотрим, что происходит в <code>LibDiamond.sol</code>. Прежде чем мы это сделаем, я должен указать на одну большую деталь о <code>LibDiamond.sol</code>. <code>LibDiamond.sol</code>использует исключительно <code>internal</code>функции. Это добавляет байт-код к нашему контракту, избавляя нас от необходимости использовать другой файл <code>delegatecall()</code>.</p>
  <p id="75e9">Хорошо, теперь, когда мы понимаем, как сэкономить на топливе в <code>LibDiamond.sol</code>, давайте посмотрим на код <code>diamondCut()</code>.</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="6qEl">// Internal function version of diamondCut<br />function diamondCut(<br /> IDiamondCut.FacetCut[] memory _diamondCut,<br /> address _init,<br /> bytes memory _calldata<br />) internal {<br /> for (uint256 facetIndex; facetIndex &lt; _diamondCut.length; facetIndex++) {<br /> bytes4[] memory functionSelectors = _diamondCut[facetIndex].functionSelectors;<br /> address facetAddress = _diamondCut[facetIndex].facetAddress;<br /> if(functionSelectors.length == 0) {<br /> revert NoSelectorsProvidedForFacetForCut(facetAddress);<br /> }<br /> IDiamondCut.FacetCutAction action = _diamondCut[facetIndex].action;<br /> if (action == IDiamond.FacetCutAction.Add) {<br /> addFunctions(facetAddress, functionSelectors);<br /> } else if (action == IDiamond.FacetCutAction.Replace) {<br /> replaceFunctions(facetAddress, functionSelectors);<br /> } else if (action == IDiamond.FacetCutAction.Remove) {<br /> removeFunctions(facetAddress, functionSelectors);<br /> } else {<br /> revert IncorrectFacetCutAction(uint8(action));<br /> }<br /> }<br /> emit DiamondCut(_diamondCut, _init, _calldata);<br /> initializeDiamondCut(_init, _calldata);<br />}</p>
  </section>
  <p id="11bc">Мы берем те же параметры, что и раньше для этой функции. Сначала мы прокручиваем нашу <code>FacetCut</code>структуру. Внутри цикла мы получаем наш селектор функций и адрес фасетной функции. Мы удостоверяемся, что селектор фасета действителен, и возвращаемся в противном случае. Затем нам нужно проверить действие, которое мы выполняем с этой конкретной функцией (добавить, заменить или удалить). Найдя действие, мы вызываем вспомогательную функцию, которая коррелирует с этим действием. Затем мы создаем событие, чтобы обеспечить прозрачность для наших пользователей. Наконец, мы проверяем, работает ли наш фасет, <code>initializeDiamondCut()</code>проверяя, имеет ли наш контракт код и может ли он быть вызван через <code>delegatecall()</code>with <code>_calldata</code>.</p>
  <p id="cf19">Теперь, когда мы знаем, как это <code>diamondCut()</code>работает, давайте посмотрим, как мы выполняем каждое действие, начинающееся с <code>Add</code>.</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="QolY">function addFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal { addFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal { <br /> if(_facetAddress == address(0)) {<br /> revert CannotAddSelectorsToZeroAddress(_functionSelectors);<br /> }<br /> DiamondStorage storage ds = diamondStorage();<br /> uint16 selectorCount = uint16(ds.selectors.length); <br /> enforceHasContractCode(_facetAddress, &quot;LibDiamondCut: Add facet has no code&quot;);<br /> for (uint256 selectorIndex; selectorIndex &lt; _functionSelectors.length; selectorIndex++) {<br /> bytes4 selector = _functionSelectors[selectorIndex];<br /> address oldFacetAddress = ds.facetAddressAndSelectorPosition[selector].facetAddress;<br /> if(oldFacetAddress != address(0)) {<br /> revert CannotAddFunctionToDiamondThatAlreadyExists(selector);<br /> } <br /> ds.facetAddressAndSelectorPosition[selector] = FacetAddressAndSelectorPosition(_facetAddress, selectorCount);<br /> ds.selectors.push(selector);<br /> selectorCount++;<br /> }<br />}</p>
  </section>
  <p id="c61c">Входными параметрами являются адрес фасетного контракта и селектор конкретной функции, с которой мы работаем. Мы хотим убедиться, что этот контракт существует, проверив, является ли адрес нулевым адресом. Далее мы инициализируем Diamond Storage. Затем мы получаем количество селекторов, которые уже есть у нашего Алмаза. После этого мы проверяем, есть ли у нашего фасета код контракта. Теперь нам нужно убедиться, что этой функции еще нет в Diamond. Мы делаем это, перебирая селекторы функций и проверяя, существует ли уже адрес. В противном случае мы нажимаем наш селектор на наши сохраненные селекторы.</p>
  <p id="0a36">Теперь давайте посмотрим, как заменить грань!</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="UizW">function replaceFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal { replaceFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal { <br /> DiamondStorage storage ds = diamondStorage();<br /> if(_facetAddress == address(0)) {<br /> revert CannotReplaceFunctionsFromFacetWithZeroAddress(_functionSelectors);<br /> }<br /> enforceHasContractCode(_facetAddress, &quot;LibDiamondCut: Replace facet has no code&quot;);<br /> for (uint256 selectorIndex; selectorIndex &lt; _functionSelectors.length; selectorIndex++) {<br /> bytes4 selector = _functionSelectors[selectorIndex];<br /> address oldFacetAddress = ds.facetAddressAndSelectorPosition[selector].facetAddress;<br /> // can&#x27;t replace immutable functions — functions defined directly in the diamond in this case<br /> if(oldFacetAddress == address(this)) {<br /> revert CannotReplaceImmutableFunction(selector);<br /> }<br /> if(oldFacetAddress == _facetAddress) {<br /> revert CannotReplaceFunctionWithTheSameFunctionFromTheSameFacet(selector);<br /> }<br /> if(oldFacetAddress == address(0)) {<br /> revert CannotReplaceFunctionThatDoesNotExists(selector);<br /> }<br /> // replace old facet address<br /> ds.facetAddressAndSelectorPosition[selector].facetAddress = _facetAddress;<br /> }<br />}</p>
  </section>
  <p id="d075">Как вы могли заметить, <code>Replace</code>запускается так же, как <code>Add</code>. Мы инициализируем Diamond Storage, проверяем, имеет ли фасет допустимый адрес и размер кода, затем прокручиваем селекторы. Во-первых, мы проверяем, является ли селектор неизменным. Затем мы проверяем, является ли функция, которую мы хотим заменить, той же функцией, которую мы добавляем. После этого мы проверяем, действителен ли адрес фасета. В противном случае мы заменяем нашу грань.</p>
  <p id="9ed1">Теперь давайте проверим наше последнее действие, <code>Remove</code>.</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="6OU5">function removeFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal { removeFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal { <br /> DiamondStorage storage ds = diamondStorage();<br /> uint256 selectorCount = ds.selectors.length;<br /> if(_facetAddress != address(0)) {<br /> revert RemoveFacetAddressMustBeZeroAddress(_facetAddress);<br /> } <br /> for (uint256 selectorIndex; selectorIndex &lt; _functionSelectors.length; selectorIndex++) {<br /> bytes4 selector = _functionSelectors[selectorIndex];<br /> FacetAddressAndSelectorPosition memory oldFacetAddressAndSelectorPosition = ds.facetAddressAndSelectorPosition[selector];<br /> if(oldFacetAddressAndSelectorPosition.facetAddress == address(0)) {<br /> revert CannotRemoveFunctionThatDoesNotExist(selector);<br /> }</p>
    <p id="dVOQ"> // can&#x27;t remove immutable functions — functions defined directly in the diamond<br /> if(oldFacetAddressAndSelectorPosition.facetAddress == address(this)) {<br /> revert CannotRemoveImmutableFunction(selector);<br /> }<br /> // replace selector with last selector<br /> selectorCount--;<br /> if (oldFacetAddressAndSelectorPosition.selectorPosition != selectorCount) {<br /> bytes4 lastSelector = ds.selectors[selectorCount];<br /> ds.selectors[oldFacetAddressAndSelectorPosition.selectorPosition] = lastSelector;<br /> ds.facetAddressAndSelectorPosition[lastSelector].selectorPosition = oldFacetAddressAndSelectorPosition.selectorPosition;<br /> }<br /> // delete last selector<br /> ds.selectors.pop();<br /> delete ds.facetAddressAndSelectorPosition[selector];<br /> }<br />}</p>
  </section>
  <p id="bc12">Опять же, мы начинаем с инициализации Diamond Storage, проверяя, имеет ли фасет действительный адрес, а затем прокручиваем селекторы. Затем мы получаем селектор функций и позицию в памяти. Мы проверяем, что он действительно существует, а затем проверяем, что он не является неизменным. После этого мы перемещаем наш селектор в конец массива и выполняем операцию <code>pop()</code>для его удаления.</p>
  <p id="1e4f"><code>diamond-2</code>и <code>diamond-3</code>обе достигают той же цели, что и <code>diamond-1</code>функция <code>diamondCut()</code>, но используют другой синтаксис и архитектуру. Для простоты этой статьи мы не будем останавливаться на них. Однако, если достаточное количество людей будет заинтересовано в том, чтобы узнать, как они работают, я могу написать новую статью в будущем, в которой будут более подробно описаны различия в реализациях.</p>
  <h1 id="29a6">LoupeFacet.sol</h1>
  <p id="82f3">Теперь, когда мы понимаем, как обновлять функции в нашем Алмазе, давайте рассмотрим, как мы можем просматривать наши грани. Помните, что for <code>diamond-1</code>и <code>diamond-2</code>не рекомендуется вызывать эти функции по цепочке. <code>diamond-3</code>, однако сильно оптимизирован для вызова этих функций в цепочке. Опять же, мы будем только повторяться <code>diamond-1</code>, но если вы понимаете, что происходит, вы должны быть в состоянии как понять, так и реализовать любую из других реализаций Diamond Standard.</p>
  <p id="f890">Сначала мы рассмотрим <code>facets()</code>. <code>facets()</code>, возвращает все грани и их селекторы для Diamond.</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="K8lg">function facets() external override view returns (Facet[] memory facets_) {facets() external override view returns (Facet[] memory facets_) {<br /> LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();<br /> uint256 selectorCount = ds.selectors.length;<br /> // create an array set to the maximum size possible<br /> facets_ = new Facet[](selectorCount);<br /> // create an array for counting the number of selectors for each facet<br /> uint16[] memory numFacetSelectors = new uint16[](selectorCount);<br /> // total number of facets<br /> uint256 numFacets;<br /> // loop through function selectors<br /> for (uint256 selectorIndex; selectorIndex &lt; selectorCount; selectorIndex++) {<br /> bytes4 selector = ds.selectors[selectorIndex];<br /> address facetAddress_ = ds.facetAddressAndSelectorPosition[selector].facetAddress;<br /> bool continueLoop = false;<br /> // find the functionSelectors array for selector and add selector to it<br /> for (uint256 facetIndex; facetIndex &lt; numFacets; facetIndex++) {<br /> if (facets_[facetIndex].facetAddress == facetAddress_) {<br /> facets_[facetIndex].functionSelectors[numFacetSelectors[facetIndex]] = selector; <br /> numFacetSelectors[facetIndex]++;<br /> continueLoop = true;<br /> break;<br /> }<br /> }<br /> // if functionSelectors array exists for selector then continue loop<br /> if (continueLoop) {<br /> continueLoop = false;<br /> continue;<br /> }<br /> // create a new functionSelectors array for selector<br /> facets_[numFacets].facetAddress = facetAddress_;<br /> facets_[numFacets].functionSelectors = new bytes4[](selectorCount);<br /> facets_[numFacets].functionSelectors[0] = selector;<br /> numFacetSelectors[numFacets] = 1;<br /> numFacets++;<br /> }<br /> for (uint256 facetIndex; facetIndex &lt; numFacets; facetIndex++) {<br /> uint256 numSelectors = numFacetSelectors[facetIndex];<br /> bytes4[] memory selectors = facets_[facetIndex].functionSelectors;<br /> // setting the number of selectors<br /> assembly {<br /> mstore(selectors, numSelectors)<br /> }<br /> }<br /> // setting the number of facets<br /> assembly {<br /> mstore(facets_, numFacets)<br /> }<br />}</p>
  </section>
  <p id="ocWJ">Обратите внимание, что входных параметров нет, и мы указываем, что будем возвращать <code>factes_</code>. <code>factes_</code>представляет собой структуру данных, которая выглядит следующим образом:</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="J4Sf">struct Facet {<br /> address facetAddress;address facetAddress;<br /> bytes4[] functionSelectors;<br />}</p>
  </section>
  <p id="3fec">Первое, что мы делаем внутри функции, это инициализируем Diamond Storage. Затем мы получаем количество имеющихся у нас селекторов. После этого мы инициализируем массив, который будем возвращать в конце нашей функции. Затем мы создаем массив для отслеживания количества функций на фасет и переменную для отслеживания количества фасетов. Затем мы прокручиваем наши селекторы функций. Внутри нашего цикла мы ищем, к какому аспекту принадлежит наш селектор. Нам нужно перебрать фасеты, чтобы найти, какой адрес соответствует адресу наших текущих селекторов функций. После того, как мы находим наш фасет, мы добавляем наш селектор функций в массив этого фасета, если он существует. В противном случае мы создаем массив. После того, как мы закончим наш цикл, мы еще раз пройдемся по граням. Внутри этого цикла мы сохраняем количество селекторов в памяти, чтобы вернуться позже. Окончательно, мы сохраняем количество граней и возвращаемся. Причина, по которой мы сохраняем количество селекторов и фасетов, заключается в том, что мы изначально инициализировали наши массивы до максимально возможного размера. Теперь, когда мы знаем, сколько конкретных селекторов и фасетов мы будем возвращать, мы сообщаем Solidity правильный размер возвращаемого массива.</p>
  <p id="13f1">Следующая функция, которую мы рассмотрим, это <code>facetFunctionSelectors()</code>. <code>facetFunctionSelectors()</code>возвращает селекторы функций для определенного аспекта. Он принимает в качестве параметра адрес целевого фасета и возвращает массив, <code>bytes4[]</code>представляющий селекторы функций.</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="ycsy">function facetFunctionSelectors(address _facet) external override view returns (bytes4[] memory _facetFunctionSelectors) {facetFunctionSelectors(address _facet) external override view returns (bytes4[] memory _facetFunctionSelectors) {<br /> LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();<br /> uint256 selectorCount = ds.selectors.length;<br /> uint256 numSelectors;<br /> _facetFunctionSelectors = new bytes4[](selectorCount);<br /> // loop through function selectors<br /> for (uint256 selectorIndex; selectorIndex &lt; selectorCount; selectorIndex++) {<br /> bytes4 selector = ds.selectors[selectorIndex];<br /> address facetAddress_ = ds.facetAddressAndSelectorPosition[selector].facetAddress;<br /> if (_facet == facetAddress_) {<br /> _facetFunctionSelectors[numSelectors] = selector;<br /> numSelectors++;<br /> }<br /> }<br /> // Set the number of selectors in the array<br /> assembly {<br /> mstore(_facetFunctionSelectors, numSelectors)<br /> }<br />}</p>
  </section>
  <p id="35cc">Снова инициализируем Diamond Storage. Затем мы получаем количество селекторов функций и инициализируем наш возвращаемый массив. Далее мы прокручиваем селекторы. Здесь мы проверяем, совпадает ли адрес селектора с нашим целевым аспектом. Если это так, мы сохраняем этот селектор функций. Наконец, мы сохраняем количество селекторов и возвращаемся.</p>
  <p id="aada">Теперь рассмотрим <code>facetAddresses()</code>, который возвращает массив адресов граней нашего Алмаза.</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="5rvl">function facetAddresses() external override view returns (address[] memory facetAddresses_) {facetAddresses() external override view returns (address[] memory facetAddresses_) {<br /> LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();<br /> uint256 selectorCount = ds.selectors.length;<br /> // create an array set to the maximum size possible<br /> facetAddresses_ = new address[](selectorCount);<br /> uint256 numFacets;<br /> // loop through function selectors<br /> for (uint256 selectorIndex; selectorIndex &lt; selectorCount; selectorIndex++) {<br /> bytes4 selector = ds.selectors[selectorIndex];<br /> address facetAddress_ = ds.facetAddressAndSelectorPosition[selector].facetAddress;<br /> bool continueLoop = false;<br /> // see if we have collected the address already and break out of loop if we have<br /> for (uint256 facetIndex; facetIndex &lt; numFacets; facetIndex++) {<br /> if (facetAddress_ == facetAddresses_[facetIndex]) {<br /> continueLoop = true;<br /> break;<br /> }<br /> }<br /> // continue loop if we already have the address<br /> if (continueLoop) {<br /> continueLoop = false;<br /> continue;<br /> }<br /> // include address<br /> facetAddresses_[numFacets] = facetAddress_;<br /> numFacets++;<br /> }<br /> // Set the number of facet addresses in the array<br /> assembly {<br /> mstore(facetAddresses_, numFacets)<br /> }<br />}</p>
  </section>
  <p id="2f14">Опять же, первое, что мы делаем, это инициализируем Diamond Storage, получаем количество селекторов функций и инициализируем наш возвращаемый массив. Мы также снова просматриваем наши селекторы. Мы проверяем адрес фасета нашего селектора. Затем мы проверяем, видели ли мы этот адрес раньше. Если у нас есть, мы пропускаем эту итерацию цикла. В противном случае мы добавляем этот новый адрес в наш возвращаемый массив. Опять же, мы обновляем размер массива и возвращаем его.</p>
  <p id="bce3">Последняя функция, которую мы рассмотрим, <code>DiamondLoupeFacet.sol</code>это <code>facetAddress</code>. Эта функция возвращает адрес фасета, предоставленного селектором функции.</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="FG8c">function facetAddress(bytes4 _functionSelector) external override view returns (address facetAddress_) {facetAddress(bytes4 _functionSelector) external override view returns (address facetAddress_) {<br /> LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();<br /> facetAddress_ = ds.facetAddressAndSelectorPosition[_functionSelector].facetAddress;<br />}</p>
  </section>
  <p id="b8e6">Эта функция довольно проста. Мы инициализируем Diamond Storage и используем то, как мы храним наши селекторы, чтобы вернуть наш адрес фасета.</p>
  <p id="5f49">На этом мы завершаем наш раздел, посвященный аспекту лупы. Теперь мы знаем, как Diamond Standard обеспечивает прозрачность для своих пользователей. Далее мы рассмотрим, как работает развертывание Diamond Standard.</p>
  <h1 id="d054">Как развернуть Diamond Standard</h1>
  <p id="9fac">При развертывании Diamond вам необходимо развернуть фасеты, а затем развернуть файлы <code>Diamond.sol</code>. Таким образом, вы можете сообщить своему Бриллианту, какие контракты он будет вызывать. Самый простой способ развернуть Diamond — с помощью пакета npm <code>diamond-util</code>. Вот как его установить:</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="zlAP">npm i diamond-utili diamond-util</p>
  </section>
  <p id="3dg5">После его установки вы можете развернуть свой Diamond с помощью следующего кода.</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="9RKL">// eslint-disable-next-line no-unused-vars<br />const deployedDiamond = await diamond.deploy({<br /> diamondName: &#x27;LeaseDiamond&#x27;,<br /> facets: [<br /> &#x27;DiamondCutFacet&#x27;,<br /> &#x27;DiamondLoupeFacet&#x27;,<br /> &#x27;Facet1&#x27;,<br /> &#x27;Facet2&#x27;<br /> ],<br /> args: [/* your parameters */]<br />})</p>
    <p id="TXBN">// init facets<br />const diamondCutFacet = await ethers.getContractAt(&#x27;DiamondCutFacet&#x27;, deployedDiamond.address)<br />const diamondLoupeFacet = await ethers.getContractAt(&#x27;DiamondLoupeFacet&#x27;, deployedDiamond.address)<br />const facet1 = await ethers.getContractAt(&#x27;Facet1&#x27;, deployedDiamond.address)<br />const facet2 = await ethers.getContractAt(&#x27;Facet2&#x27;, deployedDiamond.address)</p>
  </section>
  <p id="523a">Эта библиотека берет на себя большую часть работы за нас! Все, что нам нужно сделать, это перечислить наши аспекты, и библиотека развернет их вместе с бриллиантом. Обратите внимание, что когда мы инициализируем наши контракты, <code>ethers.js</code>мы устанавливаем адрес на <code>Diamond.sol</code>адрес .</p>
  <p id="5bc3">Если вы хотите добавить новый аспект, вы можете сделать это, вызвав <code>DiamondCutFacet.sol</code>. Вот пример.</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="EXfT">const FacetCutAction = { Add: 0, Replace: 1, Remove: 2 }</p>
    <p id="hTOc">const Facet3 = await ethers.getContractFactory(&#x27;Facet3&#x27;)<br />const facet3 = await Facet3.deploy()<br />await facet3.deployed()<br />const selectors = getSelectors(facet3).remove([&#x27;supportsInterface(bytes4)&#x27;])<br />tx = await diamondCutFacet.diamondCut(<br /> [{<br /> facetAddress: facet3.address,<br /> action: FacetCutAction.Add,<br /> functionSelectors: selectors<br /> }],<br /> ethers.constants.AddressZero, &#x27;0x&#x27;, { gasLimit: 800000 }<br />)</p>
    <p id="3b87">receipt = await tx.wait()</p>
  </section>
  <p id="0245">Как видите, сначала мы развертываем наш фасет. Затем мы используем наш пакет npm для получения селекторов функций. Затем мы вызываем <code>DiamondCutFacet.sol</code>обновить наш Diamond. <code>Replace</code>работает аналогично, за исключением того, что вы должны убедиться, что заменяемые селекторы уже есть в Diamond. <code>Remove</code>, также работает аналогично, но убедитесь, что вы передаете именно те селекторы, которые хотите удалить.</p>
  <p id="2879">Поздравляем! Теперь вы знаете, как создать и развернуть приложение блокчейна с помощью Diamond Standard!</p>
  <h1 id="8023">Заключение</h1>
  <p id="950f">На этом моя статья об Diamond Standard заканчивается. Надеюсь, я помог вам понять сложности и способы его реализации в ваших собственных проектах.</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@alzheimer/InetCommEthereum</guid><link>https://teletype.in/@alzheimer/InetCommEthereum?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=alzheimer</link><comments>https://teletype.in/@alzheimer/InetCommEthereum?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=alzheimer#comments</comments><dc:creator>alzheimer</dc:creator><title>Интернет-сообщества</title><pubDate>Sat, 11 Feb 2023 07:32:25 GMT</pubDate><media:content medium="image" url="https://img3.teletype.in/files/65/e0/65e03bd7-36f7-4034-96f0-e98bd143765d.png"></media:content><description><![CDATA[<img src="https://cdn.discordapp.com/attachments/997271802420142110/1076102630478192651/weimbe_Internet_Community_Ethereum_74c66266-8387-48eb-ba88-d599a48c4842.png"></img>Сотни тысяч энтузиастов Ethereum собираются на этих онлайн-форумах, чтобы делиться новостями, обсуждать последние разработки, обсуждать технические вопросы и представлять будущее.]]></description><content:encoded><![CDATA[
  <section style="background-color:hsl(hsl(263, 48%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <figure id="4lkZ" class="m_retina">
      <img src="https://cdn.discordapp.com/attachments/997271802420142110/1076102630478192651/weimbe_Internet_Community_Ethereum_74c66266-8387-48eb-ba88-d599a48c4842.png" width="512" />
    </figure>
  </section>
  <p id="YZk0">Сотни тысяч энтузиастов Ethereum собираются на этих онлайн-форумах, чтобы делиться новостями, обсуждать последние разработки, обсуждать технические вопросы и представлять будущее.</p>
  <h2 id="forums">Форумы</h2>
  <p id="EU15"><a href="https://www.reddit.com/r/ethereum" target="_blank">r/ethereum</a> — все, что связано с Ethereum</p>
  <p id="F3n7"><a href="https://www.reddit.com/r/ethfinance/" target="_blank">r/ethfinance</a> — финансовая сторона Ethereum, включая DeFi</p>
  <p id="vvxE"><a href="https://www.reddit.com/r/ethdev/" target="_blank">r/ethdev</a> — сосредоточен на разработке Ethereum</p>
  <p id="qplV"><a href="https://www.reddit.com/r/ethtrader/" target="_blank">r/ethtrader</a> — тенденции и анализ рынка</p>
  <p id="3GBT"><a href="https://www.reddit.com/r/ethstaker/" target="_blank">r/ethstaker</a> — добро пожаловать всем, кто интересуется стейкингом на Ethereum</p>
  <p id="5j5N"><a href="https://ethereum-magicians.org/" target="_blank">Fellowship of Ethereum Magicians</a> — сообщество, ориентированное на технические стандарты Ethereum.</p>
  <p id="NqqN"><a href="https://ethereum.stackexchange.com/" target="_blank">Ethereum Stackexchange</a> — обсуждение и помощь разработчикам Ethereum</p>
  <p id="Wghd"><a href="https://ethresear.ch/" target="_blank">Ethereum Research</a> — самая влиятельная доска объявлений для криптоэкономических исследований</p>
  <h2 id="chat-rooms">Чаты</h2>
  <p id="lml4"><a href="https://discord.com/invite/Nz6rtfJ8Cu" target="_blank">Ethereum Cat Herders</a> — сообщество, ориентированное на предоставление поддержки управления проектами для разработки Ethereum.</p>
  <p id="5fz2"><a href="https://ethglobal.co/discord" target="_blank">Ethereum Hackers</a> — чат Discord, которым управляет ETHGlobal: онлайн-сообщество для хакеров Ethereum со всего мира.</p>
  <p id="M3Ib"><a href="https://discord.gg/5W5tVb3" target="_blank">CryptoDevs</a> — сообщество Discord, ориентированное на разработку Ethereum</p>
  <p id="vgVI"><a href="https://discord.io/ethstaker" target="_blank">EthStaker Discord</a> — сообщество, ориентированное на предоставление поддержки управления проектами для разработки Ethereum.</p>
  <p id="VPXH"><a href="https://discord.gg/CetY6Y4" target="_blank">Команда веб-сайта Ethereum.org</a> — зайдите и пообщайтесь в чате веб-разработки и дизайна ethereum.org с командой и людьми из сообщества.</p>
  <p id="f2kV"><a href="https://discord.gg/ZH5aXDgWEU" target="_blank">Web3 University</a> — сообщество, ориентированное на изучение разработки Web3</p>
  <p id="xLAo"><a href="https://discord.matos.club/" target="_blank">Matos Discord</a> — сообщество создателей web3, где тусуются строители, промышленные лидеры и энтузиасты Ethereum. Мы увлечены разработкой, дизайном и культурой web3. Приходите строить вместе с нами.</p>
  <p id="nNFq"><a href="https://gitter.im/ethereum/solidity/" target="_blank">Solidity Gitter</a> — чат для разработки солидности (Gitter)</p>
  <p id="SYmT"><a href="https://matrix.to/#/#ethereum_solidity:gitter.im" target="_blank">Solidity Matrix</a> — чат для развития солидности (Матрица)</p>
  <p id="qPPw"><a href="https://ethereum.stackexchange.com/" target="_blank">Ethereum Stack Exchange </a> —<em> форум вопросов и ответов</em></p>
  <p id="kR56"><a href="https://peeranha.io/" target="_blank">Peeranha </a> —<em> децентрализованный форум вопросов и ответов</em></p>
  <h2 id="youtube-and-twitter">Ютуб и Твиттер</h2>
  <p id="Nw5c"><a href="https://www.youtube.com/c/EthereumFoundation" target="_blank">Ethereum Foundation</a> — будьте в курсе последних новостей от Ethereum Foundation</p>
  <p id="hmtm"><a href="https://twitter.com/ethereum" target="_blank">@ethereum</a> — Официальный аккаунт Ethereum Foundation</p>
  <p id="h2de"><a href="https://twitter.com/ethdotorg" target="_blank">@ethdotorg</a> — портал Ethereum, созданный для нашего растущего глобального сообщества.</p>
  <p id="utOS"><a href="https://hive.one/c/ethereum?page=1" target="_blank">Список влиятельных твиттер-аккаунтов Ethereum</a></p>
  <h2 id="sPs8">Доп. источники:</h2>
  <p id="QlEs"><a href="https://www.reddit.com/r/ethdev/" target="_blank">r/ethdev/</a> — тема на форуме по разработке Ethereum и DApps<br /><a href="https://forum.soliditylang.org/" target="_blank">Solidity Forum</a> — на форуме обсуждается много тем связанных с Solidity</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@alzheimer/ghCtwyZBKT1</guid><link>https://teletype.in/@alzheimer/ghCtwyZBKT1?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=alzheimer</link><comments>https://teletype.in/@alzheimer/ghCtwyZBKT1?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=alzheimer#comments</comments><dc:creator>alzheimer</dc:creator><title>Polygon vs Ethereum vs Polkadot: что выбрать для разработки?</title><pubDate>Thu, 26 Jan 2023 19:27:14 GMT</pubDate><media:content medium="image" url="https://img2.teletype.in/files/57/54/5754181d-95ab-49f9-a0bd-45c41ebbd483.png"></media:content><description><![CDATA[<img src="https://img2.teletype.in/files/16/56/16563bf3-601c-45ee-a4e6-ccfd4c65683c.jpeg"></img>Несмотря на доминирующее положение Ethereum на рынке, существуют десятки достойных сетей третьего поколения, которые могут составить конкуренцию этому блокчейну. Среди них Polkadot и Polygon. Они предлагают удобный пользовательский интерфейс при большей масштабируемости и совместимости.]]></description><content:encoded><![CDATA[
  <figure id="ukV7" class="m_column">
    <img src="https://img2.teletype.in/files/16/56/16563bf3-601c-45ee-a4e6-ccfd4c65683c.jpeg" width="2400" />
  </figure>
  <p id="5rD9">Несмотря на доминирующее положение Ethereum на рынке, существуют десятки достойных сетей третьего поколения, которые могут составить конкуренцию этому блокчейну. Среди них Polkadot и Polygon. Они предлагают удобный пользовательский интерфейс при большей масштабируемости и совместимости.</p>
  <p id="FAhN">Если вы в настоящее время думаете, какая из сетей блокчейна лучше всего подойдет для вашего проекта, вы попали на правильную страницу. В этой статье мы рассмотрим особенности блокчейнов Polygon, Polkadot и Ethereum и определим, как они могут повысить производительность вашего проекта.<br /></p>
  <h2 id="faBZ">Polygon против Ethereum против Polkadot: чем они отличаются</h2>
  <p id="DY7k"><br />Прежде чем мы начнем углубляться в особенности каждой сети, давайте начнем с общего сравнения каждой сети блокчейнов. Как видно из таблицы ниже, существует очевидная разница между Ethereum и его преемниками третьего поколения, Polkadot и Polygon:</p>
  <figure id="VzLu" class="m_original">
    <img src="https://ideasoft.io/wp-content/webp-express/webp-images/doc-root/wp-content/uploads/2022/12/MaticEthDot-Sheet-min-1024x512.png.webp" />
  </figure>
  <p id="ybql">Теперь, когда вы ознакомились со спецификой всех трех сетей, давайте подробно рассмотрим потенциал каждой из них. Ниже мы изложили ключевую информацию о Polkadot, Polygon и Ethereum, чтобы помочь вам найти лучшее блокчейн-решение для вашего проекта.</p>
  <p id="zrrR"></p>
  <h2 id="TBTM">Блокчейн Ethereum: обзор</h2>
  <p id="3al8"></p>
  <p id="b96y">Эфириум внес большой вклад в изменения на рынке, переключив внимание с криптовалют как просто эквивалентной формы денег на то, что они рассматриваются как неотъемлемый компонент dApps. Фактически, эта сеть остается крупнейшей в мире экосистемой dApp и второй по величине PoW (Proof-of-Work) в мире, уступая только Биткойну.</p>
  <p id="w82o">Сегодня среда разработки Ethereum в блокчейнах остается лучшим выбором для тысяч проектов. Однако, несмотря на его превосходство, все еще существуют некоторые технические ограничения, которые необходимо знать, прежде чем приступить к работе с ним.</p>
  <p id="DGvY"></p>
  <h2 id="uyfo">Плюсы и минусы сети Ethereum:</h2>
  <p id="ReSQ"></p>
  <p id="mww6">     <strong>Плюсы:</strong></p>
  <ul id="inPz">
    <li id="YYCi">Децентрализованный дизайн</li>
    <li id="1n2Y">Быстрое развертывание</li>
    <li id="GJoJ">Частные транзакции</li>
    <li id="DtFa">Большое сообщество</li>
    <li id="Gn0g">Нулевое время простоя</li>
    <li id="IJ4x">Эфириум 2.0 грядет</li>
  </ul>
  <p id="iDvU">    <strong> Минусы:</strong></p>
  <ul id="cmPW">
    <li id="r93p">Низкая масштабируемость</li>
    <li id="c0PT">Сравнительно высокая плата за газ</li>
    <li id="QzMX">Механизм Proof-of-Work (в настоящее время)</li>
    <li id="RLik">Проблемы конфиденциальности транзакций</li>
  </ul>
  <p id="9Khh"></p>
  <h2 id="spsu">Блокчейн-проекты Ethereum:</h2>
  <p id="liLh"></p>
  <p id="VVKs">В целом сеть обычно используется для создания децентрализованных приложений, проектов, основанных на программах смарт-контрактов, и проектов, связанных с одноранговыми платежами. Поэтому неудивительно, что его используют крупнейшие мировые компании, такие как JPMorgan, Microsoft, Amazon и другие.</p>
  <p id="8cPg">Будучи устоявшейся сетью, Ethereum отлично подходит для индустрии DeFi, особенно для разработки проектов dApp. Однако вы также можете найти этот блокчейн в финансах, NFT, здравоохранении, образовании, недвижимости, играх и многих других отраслях.</p>
  <p id="TXTl">Одними из самых популярных проектов на основе Ethereum сегодня являются Compound (платформа заимствования и кредитования DeFi), NFT (платформа для добычи токенов), The Sandbox (метавселенный эквивалент Minecraft), Opensea (торговая платформа NFT) и так далее.</p>
  <p id="1JmT"><strong>Идеи проекта для создания на Ethereum</strong>: платформы метавселенной, протоколы DeFi и решения DEX, автоматические маркет-мейкеры (AMM), агрегаторы криптобирж, веб-браузеры, торговые площадки NFT и другие.</p>
  <p id="gdI1"></p>
  <h2 id="Tm98">Блокчейн Polygon: обзор</h2>
  <p id="caDv"></p>
  <p id="mgV7">Сеть Polygon — это блокчейн третьего поколения, который, в отличие от Ethereum, использует модель консенсуса PoS — более эффективную и безвредную для окружающей среды, чем PoW. Еще одна уникальная особенность Polygon заключается в том, что он построен на основе Ethereum и обладает большей масштабируемостью по сравнению со своим предшественником 2-го поколения. Более того, поскольку MATIC является токеном ERC-20, он полностью совместим с другими цифровыми валютами на основе Ethereum.</p>
  <p id="SXCz">В целом, использование платформы Polygon может повысить гибкость, масштабируемость и независимость проектов. В то же время он обеспечивает безопасность, совместимость и структурные преимущества, аналогичные блокчейну Ethereum.</p>
  <p id="0YZZ"></p>
  <h2 id="nyqQ">Как это работает?</h2>
  <p id="H5XJ"></p>
  <p id="CzUE">Сеть Polygon работает на основе блокчейна Ethereum и предназначена для подключения проектов на базе Ethereum. Несмотря на свой стереотип «убийцы Эфириума», изначально он был разработан, чтобы в первую очередь помочь повысить эффективность, безопасность, размер и полезность.</p>
  <p id="qSuV">Проще говоря, Polygon применяет различные технологии для создания быстрой параллельной цепочки блоков, связанной с основной цепочкой блоков на основе Ethereum. В целом, структура PoS MATIC позволяет пользователям зарабатывать на нем деньги с помощью ставок на основе двух основных компонентов: валидаторов и делегаторов. Валидаторы используются для проверки новых транзакций и добавления их в блокчейн, в то время как делегаторы косвенно размещают токен Polygon через доверенных валидаторов.</p>
  <p id="dGIC">Относительно быстрые и дешевые транзакции в этой сети делают ее отличным выбором для децентрализованных бирж, протоколов кредитования и сбережений, приносящих доход, и даже некоторых игр, в которых можно заработать.</p>
  <p id="xftD"></p>
  <h2 id="mPwA">Плюсы и минусы сети Polygon:</h2>
  <p id="eMlz"></p>
  <p id="cYoO">    <strong> Плюсы:</strong></p>
  <ul id="MoJo">
    <li id="egi7">Низкая плата за газ и более высокая скорость транзакций</li>
    <li id="NqUK">Более эффективная работа и меньший углеродный след</li>
    <li id="cgiq">Быстрая масштабируемость и вознаграждение за стекинг</li>
    <li id="Zrvj">Совместимость с основной цепью Ethereum</li>
    <li id="ILJB">Улучшенная безопасность</li>
    <li id="4xzX">Модульность, что выгодно для добавления функций.</li>
  </ul>
  <p id="cFOY">   <strong>  Минусы:</strong></p>
  <ul id="F32v">
    <li id="10JK">Сообщается, что менее безопасный</li>
    <li id="ObMJ">Менее популярный</li>
    <li id="6FBO">Обеспечивает взаимодействие только между сайдчейнами, развернутыми в Polygon.</li>
  </ul>
  <p id="hzIq"></p>
  <h2 id="VhDf">Проекты Polygon:</h2>
  <p id="SsnV"></p>
  <p id="gG6I">Говоря о проектах на базе Polygon, нужно признать, что у блокчейна действительно хороший потенциал в развитии бизнеса. Одним из его ключевых преимуществ является возможность масштабирования, что чрезвычайно важно для многочисленных приложений dApp. Кроме того, сеть Polygon отличается большей вычислительной мощностью и полной совместимостью с Ethereum. Это важный фактор, который нельзя упускать из виду.</p>
  <p id="cTKj">Благодаря своим многочисленным преимуществам это блокчейн-решение может подключать платежные системы, DEX, AMM и другие приложения с меньшими затратами. Одними из самых популярных проектов, использующих экосистему Polygon для своей работы, являются AAVE, Curve, QuickSwap, SportX, Clover Finance и многие другие.</p>
  <p id="nFsh">В целом ожидается, что сеть блокчейнов будет иметь огромное преимущество на рынках NFT и DeFi по сравнению с Ethereum.</p>
  <p id="UcnV"><strong>Типы проектов на основе Polygon, которые следует учитывать</strong> : dApps, службы хранения файлов, децентрализованные протоколы, торговые платформы и рынки предсказаний, решения DEX и многое другое.</p>
  <p id="dJ1h"></p>
  <h2 id="0Q83">Блокчейн Polkadot: обзор</h2>
  <p id="kaZq"></p>
  <p id="p2Fm">Polkadot — это гибкая децентрализованная сеть, предназначенная для обеспечения безопасного соединения для блокчейнов. Представленный в 2020 году, он стал известен благодаря своей уникальной модели парачейн, которая позволяет быстро, безопасно и с меньшими затратами обрабатывать транзакции.</p>
  <p id="9RJT">Что делает его таким популярным в области разработки программного обеспечения? Инженеры могут создавать и запускать свои собственные токены, а также передавать любые типы данных или активов в среде блокчейна. Это открывает широкие возможности для взаимодействия с блокчейном в сети Polkadot.</p>
  <p id="rrJi">Более того, запуск парапотоков позволяет активам на основе блокчейна напрямую взаимодействовать друг с другом и обмениваться данными. Возможность решить проблему изоляции блокчейна с помощью безопасной функциональной платформы — одно из наиболее перспективных преимуществ Polkadot по сравнению с другими сетями.</p>
  <p id="Dg0n"></p>
  <h3 id="fKPj">Как это работает?</h3>
  <p id="ytxs"></p>
  <p id="QvT2">Платформа Polkadot основана на модели консенсуса Nominated PoS (в отличие от системы PoW, которую использует Биткойн). В большинстве случаев блокчейн используется для перевода средств между разными кошельками с использованием системы криптографии с открытым и закрытым ключом. Будучи общей сетью с несколькими цепочками, Polkadot позволяет обрабатывать данные и транзакции в нескольких цепочках параллельно. Это позволяет повысить скорость транзакций и функциональную совместимость, а также снизить комиссию и перегрузку каждого сегмента.</p>
  <p id="xF4e">Polkadot предназначен для поддержки других блокчейнов при передаче цифровых данных и решения проблем масштабируемости и подключения различных сетей.</p>
  <p id="ubi6">Он используется для оплаты сетевых сборов, управления голосованием и проверки прав, но, конечно же, он предлагает гораздо больше, чем услуги по управлению деньгами.</p>
  <p id="bwcY">Этот блокчейн сам по себе не является платформой смарт-контрактов, а скорее инфраструктурой dApp для интеграции программ смарт-контрактов. В настоящее время Polkadot ценится за широкий функционал и в основном дополняет существующие блокчейны, а не конкурирует с ними.</p>
  <p id="LztF"></p>
  <h2 id="VZVJ">Плюсы и минусы сети Polkadot:</h2>
  <p id="sxBR"></p>
  <p id="pOuI">     <strong>Плюсы:</strong></p>
  <ul id="FW6v">
    <li id="SvzZ">Высокая совместимость и масштабируемость</li>
    <li id="q0It">Технология шардинга</li>
    <li id="kZIl">Технология Proof-of-Stake</li>
    <li id="DvsU">Более высокие вознаграждения за стекинг</li>
    <li id="VL0i">Большая гибкость и отсутствие вилок</li>
    <li id="yMy3">Мультичейн архитектура</li>
    <li id="X3VU">Смарт-контракты</li>
  </ul>
  <p id="cOjB">     <strong>Минусы:</strong></p>
  <ul id="ASNe">
    <li id="3vJ1">Относительно новый токен с непроверенной репутацией</li>
    <li id="q4dm">Ограниченное количество парачейнов, которые продаются тому, кто предложит самую высокую цену.</li>
    <li id="vw28">Большая кривая обучения для дальнейшего развития</li>
    <li id="9i4N">Общее пространство для исполнения и ограниченное количество слотов для парачейнов</li>
  </ul>
  <p id="qhQR"></p>
  <h2 id="roEP">Проекты Polkadot:</h2>
  <p id="yRYV"></p>
  <p id="WEED">Ключевой особенностью проектов на базе Polkadot является их легкая совместимость с различными блокчейнами, в том числе не входящими в сеть DOT. Некоторые из наиболее популярных областей использования этого блокчейна — стейкинг и управление.</p>
  <p id="aqO7">Разработчики активно используют Polkadot для создания приложений на основе существующих блокчейнов, обработки интерфейсной и серверной разработки, а также многочисленных областей обслуживания.</p>
  <p id="ZlsF">Вот несколько проектов, созданных в среде Polkadot, которые вы, возможно, захотите изучить: Octopus Network (многоцепочечная совместимая криптосеть для запуска и работы цепочек приложений Web3.0), Kusama (масштабируемая сеть специализированных блокчейнов), Acala (универсальная -one DeFi hub), PolkaFoundry (фреймворк для создания бесшовных децентрализованных приложений DeFi и NFT без границ на Polkadot), Robonomics (решение для хранения более 1 миллиона цифровых двойников IoT) и многие другие.</p>
  <p id="JLTq">Ключевые типы проектов, которые вы можете попробовать с Polkadot, — это децентрализованные стейблкоины, различные dApps и хабы DeFi, фреймворки для разработки приложений DeFi и NFT и другие.</p>
  <p id="uOi7"></p>
  <h2 id="UDDT">Какую сеть выбрать: Polygon, Ethereum или Polkadot?</h2>
  <p id="O8fl"></p>
  <p id="eCcO">Блокчейн Ethereum по-прежнему сильно зависит от концепции PoW. При этом каждый пользователь должен пройти уровень сложности, чтобы доказать, что блок действителен. Однако, несмотря на высокий уровень безопасности, это влияет на скорость транзакций, а также требует значительных комиссий и большого энергопотребления.</p>
  <p id="gvfC">Напротив, и Polygon, и Polkadot основаны на модели PoS. В соответствии с этим децентрализованные сети значительно уменьшают проблемы, связанные с достоверностью временных меток, масштабируемостью и, конечно же, скоростью транзакций.</p>
  <p id="MYEe">Также стоит сказать, что Polkadot на самом деле применяет вариант концепции PoS — Nominated Proof of Stake. Это включает в себя две переменные, валидаторы и номинаторы, которые в значительной степени способствуют честности и высокой безопасности сети.</p>
  <p id="6mqF">В то же время Ethereum V2, официально представленный в сентябре 2022 года, также планирует перейти на алгоритм PoS. В связи с этим разработчики ожидают увидеть положительные улучшения в скорости сети и ее экологичности.</p>
  <p id="2Znc"></p>
  <h3 id="jnWW">Масштабируемость:</h3>
  <p id="sj0k">С точки зрения скорости транзакций и масштабируемости Polygon в настоящее время является абсолютным победителем. Он способен обрабатывать до 65 000 транзакций в секунду, что больше, чем у Polkadot (пока что), не говоря уже об Ethereum, который способен выполнять только до 30 транзакций.</p>
  <p id="d6RN">Однако сеть Polkadot все еще находится на ранней стадии разработки. Согласно его документации, ожидается, что в ближайшие годы блокчейн достигнет 1 000 000 транзакций в секунду, что будет более чем конкурентоспособным с Polygon.</p>
  <p id="UWcN"></p>
  <h3 id="WbPx">Децентрализация:</h3>
  <p id="q9sm">Подобно Ethereum, блокчейны Polygon и Polkadot сами по себе являются децентрализованными платформами. Они позволяют разработчикам создавать масштабируемые и удобные для пользователя приложения dApp с достойным уровнем безопасности. Поскольку Polygon присутствует на рынке некоторое время, он уже доказал свою ценность с точки зрения децентрализации.</p>
  <p id="oBu8">Polkadot уже используется для подключения частных сетей и сетей консорциумов, общедоступных и закрытых сетей, оракулов и многих других передовых решений. Кроме того, сеть Polkadot интенсивно развивалась в направлении развития параллельной децентрализованной интернет-инфраструктуры (Web3). Считается, что это позволяет пользователям запускать полностью децентрализованную сеть.</p>
  <p id="VtOw">Несмотря на сильные и слабые стороны всех трех сетей, считается, что они будут сосуществовать и дополнять друг друга в децентрализованном будущем. Разработчики могут использовать преимущества Polygon, Ethereum и Polkadot при создании конкретных децентрализованных проектов, таких как платформы социальных сетей, метавселенная или решения DeFi.</p>
  <p id="kdrX"></p>
  <h3 id="G0aT">Окончательный вердикт:</h3>
  <p id="FrFI">Несмотря на то, что они сильно различаются по производительности и архитектуре, Polkadot, Polygon и Ethereum обладают огромным потенциалом в развитии проектов. Если ваш проект не предназначен для масштабирования и вы ищете надежное, универсальное блокчейн-решение, которое просто работает, выбирайте Ethereum.</p>
  <p id="LFu6">Однако тем, кто ищет масштабируемость, безопасность и высокую скорость транзакций, стоит рассмотреть Polkadot или Polygon. Эти сети третьего поколения, несомненно, обеспечат первоклассный пользовательский интерфейс при более низких комиссиях за транзакции, что действительно важно как для создателей, так и для клиентов. В то время как Polygon больше основан на Ethereum и имеет вокруг себя обширное сообщество технических экспертов, Polkadot — это универсальное решение, которое работает как мост между различными сетями блокчейнов и может расширить возможности вашего проекта независимо от его масштаба или отраслевой направленности.</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@alzheimer/E-3PrFC4XRu</guid><link>https://teletype.in/@alzheimer/E-3PrFC4XRu?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=alzheimer</link><comments>https://teletype.in/@alzheimer/E-3PrFC4XRu?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=alzheimer#comments</comments><dc:creator>alzheimer</dc:creator><title>Как Создать Автоматический Аудитор Смарт-Контракта для Web</title><pubDate>Thu, 08 Dec 2022 19:48:29 GMT</pubDate><media:content medium="image" url="https://img1.teletype.in/files/40/41/4041a95a-5e80-4dee-be8e-05a788a4505d.png"></media:content><description><![CDATA[<img src="https://miro.medium.com/max/700/1*sXmOBx6Y3eK5wCgZZSc4aQ.png"></img>В наши дни стоимость аудита продвинутого смарт-контракта может составлять от 50 000 до 100 000 долларов, а иногда и больше, к тому же на проведение комплексного аудита часто уходят месяцы. Так почему бы не переложить большую часть этого процесса на автоматизированного программного аудитора? Мы, разработчики, знаем одну вещь: когда речь идет о проверке сложных и очень подробных вещей, таких как код, компьютеры способны выполнять работу гораздо эффективнее. Я не говорю, что нам не нужны человеческие аудиторы безопасности, я просто считаю, что человеческий аудит должен быть последним шагом после комплексного автоматизированного аудита. Чтобы проверить эту идею, я решил создать бесплатный автоматизированный веб-аудитор смарт-контрактов...]]></description><content:encoded><![CDATA[
  <figure id="sQum" class="m_original">
    <img src="https://miro.medium.com/max/700/1*sXmOBx6Y3eK5wCgZZSc4aQ.png" width="700" />
  </figure>
  <p id="780c">В наши дни стоимость аудита продвинутого смарт-контракта может составлять от 50 000 до 100 000 долларов, а иногда и больше, к тому же на проведение комплексного аудита часто уходят месяцы. Так почему бы не переложить большую часть этого процесса на автоматизированного программного аудитора? Мы, разработчики, знаем одну вещь: когда речь идет о проверке сложных и очень подробных вещей, таких как код, компьютеры способны выполнять работу гораздо эффективнее. Я не говорю, что нам не нужны человеческие аудиторы безопасности, я просто считаю, что человеческий аудит должен быть последним шагом после комплексного автоматизированного аудита.<br /><br />Чтобы проверить эту идею, я решил создать бесплатный <a href="https://ethereumsmartcontractauditor.com/" target="_blank">автоматизированный веб-аудитор смарт-контрактов</a> с <a href="https://github.com/Christopher-I/SmartContractAuditor" target="_blank">открытым исходным кодом</a>, очень похожий на <a href="http://remix.ethereum.org/#optimize=false&evmVersion=null" target="_blank">веб-компилятор Solidity Remix</a>. Пожалуйста, имейте в виду, что этот аудитор все еще примитивен и нуждается в большой работе, и, надеюсь, вклад сообщества блокчейн поможет довести его до уровня зрелой платформы. Но я думаю, что у него есть базовые основы, на которые можно опираться.<br /><br />Давайте приступим. Я создал фронт-энд аудитора на React, но этот учебник будет в основном посвящен бэк-энд, чтобы сделать его коротким и читабельным. Я начну с общего объяснения того, как я создал аудитора, а затем рассмотрю пример того, как я включил логику аудита в код. В настоящее время аудитор может сканировать код, написанный на solidity, а в будущем планируется расширить его на языки смарт-контрактов <a href="https://developers.libra.org/docs/move-paper" target="_blank">Move</a> и <a href="https://github.com/vyperlang/vyper" target="_blank">Vyper</a>. Я предположу, что вы знаете основы react, terminal, node.js и JavaScript.<br /><br /><strong>Front End:</strong> Для фронтальной части я использовал React (create-react-app).<br /><strong>Back End:</strong> Node.js / java script. <strong>Server:</strong> Я развернул свой код на Netflify(serverless). Вы также можете взглянуть на мое <a href="https://ethereumsmartcontractauditor.com/" target="_blank">веб-приложение здесь</a> и <a href="https://github.com/Christopher-I/SmartContractAuditor" target="_blank">исходный код здесь </a>для более подробной информации.<br /></p>
  <ol id="KJTE">
    <li id="BdxR"><strong>Базовая установка<br /><br /></strong>Перейдите в нужный каталог в командной строке и создайте новый проект react.<br /><br /><em>terminal: create-react-app auditorTutorial<br /><br /></em>Удалите все файлы в папке src в только что созданном проекте.<br /><br />Создайте файл index.js и папку components, а в ней - файл app.js. Вы можете настроить свою папку src по своему усмотрению, но вы также можете посмотреть мою папку <a href="https://github.com/Christopher-I/SmartContractAuditorWebBuild" target="_blank">здесь</a>.<br /><br />Установите несколько модулей и библиотек.<br /><em><strong>BrowserSolc:</strong></em> обертка Solidity, которая может компилировать смарт-контракты в браузере.<strong><br /><em>Web3:</em></strong> будет использоваться для получения дополнительной информации из блокчейна ethereum, такой как примерная стоимость газа. Я использовал <a href="https://infura.io/login" target="_blank">infura</a> в качестве провайдера для подключения к узлу ethereum.<br /><br /><em>terminal: npm i BrowserSolc, web3, semantic-ui-react<br /><br /></em>Как я уже говорил выше, эта статья будет посвящена в основном бэкенду, поэтому вы можете создать любой макет фронтэнда по своему усмотрению, но если вы используете React, рекомендуется использовать <a href="https://goshakkk.name/controlled-vs-uncontrolled-inputs-react/" target="_blank">управляемый текстовый компонент</a>, который может хранить текст смарт-контракта, вводимый пользователем. Сначала нам нужно прочитать код смарт-контракта, введенный в браузере. В качестве входа аудитора я использовал <a href="https://react.semantic-ui.com/addons/text-area/" target="_blank">семантический компонент реакта с управляемой текстовой областью</a>, содержимое которой хранится в состоянии.<br /><br /><em><code>пример:<br /><br />state = {value: “ ”, contract: “”};<br /><br />//обновление состояния контракта на основе пользовательского ввода<br />handleChangesToContract=(event)=&gt;{<br />this.setState({<br />contract:event.target.value<br />});<br />}</code><br /><br /><code>render(){&lt;TextArea value= {this.state.contractCode} onChange=<br />{this.handleChangesToContract} /&gt;}</code><br /></em></li>
    <li id="aot3"><strong>Извлечение кода договора и сохранение в формате массива<br /><br /></strong><em>//пример того, когда запускать аудит, предполагая, что у вас есть кнопка отправки, которая вызывает функцию<br /><br />onSubmit(){ let data = this.state.contract;}<br /><br /></em>Далее я использовал метод javascript &#x27;.split(&quot;\n&quot;)&#x27;, чтобы разделить код смарт-контракта на массив на основе каждой новой строки.<br /><br /><em>onSubmit(){ let data = this.state.contract;<br /><br />let dataArray = source.split(“\n”)} ;<br /></em></li>
    <li id="ELh6"><strong>Компилировать код<br /><br /></strong>Бэкэнд аудитора состоит из двух различных частей. Во-первых, компилятор solidity запускает код смарт-контракта и предоставляет информацию о любых ошибках и успешной компиляции, во-вторых, набор логики, который проверяет уязвимости безопасности.<br /><br />Убедитесь, что BrowserSolc и web3 определены в вашем файле app.js (или там, где вы компилируете файл смарт-контракта). BrowserSolc может быть включен в качестве скрипта в ваш &#x27;public.index.html путем включения :<br /><br /><em>&lt;script src=”./browser-solc.min.js” type=”text/javascript”&gt;&lt;/script&gt;<br /><br /></em>Web3 может быть определен как компонент вашего приложения:<br /><br /><em>импортировать Web3 из &#x27;web3&#x27;;</em><br /><br />Далее мы компилируем код нашего смарт-контракта, который сохраняется в состоянии. Мое состояние хранится под именем &#x27;data&#x27;. Вам также понадобится учетная запись infura. Чтобы создать учетную запись, нажмите <a href="https://infura.io/" target="_blank">здесь</a>.<br /><br /><em><code>//Загрузка выбранной версии компилятора<br />window.BrowserSolc.loadVersion(this.state.currentCompiler, async function (compiler){<br /><br />let optimize = 1;<br />let result = compiler.compile(data, optimize);<br /><br />const provider = new Web3.providers.HttpProvider(<br />‘<a href="https://rinkeby.infura.io/v3/" target="_blank">https://rinkeby.infura.io/v3/</a>(здесь ваш номер инфуры)&#x27;<br />)<br />const web3 = new Web3(provider);<br /><br />let bytecode = result.contracts[“:SampleContract”].bytecode;<br /><br />}</code><br /><br /></em>С помощью web3 и байткода, полученного в результате успешной компиляции, можно обращаться к блокчейну ethereum для получения дополнительных данных, таких как расчетная стоимость газа.<br /></li>
    <li id="wzXo"><strong>Выполнить аудит смарт-контракта<br /><br /></strong>Создайте отдельный файл вне компонента приложения и назовите его auditor.js . Это файл, который будет содержать всю логику аудита. Мы будем отправлять массив нашего смарт-контракта в этот файл, проводить аудит и затем отправлять его обратно в наш компонент. Вы можете определить свой файл audit.js следующим образом:<br /><br /><em><code>export default(dataArray)=&gt;{<br /><br />//определяем одно предупреждение и массив всех обнаруженных предупреждений<br /><br />let warn;<br /><br />let warnings=[];<br /><br />return warnings;<br /><br />}</code><br /><br /></em>Исходя из моих исследований, лучшими источниками для поиска логики аудита являются более ранние взломы, такие как взлом <a href="https://www.coindesk.com/understanding-dao-hack-journalists" target="_blank">DAO</a> и <a href="https://blog.zeppelin.solutions/on-the-parity-wallet-multisig-hack-405a8c12e8f7" target="_blank">Parity</a>, а также шаблоны, основанные на &quot;лучших практиках смарт-контрактов Ethereum&quot;, например, опубликованное компанией <a href="https://consensys.github.io/smart-contract-best-practices/known_attacks/" target="_blank">consensys руководство</a> по защите смарт-контрактов. В этом руководстве мы будем использовать руководство Consensys в качестве источника логики аудита.<br /><br />Давайте разберем код на предмет <a href="https://consensys.github.io/smart-contract-best-practices/known_attacks/" target="_blank">атаки Reentrancy</a>, которая встречается довольно часто.<br /><br />Отрывок с <a href="https://consensys.github.io/smart-contract-best-practices/known_attacks/" target="_blank">веб-сайта Consensys</a> об атаках на реентерабельность -<br /><br />&quot;Одна из главных опасностей <a href="https://consensys.github.io/smart-contract-best-practices/recommendations#external-calls" target="_blank">вызова внешних контрактов</a> заключается в том, что они могут взять на себя поток управления и внести изменения в ваши данные, которых вызывающая функция не ожидала. Этот класс ошибок может принимать различные формы, и обе основные ошибки, которые привели к краху DAO, были ошибками такого рода&quot;.<br /><br /><strong>&quot;Реентерабельность на одной функции&quot;:</strong> Первая замеченная версия этой ошибки касалась функций, которые могли вызываться многократно, до завершения первого вызова функции. Это может привести к тому, что различные вызовы функции будут взаимодействовать разрушительным образом.&quot;<br /><br />В принципе, можно очень быстро выполнить несколько вызовов функции контракта до того, как вся логика функции будет завершена. Например, злоумышленник может сделать несколько снятий средств со счета сверх фактического баланса счета, если баланс счета (состояние) не обновляется перед каждым вызовом функции снятия средств.<br /><br />Один из способов предотвратить это - использовать <a href="https://consensys.github.io/smart-contract-best-practices/recommendations#send-vs-call-value" target="_blank">use <code>send()</code> вместо <code>call.value()()</code></a>. Это ограничит выполнение любого внешнего кода.<br /><br />Чтобы перевести это в логику, мы можем просто найти в массиве кода нашего смарт-контракта набор строк “<code><a href="https://consensys.github.io/smart-contract-best-practices/recommendations#send-vs-call-value" target="_blank">call.value()()</a>&quot;.<br /><br /><em>//определите строку, которую вы хотите найти<br /><br />let dangerousCalls1 = ‘.call.value()’;<br /><br />//просмотреть смарт-контракт построчно и сохранить все найденные предупреждения в //массив<br /><br />for (let index=0; index&lt;dataArray.length; index++) {<br />if (dataArray[index].includes(dangerousCalls1)) {<br />warn = {key:(index), value:&quot;Помните, что использование &#x27;.call.value()&#x27;, подвержено атакам повторного входа, по возможности используйте send() или transfer(). Также не забудьте установить баланс вашего нового счета перед переводом&quot;};<br />warnings.push(warn);<br />}<br /><br />}<br /><br /></em></code>Затем мы можем вернуть результаты в наш компонент и отобразить все предупреждения пользователю.<br /><br />Это очень простой пример поиска уязвимостей в коде, но в принципе любой шаблон можно разбить на строительные блоки и добавить в логику auditor.js. Следует учитывать и другие факторы, например, искомая строка в конкретной строке может быть не вся в одной строке, так в примере выше &quot;.call.&quot; и &quot;.value()&quot; могут быть вызваны на разных строках, поэтому более детальная проверка может разделить поиск каждой строки отдельно и проверить следующую &quot;активную&quot; строку, если она содержит определенную строку.<br /><br />Как вы можете заметить, для создания надежного бесплатного открытого публичного аудитора потребуется довольно обширная база данных логики, которая может быть создана за счет вклада сообщества в логику аудита.</li>
  </ol>

]]></content:encoded></item></channel></rss>