Для начала определимся, что мы хотим получить.
Авторизация с кошельком через metamask extension.
Магазин внутри-игровых предметов. При покупке, осуществляется перевод средств на адрес магазина и записывается адрес покупателя и id предмета в контракт. Можно запросить купленные предметы.


Фреймворк для разработки и тестирования
Во-первых, понадобятся инструменты для сборки, тестирования, отладки и публикации смарт-контрактов. Современные решения: foundry и hardhat3. Я использовал foundry.
Для разработки также потребуется тестнет. Можно использовать стороннее решение, или воспользоваться тестнетом представляемым фреймворком. Я использовал anvil из foundry.
anvil запускается и работает из консоли. Функционал стандартный, тестнет создает аккаунты со средствами на счетах и предоставляет RPC точку(вида, http://127.0.0.1:8545) для работы. По этому адресу нужно подключить metamask extension. А также туда публикуется собранный контракт.


Сборка и публикация
Контракт будет написан на solidity. Нам понадобятся две функции:
1. Покупка предмета. Покупка будет передавать средства на кошелек магазина и записывать покупателю id купленного предмета.
function purchaseItem(uint8 _itemId) external payable { uint256 itemCost = 2 gwei; // 0.0012 USD / 0.18 RUB; // Forward the funds to the seller (bool success, ) = STORE_ADDRESS.call{value: itemCost}(""); require(success, "Transfer failed"); boughtItems[msg.sender].push(_itemId); }
2. Просмотр купленных предметов.
function getBoughtItems() external view returns (uint8[] memory) { return boughtItems[msg.sender]; }
Также запишем адрес кошелька магазина при инициализации контракта.
constructor(address _store) { STORE_ADDRESS = _store; }
Для сборки, тестирования и публикации я использовал forge из фреймворка foundry. Тесты для дураков приводить здесь не буду. После успешного тестирования и сборки, публикуем контракт:
forge create ./src/Store.sol:Store \ --private-key <PRIVATE_KEY> \ --rpc-url <RPC_URL> \ --broadcast \ --constructor-args <STORE_PUBLIC_KEY>
После публикации, нам предоставляют адрес смарт-контракта. Строка "Deployed to". Его будем использовать в следующей части при подключении интерфейса.

Интерфейс магазина
Понадобится библиотека для взаимодействия с metamask и блокчейном. Я использовал ethers v6, она показалась мне наиболее хорошо документированной.
Подключаемся к кошельку через metamask extension.
import { ethers } from "ethers"; const provider = new ethers.BrowserProvider(window.ethereum);
Запросим баланс, чтобы убедится в корректной работе.
const signerObj = await provider.getSigner(); const balance = await provider.getBalance(signerObj.address); const balanceFormatted = ethers.formatEther(balance);
Взаимодействие со смарт-контрактом
1. Нам нужен abi собранного контракта. Это строка с описанием методов смарт-контракта, его можно написать самостоятельно или взять в артефакте после сборки.
import ContractArtifact from "***/Store.json"; const abi = ContractArtifact.abi;
2. Создаем экземпляр Contract, передаем туда адрес смарт-контракта, который выдали после сборки, abi и объект полученный при авторизации.
const contract = new ethers.Contract(CONTRACT_ADDRESS, abi, signerObj);
3. Теперь можно вызывать функции смарт-контракта.
// покупка предмета contract.purchaseItem(itemId, { value: ethers.parseUnits("2", "gwei") }); // получение списка покупок const userItems = await contract.getBoughtItems();
По завершении работ, можно залить магазин и контракт в настоящую сеть. Для публикации потребуется небольшое количество эфира.
Ссылки
И злополучная книга

Всем спасибо за внимание!
