July 28, 2022

Web3 реги и как они работают

Всем привет!

В этой статье разберем принципы работы регистраций на веб3 сайтах

Ссылка на гитхаб с исходным кодом будет в конце статьи

Я буду делать все на js

В мире веб3 существует несколько способов authenticaton на странице

  1. Как у 1inch - веб приложение выступает чисто интерфейсом для работы с контрактом DEXa и ничего не хранит на серверах
  2. Как у opensea - веб приложение 50/50 на веб3, потому что некоторые моменты хранятся на серверах, а остальное в блокчене
  3. Как у Дегенскана - веб приложение с подключением кошелька, но вся работа с блокчейнами происходит на бэкэнде

Давайте разберёмся, как сделать authentication в каждом случае

1. КАК У 1inch

Существует куча различный гайдов по тому, как добавить в свое приложение кнопку "connect wallet", поэтому не буду заострять внимание на этом. Просто в общих чертах опишу, как это работает.

ШАГ 1 - Создаем файл index.html, туда добавляем кнопку "connect wallet" и подключаем наш будущий файл script.js

ШАГ 2 - Делаем файл script.js, вешаем события на кнопки и используем чудесный API метамаска

Прелесть тут в том, что не нужно не нужно импортировать сторонние библиотеки

А теперь подробнее

window.ethereum - возвращает объект, если у пользователя установлено расширение метамаска, если его нет, то возвращается undefined

await ethereum.request({ method: 'eth_requestAccounts' }); - тут мы асинхронно запрашиваем у пользователя кошельки, чтобы подключится к веб-приложению

ethereum.selectedAddress - хранит массив подключенных адресов. Берем [0] элемент и получаем выбранный адрес, если он один, если много, то можем брать любой

Ура! Мы знаем адрес пользователя и можем делать запросы на отправление транзакций и т.п., а в метамаске теперь написано "подключено"

Теперь нам достаточно создать объект transactionParameters, куда передадим от кого (from), куда (to) и сколько эфира отправить (value)

await ethereum.request({method: 'eth_sendTransaction', params [transactionParameters]}); - делаем еще один request и отправляем транзакцию

При нажатии на кнопку send мы можем делать что угодно, я прикрутил отправку эфиров ortomich.eth

Вот тут документация метамаск апи: https://docs.metamask.io/guide/

Тут неповторимий Патрик делает это на протяжении 10 часов: https://www.youtube.com/watch?v=pdsYCkUWrgQ&t=1406s

Тут про window.ethereum - https://eips.ethereum.org/EIPS/eip-1193

2. КАК У OPENSEA

На всем известной площадке используются такие штуки как ПОДПИСИ

В чем основные плюсы сигнатур (аkа подписей)

  1. Бесплатно
  2. Никто не подделает твою подпись (если только угонит приватный ключ)

Они собственно и придуманы, чтобы подтверждать различные действия на сайте от вашего лица, не платя за газ

Как же их использовать, чтобы зайти на сайт, где нужно не только делать свапы, а еще добавлять в избранное и т.п.?

Вся логика основано на том факте, что кроме самого пользователя, никто не сгенерит уникальную сигнатуру

ШАГ 0 - Инициализируем проект качаем модули

ШАГ 1 - Делаем html + подключаем axios и ethers, чтобы слать запросы на сервер и взаимодействовать с блокчейном

ШАГ 2 - Запускаем чудо-сервер на node.js + нам понадобиться бд чтоб хранить пользователей, mongoDB = 1 love ^_^ У них красивый сайт))))))

Тут стандартные node.js штучки, ну и соответвенно делаем путь /login, чтобы куда-то слать наши подписи

ШАГ 3 - Делаем файл userModel - это чисто для БД, чтобы понимала, что от нее хотят, короче просто поля для бд. По сути нам достаточно хранить только кошелек, чтобы идентифицировать пользователя, но я еще добавил роль, потому что могу x2

ШАГ 4 - Делаем файл authController, там будет лежать логика для autentification на сервере

В нем у нас будет две функции login и signatureVerify, нетрудно догадаться что они делают

Далее в signatureVerify берем подпись, и сообщение, а чудо метод recover возвращает исходный адрес, что с этой информацией делать дальше догадаться несложно.

const signer = await web3.eth.accounts.recover(message, sign);
if (signer != address) {
  res.status(400).json({
    msg: 'error',
    data: 'Wrong signature',
  });
}

Простой if сделает все сам. Если все хорошо, то переходим в функции login

В функции login мы точно знаем, что пользователь "владеет этим кошельком", и используя его адрес мы либо создаем новый аккаунт, либо входим в уже существующий

const address = req.body.address;
let user = await User.findOne({ address }); //ищем в бд
let dbMsg;
if (!user) {
  user = await User.create({ address: address });//создаем пользователя
  dbMsg = `new user ${address}`;
} else {
  dbMsg = `user exist`;//просто выводим
}

ШАГ 5 - Чтобы сделать модное сообщение для подписания как у опенси...

....просто генерируем случайную строку в hex формате

const genRanHex = (size) =>
  [...Array(size)]
    .map(() => Math.floor(Math.random() * 16).toString(16))
    .join('');
const nonce = genRanHex(32);
const message = `Welcome to OpenSea!\n\nClick to sign in and accept the OpenSea Terms of Service: https://opensea.io/tos\n\nThis request will not trigger a blockchain transaction or cost any gas fees.\n\nYour authentication status will reset after 24 hours.\n\nWallet address:\n${ethereum.selectedAddress}\n\nNonce:\n${nonce}`;

Зачем это нужно

Как можно в теории угнать логин? (Представим мир, где на опенси в подписи текст "1234", и с помощью подписи можно отправить все нфт любому человеку)

  1. Негодяи знают, что на опенси подпись "1234", и делают сайт с такой же подписью
  2. Вы каким-то образом туда заходите, и подписываете сообщение "1234"
  3. Негодяи теперь знают, ваш адрес и подпись сообщения "1234"
  4. Они идут на опенси и заходят под вашим логином

НО!

В реальном мире они максимум уберут лайки с нфт, так что бояться не стоит, но на всякий случай, если будете делать какой-то проект, то имейте это ввиду

Опенси раз в 24 часа просит вас подписать подобное сообщение, чтобы обновить данные и лишить хлеба негодяев

Тут доки ethers - https://docs.ethers.io/v5/

Тут можно поиграться с подписями - https://etherscan.io/verifiedSignatures#

Тут проект, который тоже использует подписи - https://snapshot.org/

Тут как работают сигнатуры - https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm

КАК У ДЕГЕНСКАНА

Тут основная логика в том, что не нужны особо взаимодействия с блокчейном, поэтому работает золотое правило web3

Если можно не использовать блокчейн, то мы им и не пользуемся

Поэтому когда мы нажимаем "connect wallet" и подписываем сообщение, идет запрос на их сервер, где передается просто сигнатура

И получаем такой ответ, у меня нет подписки, поэтому тут false

Делаем вывод из этого, что когда вы делаете подпись, она отправляется на сервер, и там просто проверяется, нет ли у этого пользователя доступа к дегенскану или админке.

Все просто и лаконично

Как и обещал, вот ссылка на гитхаб

https://github.com/chpotl/web3Auth

Надеюсь статья была полезной

Спасибо за прочтение

Мой телеграм - https://t.me/chpotldev