Перейти к содержимому

Создайте простой смарт-контракт для кредитования на Linea

Узнайте, как создать и развернуть простой смарт-контракт для кредитования и заимствования на Linea.

13 мин чтения
Создайте простой смарт-контракт для кредитования на Linea

Децентрализованные финансы (DeFi) изменили подход к кредитованию и заимствованию средств, устранив посредников и используя смарт-контракты для автоматической обработки транзакций. То, что раньше требовало банков и бумажной волокиты, теперь можно сделать в несколько кликов — полностью on-chain.

Linea помогает разработчикам создавать DeFi-приложения с улучшенной масштабируемостью и более низкими затратами на газ по сравнению с основной сетью Ethereum, используя zero-knowledge rollups (zk-rollups) для пакетной обработки и сжатия транзакций.

В этом руководстве мы пошагово рассмотрим создание и развёртывание простого смарт-контракта для кредитования и заимствования на Linea. Вы узнаете, как управлять залогом, выдавать займы и настраивать правила погашения — все эти функции являются ключевыми для DeFi-системы кредитования.

По завершении у вас будет рабочий смарт-контракт и чёткое понимание того, как DeFi-кредитование работает изнутри. Независимо от того, новичок ли вы в разработке на блокчейне или хотите отточить свои навыки, это пошаговое руководство даст вам инструменты для начала работы на Linea.

Предварительные требования

  • Вы должны иметь базовое понимание Solidity.

  • На вашем компьютере должны быть установлены Nodejs и Foundry.

Обзор контракта

Этот контракт обеспечивает:

  1. Внесение залога: Пользователи могут вносить залог в контракт, при этом данные надёжно хранятся в смарт-контракте.

  2. Заимствование: Пользователи могут получить займ под внесённый залог.

  3. Погашение: Пользователи могут погасить займы, чтобы разблокировать залог.

  4. Вывод залога: Пользователи могут выводить залог, не заблокированный активным займом.

Настройка проекта

Для этого проекта мы будем использовать фреймворк Foundry. После установки Foundry выполните команду ниже, чтобы инициализировать новый проект:

forge init lending

Откройте папку market в Vscode или вашем любимом редакторе кода и удалите файлы scripts/counter.s.sol, src/counter.sol и test/counter.t.sol.

Установка всех зависимостей

forge install foundry-rs/forge-std --no-commit && forge install OpenZeppelin/openzeppelin-contracts --no-commit

Полный код смарт-контракта для кредитования и заимствования

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
import "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import "lib/openzeppelin-contracts/contracts/access/Ownable.sol";
contract LendingBorrowing is Ownable {
    struct Loan {
        uint256 amount; // Borrowed amount
        uint256 collateral; // Collateral amount
        bool isActive; // Loan status
    }
    IERC20 public immutable collateralToken;
    IERC20 public immutable lendingToken;
    uint256 public collateralFactor; // Percentage of collateral allowed to be borrowed (e.g., 50%)
    mapping(address => uint256) public collateralBalances; // User collateral balances
    mapping(address => Loan) public loans; // User loans
    event CollateralDeposited(address indexed user, uint256 amount);
    event CollateralWithdrawn(address indexed user, uint256 amount);
    event LoanTaken(address indexed user, uint256 amount);
    event LoanRepaid(address indexed user, uint256 amount);
    constructor(IERC20 _collateralToken, IERC20 _lendingToken, uint256 _collateralFactor) Ownable(msg.sender) {
        require(_collateralFactor <= 100, "Collateral factor must be <= 100");
        collateralToken = _collateralToken;
        lendingToken = _lendingToken;
        collateralFactor = _collateralFactor;
    }
    function setCollateralFactor(uint256 _newFactor) external onlyOwner {
        require(_newFactor <= 100, "Collateral factor must be <= 100");
        collateralFactor = _newFactor;
    }
    function depositCollateral(uint256 _amount) external {
        require(_amount > 0, "Amount must be greater than zero");
        collateralBalances[msg.sender] += _amount;
        collateralToken.transferFrom(msg.sender, address(this), _amount);
        emit CollateralDeposited(msg.sender, _amount);
    }
    function withdrawCollateral(uint256 _amount) external {
        require(_amount > 0, "Amount must be greater than zero");
        require(collateralBalances[msg.sender] >= _amount, "Insufficient collateral");
        uint256 maxWithdrawable = collateralBalances[msg.sender] - _loanRequiredCollateral(msg.sender);
        require(_amount <= maxWithdrawable, "Cannot withdraw collateral locked for a loan");
        collateralBalances[msg.sender] -= _amount;
        collateralToken.transfer(msg.sender, _amount);
        emit CollateralWithdrawn(msg.sender, _amount);
    }
    function takeLoan(uint256 _amount) external {
        require(_amount > 0, "Amount must be greater than zero");
        require(loans[msg.sender].isActive == false, "Existing loan must be repaid first");
        uint256 maxLoan = (collateralBalances[msg.sender] * collateralFactor) / 100;
        require(_amount <= maxLoan, "Loan exceeds collateral limit");
        loans[msg.sender] = Loan({
            amount: _amount,
            collateral: collateralBalances[msg.sender],
            isActive: true
        });
        lendingToken.transfer(msg.sender, _amount);
        emit LoanTaken(msg.sender, _amount);
    }
    function repayLoan(uint256 _amount) external {
        require(_amount > 0, "Amount must be greater than zero");
        Loan storage userLoan = loans[msg.sender];
        require(userLoan.isActive, "No active loan");
        require(_amount <= userLoan.amount, "Repay amount exceeds loan");
        lendingToken.transferFrom(msg.sender, address(this), _amount);
        userLoan.amount -= _amount;
        if (userLoan.amount == 0) {
            userLoan.isActive = false;
        }
        emit LoanRepaid(msg.sender, _amount);
    }
    function _loanRequiredCollateral(address _user) internal view returns (uint256) {
        Loan memory userLoan = loans[_user];
        if (!userLoan.isActive) return 0;
        return (userLoan.amount * 100) / collateralFactor;
    }
    function getLoanDetails(address _user) external view returns (uint256 amount, uint256 collateral, bool isActive) {
        Loan memory userLoan = loans[_user];
        return (userLoan.amount, userLoan.collateral, userLoan.isActive);
    }
}
Копировать

Обзор кода

Структура Loan

struct Loan {
        uint256 amount; // Borrowed amount
        uint256 collateral; // Collateral amount
        bool isActive; // Loan status
    }
Копировать

Структура Loan служит шаблоном для хранения сведений об отдельных займах, взятых пользователями. Каждое поле структуры представляет ключевую информацию о статусе и условиях займа. Ниже приведено описание полей:

  • Amount: Хранит количество токенов, которые пользователь занял. Это значение помогает отслеживать задолженность пользователя, определяет обязательства по погашению и проверяет условия займа.

  • Collateral: Хранит стоимость залога, внесённого пользователем для обеспечения займа. Это защищает средства кредитора и помогает определить максимальную сумму займа на основе коэффициента залога.

  • IsActive: Указывает, является ли займ активным в данный момент. Это поле помогает отслеживать статус займа и не позволяет пользователям брать новый займ до полного погашения существующего.

Переменные состояния

IERC20 public immutable collateralToken;
    IERC20 public immutable lendingToken;
    uint256 public collateralFactor; // Percentage of collateral allowed to be borrowed (e.g., 50%)
Копировать

Приведённый фрагмент определяет три ключевые переменные состояния, каждая из которых играет определённую роль в обеспечении функциональности кредитной платформы. Ниже приведено их описание:

  • CollateralToken: Представляет токен, который пользователи вносят в качестве залога для займов. Например, если в качестве залога используется USDC, эта переменная хранит адрес контракта USDC в блокчейне.

  • LendingToken: Эта переменная представляет токен, который платформа выдаёт заёмщикам. Если USDT является токеном кредитования, она хранит адрес контракта USDT в блокчейне.

  • CollateralFactor: Определяет процент стоимости залога, который пользователь может занять. Выражается в виде целого числа, где 100 представляет 100% стоимости залога. Например, если collateralFactor равен 50, пользователь может занять до 50% стоимости своего залога. Это обеспечивает избыточное обеспечение займов для поддержания безопасности системы кредитования. Если пользователь вносит залог на $1 000, а collateralFactor составляет 50%, максимальный займ, который он может получить, составляет $500.

Маппинги

mapping(address => uint256) public collateralBalances; // User collateral balances
 mapping(address => Loan) public loans; // User loans
Копировать
  • Маппинг CollateralBalances: Отслеживает сумму залога, внесённого каждым пользователем. У каждого пользователя есть уникальный баланс залога, связанный с его адресом. Этот маппинг помогает проверить, достаточно ли у пользователя залога для получения займа или вывода средств.

  • Маппинг Loans: Отслеживает детали активных займов каждого пользователя, связывая их адрес с информацией о займе. Это гарантирует, что пользователь не сможет взять новый займ, пока у него есть активный.

События

 event CollateralDeposited(address indexed user, uint256 amount); 
 event CollateralWithdrawn(address indexed user, uint256 amount);
 event LoanTaken(address indexed user, uint256 amount);
 event LoanRepaid(address indexed user, uint256 amount);
Копировать
  • Событие CollateralDeposited — генерируется, когда пользователь вносит залог в контракт. Записывает адрес пользователя и внесённую сумму.

  • Событие CollateralWithdrawn — генерируется, когда пользователь выводит залог из контракта. Записывает адрес пользователя и выведенную сумму.

  • Событие LoanTaken — генерируется, когда пользователь берёт займ. Записывает адрес пользователя и заимствованную сумму.

  • Событие LoanRepaid — генерируется, когда пользователь погашает займ. Записывает адрес пользователя и сумму погашения.

Конструктор

 constructor(IERC20 _collateralToken, IERC20 _lendingToken, uint256 _collateralFactor) Ownable(msg.sender) {
        require(_collateralFactor <= 100, "Collateral factor must be <= 100");
        collateralToken = _collateralToken;
        lendingToken = _lendingToken;
        collateralFactor = _collateralFactor;
    }
Копировать

Конструктор — это специальная функция в Solidity, которая выполняется только один раз при развёртывании контракта. Её назначение:

  • Настройка начальной конфигурации контракта.

  • Присвоение значений ключевым переменным состояния.

  • Установка владения и контроля доступа через Ownable.

Конструктор принимает три аргумента: _collateralToken, _lendingToken и _collateralFactor.

  • _collateralToken — токен, используемый в качестве залога для займов.

  • _lendingToken — токен, который пользователи занимают из системы.

  • _collateralFactor — процент залога, определяющий максимальную заёмную ёмкость, при условии, что он не превышает 100%.

При инициализации конструктор:

  • Назначает _collateralToken в качестве залогового актива.

  • Устанавливает _lendingToken в качестве токена заимствования.

  • Настраивает _collateralFactor для определения соотношения залога к займу.

Кроме того, Ownable(msg.sender) гарантирует, что развёртыватель контракта становится его владельцем, предоставляя ему административные привилегии, например, возможность изменять collateralFactor при необходимости.

Установка коэффициента залога

function setCollateralFactor(uint256 _newFactor) external onlyOwner {
        require(_newFactor <= 100, "Collateral factor must be <= 100");
        collateralFactor = _newFactor;
    }
Копировать

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

Функция помечена как external, то есть её можно вызвать только извне контракта. Модификатор onlyOwner гарантирует, что только владелец контракта (как правило, развёртыватель) может вызвать эту функцию, обеспечивая строгий контроль доступа.

Функция проверяет, что новый коэффициент залога является допустимым процентом в диапазоне от 0 до 100, чтобы исключить установку нереалистичных или небезопасных значений. Например, коэффициент выше 100 мог бы позволить пользователям занимать больше, чем покрывает их залог.

Функция обновляет переменную состояния collateralFactor новым значением, переданным как _newFactor.

Внесение залога

 function depositCollateral(uint256 _amount) external {
        require(_amount > 0, "Amount must be greater than zero");
        collateralBalances[msg.sender] += _amount;
        collateralToken.transferFrom(msg.sender, address(this), _amount);
        emit CollateralDeposited(msg.sender, _amount);
    }
Копировать

Эта функция является ключевой возможностью, позволяющей пользователям вносить залог в контракт. Это обязательный шаг перед получением займа; функция обеспечивает корректный учёт и хранение залога в контракте.

Функция проверяет, что пользователь указывает допустимую сумму, превышающую ноль, и увеличивает баланс залога пользователя на внесённую сумму. Она использует transferFrom для перевода токенов от пользователя к контракту, что требует предварительного одобрения пользователем права контракта на расходование его токенов перед вызовом этой функции.

Эта функция обеспечивает следующее:

  • Внесение залога: Пользователи вносят указанное количество заранее определённого токена (collateralToken) в контракт. Этот залог служит обеспечением для любых займов, которые они берут.

  • Отслеживание балансов залога: Внесённая сумма добавляется к балансу залога пользователя, который отслеживается в маппинге collateralBalances.

  • Обеспечение заимствования: Залог служит основой для расчёта суммы, которую пользователь может занять.

Вывод залога

function withdrawCollateral(uint256 _amount) external {
        require(_amount > 0, "Amount must be greater than zero");
        require(collateralBalances[msg.sender] >= _amount, "Insufficient collateral");
        uint256 maxWithdrawable = collateralBalances[msg.sender] - _loanRequiredCollateral(msg.sender);
        require(_amount <= maxWithdrawable, "Cannot withdraw collateral locked for a loan");
        collateralBalances[msg.sender] -= _amount;
        collateralToken.transfer(msg.sender, _amount);
        emit CollateralWithdrawn(msg.sender, _amount);
    }
Копировать

Эта функция позволяет пользователям выводить часть или весь внесённый залог, при этом гарантируя, что залог, заблокированный в качестве обеспечения активного займа, не может быть выведен.

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

В итоге эта функция обеспечивает следующее:

  • Вывод залога: Позволяет пользователям выводить доступный залог из контракта.

  • Защита займа: Гарантирует, что пользователи не смогут вывести залог, необходимый для обеспечения активного займа.

  • Управление состоянием: Обновляет баланс залога пользователя после успешного вывода.

Получение займа

function takeLoan(uint256 _amount) external {
        require(_amount > 0, "Amount must be greater than zero");
        require(loans[msg.sender].isActive == false, "Existing loan must be repaid first");
        uint256 maxLoan = (collateralBalances[msg.sender] * collateralFactor) / 100;
        require(_amount <= maxLoan, "Loan exceeds collateral limit");
        loans[msg.sender] = Loan({
            amount: _amount,
            collateral: collateralBalances[msg.sender],
            isActive: true
        });
        lendingToken.transfer(msg.sender, _amount);
        emit LoanTaken(msg.sender, _amount);
    }
Копировать

Эта функция позволяет пользователям занимать токены из контракта на основе внесённого залога. Сумма займа ограничена внесённым залогом пользователя и коэффициентом залога контракта, что обеспечивает безопасность заимствования. Эта функция играет ключевую роль в выдаче займов при сохранении безопасности системы.

Функция обеспечивает следующее:

  • Сумма займа превышает ноль.

  • У пользователя нет активного займа, что исключает одновременное получение нескольких займов.

  • Запрошенный займ не превышает максимальный лимит заимствования на основе залога.

  • Маппинг loans обновляется данными займа пользователя.

  • Заимствованные токены переводятся из контракта пользователю.

В итоге эта функция обеспечивает следующее:

  • Выдача займов: Позволяет пользователям занимать токены под внесённый залог.

  • Управление залогом: Гарантирует, что сумма займа не превышает заёмную ёмкость пользователя.

  • Отслеживание займов: Ведёт записи о займах пользователей для предотвращения избыточного заимствования и обеспечения целостности системы.

Погашение займа

function repayLoan(uint256 _amount) external {
        require(_amount > 0, "Amount must be greater than zero");
        Loan storage userLoan = loans[msg.sender];
        require(userLoan.isActive, "No active loan");
        require(_amount <= userLoan.amount, "Repay amount exceeds loan");
        lendingToken.transferFrom(msg.sender, address(this), _amount);
        userLoan.amount -= _amount;
        if (userLoan.amount == 0) {
            userLoan.isActive = false;
        }
        emit LoanRepaid(msg.sender, _amount);
    }
Копировать

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

Функция выполняет следующие проверки и действия:

  • Убеждается, что сумма погашения превышает ноль, чтобы исключить недопустимые операции.

  • Получает данные займа пользователя и подтверждает наличие активного займа перед продолжением.

  • Гарантирует, что сумма погашения не превышает остаток по займу.

  • Переводит сумму погашения от пользователя к контракту, требуя предварительного одобрения на указанную сумму.

  • Уменьшает остаток по займу на сумму погашения.

  • Если займ полностью погашен, функция помечает его как неактивный.

В итоге эта функция обеспечивает следующее:

  • Погашение займа: Позволяет заёмщикам вернуть заимствованную сумму в контракт.

  • Отслеживание займов: Обновляет остаток и статус займа после погашения.

  • Прозрачность: Генерирует событие для записи транзакций погашения в блокчейне.

Тесты

Создайте файл Token.sol в папке src и добавьте в него приведённый ниже код.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {ERC20} from "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol";

contract Token is ERC20 {
    constructor(string memory name, string memory symbol) ERC20(name, symbol){}
    function mint(address user, uint256 amount) public {
        _mint(user, amount);
    }
}
Копировать

Создайте файл lending.t.sol в папке test и добавьте в него приведённый ниже код.

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
import {Test, console} from "forge-std/Test.sol";
import { LendingBorrowing} from "../src/Lending.sol";
import { Token } from "../src/Token.sol";
contract LendingTest is Test {
     LendingBorrowing public lending;
     Token public collateral;
     Token public lendingToken;
     address public user1 = makeAddr("user1");
     address public user2 = makeAddr("user2");
     address public user3 = makeAddr("user3");

    function setUp() public {
        collateral = new Token("collateralToken", "ct");
        lendingToken = new Token("lendingToken", "lt");
        lending = new LendingBorrowing(collateral, lendingToken, 80);
        collateral.mint(user1, 100 ether);
        lendingToken.mint(address(lending), 1000 ether);
    }
    function test_DepositCollateral() public {
        vm.startPrank(user1);
        collateral.approve(address(lending), 100 ether);
        lending.depositCollateral(50 ether);

        assert(collateral.balanceOf(user1) == 50 ether);
        assert(collateral.balanceOf(address(lending)) == 50 ether);  
    }

    function test_TakeLoan() public {
        vm.startPrank(user1);
        collateral.approve(address(lending), 100 ether);
        lending.depositCollateral(50 ether);
        vm.expectRevert();
        lending.takeLoan(100 ether);
        vm.expectRevert();
        lending.takeLoan(49 ether);
        lending.takeLoan(40 ether);
        assert(lendingToken.balanceOf(user1) == 40 ether);
    }

    function test_RepayLoan() public {
        vm.startPrank(user1);
        collateral.approve(address(lending), 100 ether);
        lending.depositCollateral(50 ether);
        lending.takeLoan(40 ether);
        lendingToken.approve(address(lending), 40 ether);
        lending.repayLoan(40 ether);
        assert(lendingToken.balanceOf(user1) == 0 ether);
    }

    function test_WithdrawCollateral() public {
        vm.startPrank(user1);
        collateral.approve(address(lending), 100 ether);
        lending.depositCollateral(50 ether);
        lending.takeLoan(40 ether);
         lendingToken.approve(address(lending), 40 ether);
        lending.repayLoan(40 ether);
        lending.withdrawCollateral(50 ether);
        assert(lendingToken.balanceOf(user1) == 0 ether);
        assert(collateral.balanceOf(user1) == 100 ether);
    }

}
Копировать

Настройка тестов

Эта функция вызывается перед каждой тестовой функцией и используется для инициализации состояния.

  • Развёртывает контракты токенов: Развёртываются оба контракта — collateral и lendingToken.

  • Развёртывает контракт LendingBorrowing: Контракт LendingBorrowing инициализируется с токеном залога, lendingToken и соотношением залога к займу 80% (то есть пользователь может занять не более 80% стоимости своего залога).

  • Минтит токены:- 100 токенов залога минтится для Пользователя 1.

  • 1000 токенов кредитования минтится в контракт кредитования.

Тест внесения залога

Эта функция проверяет, что пользователь может внести залог в контракт кредитования. Пользователь 1 одобряет контракту кредитования право расходовать до 100 своих токенов залога и вносит 50 токенов залога в контракт. Функция проверяет, что:

  • Баланс Пользователя 1 уменьшается на 50 токенов.

  • Баланс залога контракта кредитования увеличивается на 50 токенов.

Тест получения займа

Эта функция проверяет, что пользователь может получить займ на основе внесённого залога. Пользователь 1 вносит 50 токенов залога и одобряет контракту кредитования право их расходовать.

  • Тест проверяет, что попытка взять займ выше допустимой суммы или ниже требуемого минимума (на основе залога) завершается ошибкой.

  • Пользователь 1 успешно берёт займ в 40 токенов lendingToken.

  • Тест проверяет, что Пользователь 1 получает 40 токенов lendingToken после получения займа.

Тест погашения займа

Эта функция проверяет, что пользователь может корректно погасить займ.

  • Пользователь 1 вносит 50 токенов залога и берёт займ в 40 токенов lendingToken.

  • Пользователь 1 одобряет контракту кредитования право расходовать 40 токенов lendingToken и погашает займ.

  • Тест проверяет, что баланс lendingToken Пользователя 1 равен нулю после погашения займа.

Тест вывода залога

Эта функция проверяет, что пользователь может вывести залог после погашения займа.

  • Пользователь 1 вносит 50 токенов залога, берёт займ в 40 токенов lendingToken и погашает займ.

  • После погашения займа Пользователь 1 выводит свой залог.

  • Тест проверяет, что:- Пользователь 1 получает обратно 50 токенов залога.

  • Баланс Пользователя 1 равен 100 (поскольку изначально было заминчено 100 токенов).

  • Баланс lendingToken Пользователя 1 равен нулю после погашения займа.

Запуск тестов

forge test

Развёртывание и верификация на Linea

Добавьте необходимые переменные в .env; файл .env должен находиться на корневом уровне.

LINEA_RPC_URL=https://linea-mainnet.infura.io/v3/ // Infura RPC endpoint for connecting to Linea 
PRIVATE_KEY=************************************************* // Wallet private key for signing transactions LINEA_API_KEY=************************* // API key for accessing Linea services via Infura
Копировать

Добавьте приведённые ниже данные в foundry.toml

[etherscan]
linea = { key = "${LINEA_API_KEY}", url = "https://api-sepolia.lineascan.build/api" }
Копировать

Создайте Makefile и добавьте в него приведённые ниже данные

deploy:
    forge create src/Lending.sol: LendingBorrowing  --rpc-url $(LINEA_RPC_URL) --private-key $(PRIVATE_KEY)

verify:; forge verify-contract --rpc-url $(LINEA_RPC_URL) --chain linea <contract address> src/Lending.sol:LendingBorrowing --constructor-args arg1 arg2
Копировать

Развёртывание

make deploy

Верификация

make verify

Заключение

Создание простого смарт-контракта для кредитования и заимствования закладывает основу для понимания DeFi и разработки на блокчейне. В этом руководстве рассмотрены:

  • Внесение залога — пользователи блокируют активы в качестве обеспечения займов.

  • Получение займов — заёмщики получают доступ к средствам на основе своего залога.

  • Погашение займов — пользователи возвращают заимствованные средства для погашения долга.

  • Вывод залога — пользователи возвращают залог после полного погашения.

Объединив эти элементы, мы создали функциональную автоматизированную систему кредитования. По мере роста DeFi эти концепции служат строительными блоками для более сложных финансовых приложений.

Для получения практических руководств и глубокого погружения в разработку на блокчейне посетите канал MetaMask Developer на YouTube и следите за нашими последними материалами в Twitter.

Переведено ИИ. Может содержать ошибки. Пожалуйста, всегда проверяйте информацию.

Оцените перевод

Автор статьи:

  • Kingsley Okonkwo

    Кингсли — сертифицированный разработчик блокчейна Ethereum, работающий техническим писателем в Consensys с особым акцентом на инструменты для разработчиков. До прихода в Consensys Кингсли работал фриланс-разработчиком бэкенда на нескольких платформах, включая Gigster и Braintrust. Имея за плечами 5 лет опыта в разработке программного обеспечения, он уверенно владеет такими инструментами, как JavaScript (Node.js и React), GoLang, SQL и Docker. Кингсли мастерски создаёт пошаговые руководства и практические гайды, используя новейшие технологии web3, чтобы помочь коллегам-разработчикам создавать более качественные dapps. В настоящее время проживая в Дубае, Кингсли в свободное время увлекается баскетболом и футболом.

    Читать все статьи