Web3 реги и как они работают
В этой статье разберем принципы работы регистраций на веб3 сайтах
В мире веб3 существует несколько способов authenticaton на странице
- Как у 1inch - веб приложение выступает чисто интерфейсом для работы с контрактом DEXa и ничего не хранит на серверах
- Как у opensea - веб приложение 50/50 на веб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
На всем известной площадке используются такие штуки как ПОДПИСИ
Они собственно и придуманы, чтобы подтверждать различные действия на сайте от вашего лица, не платя за газ
Как же их использовать, чтобы зайти на сайт, где нужно не только делать свапы, а еще добавлять в избранное и т.п.?
Вся логика основано на том факте, что кроме самого пользователя, никто не сгенерит уникальную сигнатуру
ШАГ 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", и с помощью подписи можно отправить все нфт любому человеку)
- Негодяи знают, что на опенси подпись "1234", и делают сайт с такой же подписью
- Вы каким-то образом туда заходите, и подписываете сообщение "1234"
- Негодяи теперь знают, ваш адрес и подпись сообщения "1234"
- Они идут на опенси и заходят под вашим логином
НО!
В реальном мире они максимум уберут лайки с нфт, так что бояться не стоит, но на всякий случай, если будете делать какой-то проект, то имейте это ввиду
Опенси раз в 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
Делаем вывод из этого, что когда вы делаете подпись, она отправляется на сервер, и там просто проверяется, нет ли у этого пользователя доступа к дегенскану или админке.