Создание и развертывание вашего первого смарт-контракта Solidity
Начало работы
Смарт-контракты — фрагменты кода, живущие на блокчейне, — составляют основу децентрализованных приложений. Это самоисполняющиеся соглашения, написанные на Solidity, в основном развернутые на Ethereum. Давайте построим его вместе.
Вам понадобится несколько инструментов в вашем арсенале:
- Node.js и npm (менеджер пакетов JavaScript)
- Hardhat (ваша локальная блокчейн-площадка)
- MetaMask (ваш цифровой кошелек)
- Немного знаний JavaScript/TypeScript
Создание мастерской
Откройте свой терминал и давайте создадим пространство нашего проекта:
mkdir my-first-contractcd my-first-contractnpm init -ynpm install — save-dev hardhat @nomiclabs/hardhat-ethers ethers
Вы можете увидеть некоторые предупреждения об устаревших пакетах, обычно это нормально и не слишком важно для нашего тестирования.
Далее создайте проект Hardhat:
npx hardhat
При появлении запроса выберите «Создать проект TypeScript». CLI настроит базовую структуру проекта со всем необходимым для начала работы, включая образцы контрактов и скрипты. Вы можете просто нажать клавишу Return, чтобы использовать параметры по умолчанию.
Составление контракта
Мы создадим контракт токена, который будет чеканить и перемещать цифровые активы между адресами. Создайте в своем каталоге:Token.solcontracts
// SPDX-License-Identifier: MITpragma solidity ^0.8.0;contract SimpleToken { string public name; string public symbol; uint8 public decimals; uint256 public totalSupply; mapping(address => uint256) public balanceOf; event Transfer(address indexed from, address indexed to, uint256 value); event Mint(address indexed to, uint256 value); constructor(string memory _name, string memory _symbol) { name = _name; symbol = _symbol; decimals = 18; totalSupply = 0; } function mint(address _to, uint256 _amount) public { require(_to != address(0), "Invalid address"); balanceOf[_to] += _amount; totalSupply += _amount; emit Mint(_to, _amount); emit Transfer(address(0), _to, _amount); } function transfer(address _to, uint256 _value) public returns (bool success) { require(_to != address(0), "Invalid address"); require(balanceOf[msg.sender] >= _value, "Insufficient balance"); balanceOf[msg.sender] -= _value; balanceOf[_to] += _value; emit Transfer(msg.sender, _to, _value); return true; }}
Наш контракт состоит из трех основных компонентов — переменные состояния отслеживают детали токена, события транслируют изменения и функции обрабатывают операции с токенами. Код управляет балансами, переводит токены и при необходимости чеканит новые.
Развертывание по всему миру
Ну, ладно, не мир. Просто небольшой тестовый сетка, но все же. Это будет работать точно так же, если вы нацелитесь на реальную сеть Ethereum.
Чтобы развернуть смарт-контракт, создайте скрипт развертывания () в своем каталоге:deploy.tsscripts
import { ethers } from "hardhat";import { SimpleToken__factory } from "../typechain-types";async function main() { const [deployer] = await ethers.getSigners(); console.log("Deploying contracts with the account:", deployer.address); const SimpleTokenFactory: SimpleToken__factory = await ethers.getContractFactory("SimpleToken") as SimpleToken__factory; const token = await SimpleTokenFactory.deploy("My Token", "MTK"); await token.waitForDeployment(); console.log("Token address:", await token.getAddress());}main() .then(() => process.exit(0)) .catch((error) => { console.error(error); process.exit(1); });
Если вы добавили данные о сети, мы собираемся нацелиться на тестовую сеть Sepolia, которая похожа на копию сети Ethereum, но токены и монеты на ней не имеют ценности и используются для разработки и тестирования:hardhat.config.ts
import { HardhatUserConfig } from "hardhat/config";import "@nomicfoundation/hardhat-toolbox";const config: HardhatUserConfig = { solidity: "0.8.0", networks: { hardhat: {}, sepolia: { url: process.env.SEPOLIA_URL || "", accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : [] } }};export default config;
В целях безопасности создайте файл для переменных среды:.env
SEPOLIA_URL="Your-Infura-or-Alchemy-URL"PRIVATE_KEY="Your-MetaMask-Private-Key"
(Небольшое замечание по безопасности. Никогда и никому не сообщайте свои ключи, ни по какой причине, если вы не абсолютно уверены, что знаете, что происходит. Несмотря на то, что это всего лишь тестовый контракт, вы можете случайно использовать тот же ключ, что и ваш реальный кошелек. Только будьте осторожны!)
Развёртывание
Есть несколько вещей, которые вам нужно сделать прямо сейчас. Я предполагаю, что у вас уже настроен кошелек, совместимый с eth, и это выходит за рамки этой статьи, но я кратко расскажу о том, что должно произойти:
Во-первых, вам нужно будет взять несколько тестовых ETH из крана Sepolia:
- Установите MetaMask, если вы еще этого не сделали (доступно в виде расширения для браузера)
- Создайте новый кошелек или импортируйте существующий
- Переключитесь на тестовую сеть Sepolia в MetaMask (нажмите на выпадающее меню сети вверху)
- Посетите смеситель Sepolia в https://sepoliafaucet.com
- Подключите свой кошелек и запросите тестовый ETH
- Подождите несколько минут, пока тестовый ETH поступит в ваш кошелек
Добавьте URL-адрес узла Ethereum (из Infura или Alchemy) в .env
На этом шаге я расскажу об Infura, то же самое и с Alchemy. Оба являются хорошими сервисами и очень помогают при тестировании.
- Перейдите в https://infura.io и создайте учетную запись
- Создайте новый проект (назовите его как угодно)
- Выберите "Web3 API" в качестве типа проекта.
- На панели мониторинга проекта найдите конечную точку
- Скопируйте URL конечной точки «Sepolia» — он выглядит как
https://sepolia.infura.io/v3/your-project-id
Теперь у вас есть эти две части информации, вернитесь к файлу и подключите их, и тогда мы готовы к запуску..env
Запустите развертывание с помощью:
npx hardhat run scripts/deploy.ts --network sepolia
Тестирование вашего творения
Перетащите этот тестовый файл в свой каталог как :testToken.test.ts
import { expect } from "chai";import { ethers } from "hardhat";import { SimpleToken } from "../typechain-types";import { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers";describe("SimpleToken", function () { let SimpleToken; let token: SimpleToken; let owner: SignerWithAddress; let addr1: SignerWithAddress; let addr2: SignerWithAddress; beforeEach(async function () { [owner, addr1, addr2] = await ethers.getSigners(); SimpleToken = await ethers.getContractFactory("SimpleToken"); token = await SimpleToken.deploy("My Token", "MTK") as SimpleToken; }); describe("Deployment", function () { it("Should set the right name and symbol", async function () { expect(await token.name()).to.equal("My Token"); expect(await token.symbol()).to.equal("MTK"); }); }); describe("Transactions", function () { it("Should mint tokens to address", async function () { await token.mint(addr1.address, 50); expect(await token.balanceOf(addr1.address)).to.equal(50); }); it("Should transfer tokens between accounts", async function () { await token.mint(addr1.address, 50); await token.connect(addr1).transfer(addr2.address, 25); expect(await token.balanceOf(addr2.address)).to.equal(25); }); });});
npx hardhat test
Он должен выводить некоторые результаты тестов при выполнении функций контракта.
Игра по контракту
После развертывания вы можете взаимодействовать со своим творением через MetaMask и Etherscan — отслеживать транзакции и просматривать детали контракта. Для программного взаимодействия пригодится Ethers.js:
import { ethers } from "ethers";import type { SimpleToken } from "./typechain-types";const provider = new ethers.BrowserProvider(window.ethereum);const contract = new ethers.Contract(contractAddress, abi, provider) as SimpleToken;// Mint tokensawait contract.mint(recipientAddress, amount);// Transfer tokensawait contract.transfer(recipientAddress, amount);
Спасибо за прочтение! Пожалуйста, поделитесь своим отзывом в комментариях и подпишитесь на меня в социальных сетях, если вам понравилась статья. Я также создал сообщество Telegram, где мы можем собираться и обсуждать интересные темы, связанные с криптовалютой. Вы можете присоединиться к нам и принять участие в обсуждении → Telegram: Contact @razgules