Создание смарт-контракта краудфандинга с помощью Solidity


Что такое краудфанд

Crowdfunding is the practice of using modest sums of money from a large number of people to finance a new business endeavor.

Допустим, я хочу открыть скромный чайный магазин, но у меня нет для этого ни ресурсов, ни денег. Что тогда я могу сделать?
Либо я могу получить кредит от друга, семьи или банка, либо я могу попросить кого-то дать мне деньги и поработать со мной над проектом. Краудфандинг будет использоваться, если проект слишком большой, чтобы в него мог вложиться один инвестор. Я буду просить деньги у кого угодно в обмен на акции моего бизнеса, и каждый инвестирующий будет обладать частью в бизнесе.


Как это работает?

Посмотрите на иллюстрацию структуры, которую мы планируем построить в первую очередь.

  • Владелец бизнеса вызывает контракт для запуска кампании, используя несколько обоснований, включая количество токенов, которые необходимо собрать для кампании, дату начала и дату окончания.
  • Если кампания еще не началась, владелец бизнеса может отменить ее в любое время.
  • Используя функцию «залог» и вводя «id» кампании вместе с количеством токенов, которые необходимо заложить, пользователи могут пожертвовать свои токены на конкретную кампанию.
  • Пока кампания все еще активна, они также могут забрать свои ранее обещанные токены.
  • По завершении кампании можно получить один из двух возможных результатов.
    • Кампания считается успешной, если она собрала необходимое количество токенов и соответствует минимальным требованиям владельца бизнеса. В этом случае владелец бизнеса может вызвать функцию «claim», чтобы забрать все токены.
    • Если заложено недостаточное количество токенов, что является другим сценарием провала кампании, залогодатели могут вывести свои токены из контракта с помощью функции «withdraw».

Интеллектуальный контракт

Весь файл —

Envoy-VC / Smart-Contracts

Коллекция смарт-контрактов, которые помогут вам в работе над проектами web 3.

ПРЕКВИЗИТ

  • Основы работы с Remix IDE.
  • Некоторые базовые знания о Solidity и токенах ERC-20.

Сначала мы указываем нашу лицензию и версию Solidity, которую мы собираемся использовать. Версия, на которой мы работаем, обозначается pragma solidity; обратите внимание, что версия нашего компилятора должна совпадать, чтобы не было признаков ошибки.
В этой статье будет использоваться версия 0.8.7.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
Вход в полноэкранный режим Выход из полноэкранного режима

Чтобы помочь контракту вызывать функции transfer и transferFrom из контракта ERC-20 Token Contract, сейчас мы построим интерфейс для наших ERC-20 Tokens.

interface IERC20 {
    function transfer(address, uint) external returns (bool);

    function transferFrom(
        address,
        address,
        uint
    ) external returns (bool);
}
Вход в полноэкранный режим Выход из полноэкранного режима

Теперь мы объявим некоторые переменные состояния, чтобы начать работу нашего смарт-контракта.

  • Кампания — структура для хранения данных о создателе кампании, цели, времени начала, времени окончания и заложенных токенах.
  • токен — для обозначения контракта ERC-20 Token, используемого для передачи токенов.
  • count — для отслеживания кампаний.
  • maxDuration — указать максимальную продолжительность кампании.
  • campaigns — mapping, который связывает кампании с их ID.
  • pledgedAmount — mapping для связи адреса пользователя и количества обещанных им токенов, и еще один mapping для связи с идентификатором кампании.
struct Campaign {
        address creator;
        uint goal;
        uint pledged;
        uint startAt;
        uint endAt;
        bool claimed;
    }

    IERC20 public immutable token;
    uint public count;
    uint public maxDuration;
    mapping(uint => Campaign) public campaigns;
    mapping(uint => mapping(address => uint)) public pledgedAmount;
Вход в полноэкранный режим Выход из полноэкранного режима

Далее мы обозначим некоторые действия как события, которые произойдут, если кампания будет начата, токен будет заложен или не заложен, кампания будет отменена, а токен будет востребован или отозван.

event Launch(
        uint id,
        address indexed creator,
        uint goal,
        uint32 startAt,
        uint32 endAt
    );
    event Cancel(uint id);
    event Pledge(uint indexed id, address indexed caller, uint amount);
    event Unpledge(uint indexed id, address indexed caller, uint amount);
    event Claim(uint id);
    event Refund(uint id, address indexed caller, uint amount);
Войти в полноэкранный режим Выход из полноэкранного режима

Далее мы настраиваем конструктор нашего контракта, которому в качестве двух входных данных требуется адрес токена ERC-20 и максимальное время проведения кампании.

constructor(address _token, uint _maxDuration) {
        token = IERC20(_token);
        maxDuration = _maxDuration;
    }
Войти в полноэкранный режим Выход из полноэкранного режима

Наша первая функция «launch», которая принимает цель кампании, метку начала и метку окончания, теперь определена.

Перед запуском кампании мы сначала выполняем несколько проверок.

  1. Мы определяем, превышает ли время начала текущее время.
  2. Мы убеждаемся, что время окончания позже времени начала.
  3. Наконец, мы убеждаемся, что кампания не выйдет за пределы своего максимального времени.

После этого мы поднимаем нашу переменную count. Затем информация о кампании сохраняется в связке campaigns, где переменная count служит ключом, а struct — значением.

И, наконец, создайте событие Launch.

function launch(uint _goal, uint32 _startAt, uint32 _endAt) external {
        require(_startAt >= block.timestamp,"Start time is less than current Block Timestamp");
        require(_endAt > _startAt,"End time is less than Start time");
        require(_endAt <= block.timestamp + maxDuration, "End time exceeds the maximum Duration");

        count += 1;
        campaigns[count] = Campaign({
            creator: msg.sender,
            goal: _goal,
            pledged: 0,
            startAt: _startAt,
            endAt: _endAt,
            claimed: false
        });

        emit Launch(count,msg.sender,_goal,_startAt,_endAt);
    }
Вход в полноэкранный режим Выход из полноэкранного режима

Далее мы определяем функцию cancel, которая позволяет создателю кампании завершить кампанию при условии, что он является ее создателем и что кампания еще не началась.

function cancel(uint _id) external {
        Campaign memory campaign = campaigns[_id];
        require(campaign.creator == msg.sender, "You did not create this Campaign");
        require(block.timestamp < campaign.startAt, "Campaign has already started");

        delete campaigns[_id];
        emit Cancel(_id);
    }
Вход в полноэкранный режим Выход из полноэкранного режима

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

Для того чтобы передать токены от пользователя смарт-контракту, мы сначала выполняем базовые тесты, например, определяем, началась ли кампания или завершилась. Затем мы используем переменную token, которая соответствует интерфейсу IERC, и вызываем функцию transferFrom для передачи токенов от пользователя к смарт-контракту.

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

Затем мы испускаем событие Pledge.

function pledge(uint _id, uint _amount) external {
        Campaign storage campaign = campaigns[_id];
        require(block.timestamp >= campaign.startAt, "Campaign has not Started yet");
        require(block.timestamp <= campaign.endAt, "Campaign has already ended");
        campaign.pledged += _amount;
        pledgedAmount[_id][msg.sender] += _amount;
        token.transferFrom(msg.sender, address(this), _amount);

        emit Pledge(_id, msg.sender, _amount);
    }
Вход в полноэкранный режим Выход из полноэкранного режима

Мы предоставляем функцию unpledge, которая удаляет токены, обещанные пользователем, так же, как и функция pledge.

function unPledge(uint _id,uint _amount) external {
        Campaign storage campaign = campaigns[_id];
        require(block.timestamp >= campaign.startAt, "Campaign has not Started yet");
        require(block.timestamp <= campaign.endAt, "Campaign has already ended");
        require(pledgedAmount[_id][msg.sender] >= _amount,"You do not have enough tokens Pledged to withraw");

        campaign.pledged -= _amount;
        pledgedAmount[_id][msg.sender] -= _amount;
        token.transfer(msg.sender, _amount);

        emit Unpledge(_id, msg.sender, _amount);
    }
Вход в полноэкранный режим Выход из полноэкранного режима

Создатель может потребовать все токены, собранные для кампании, с помощью функции claim, которую мы определим далее, если выполняются следующие критерии.

  1. создатель кампании является тем, кто вызвал функцию.
  2. Кампания завершилась.
  3. Цель превышена по количеству собранных жетонов (кампания завершилась).
  4. Жетоны еще не были выкуплены.
function claim(uint _id) external {
        Campaign storage campaign = campaigns[_id];
        require(campaign.creator == msg.sender, "You did not create this Campaign");
        require(block.timestamp > campaign.endAt, "Campaign has not ended");
        require(campaign.pledged >= campaign.goal, "Campaign did not succed");
        require(!campaign.claimed, "claimed");

        campaign.claimed = true;
        token.transfer(campaign.creator, campaign.pledged);

        emit Claim(_id);
    }
Вход в полноэкранный режим Выход из полноэкранного режима

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

function refund(uint _id) external {
        Campaign memory campaign = campaigns[_id];
        require(block.timestamp > campaign.endAt, "not ended");
        require(campaign.pledged < campaign.goal, "You cannot Withdraw, Campaign has succeeded");

        uint bal = pledgedAmount[_id][msg.sender];
        pledgedAmount[_id][msg.sender] = 0;
        token.transfer(msg.sender, bal);

        emit Refund(_id, msg.sender, bal);
    }
Войти в полноэкранный режим Выход из полноэкранного режима

Вот так создается контракт крауд-финансирования, позволяющий пользователям создавать кампании и жертвовать токены на различные проекты.

Полный код —

Envoy-VC / Смарт-контракты

Коллекция смарт-контрактов, которые помогут вам в работе над вашими проектами на базе web 3.

Оцените статью
devanswers.ru
Добавить комментарий