# Base. Делаем важный деплой

By [CryptoFortochka](https://paragraph.com/@sosew) · 2024-07-09

---

[**CryptoFortochka**](https://t.me/cryptoforto) — гайды, ноды, новости, тестнеты

**Base** — это безопасный, доступный и удобный для разработчиков **Ethereum L2**, призванный привлечь следующий миллиард пользователей в **web3**. Созданный в рамках **Coinbase** и планирующий прогрессивную децентрализацию, Base стремится создать открытую, глобальную криптоэкономику, доступную всем

*   **Инвесторы:** Coinbase Ventures
    
*   **Арендовать сервер:** [PqHosting](https://pq.hosting/?from=540715)**,** [XorekCloud](https://xorek.cloud/?from=4767)**,** [AEZA](https://aeza.net/?ref=379357) , [Hetzner](https://accounts.hetzner.com/), [Contabo](https://contabo.com/en/vps/)
    
*   **Чат с поддержкой:** [https://t.me/fortochat](https://t.me/fortochat)
    

Вчера наткнулся на активность в тестовой сети **Base**, за который можно будет получить важную роль в дискорде, а ей владеют всего лишь **25к+** людей из **400к**

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

> _Также повторюсь, знания в_ **_IT_** _вам не потребуется, справиться каждый человек! Не пугайтесь вы этих цифр и букв)_

**Что делать?**
===============

*   Переходим по [**ссылке**](https://docs.base.org/base-camp/docs/deployment-to-testnet/deployment-to-testnet-exercise/) и коннектим **EVM** кошелек
    

![](https://storage.googleapis.com/papyrus_images/5db9047a3f391f8cfc3b27071a35c1397a6d9439ba9e9dae94f7c1bf68d54432.png)

*   Добавиться сеть **Base Sepolia** — добавляем
    

![](https://storage.googleapis.com/papyrus_images/931e2f161872de46e0fb6d35d53ba8304f633a6cdbdfed3e71930b3ba6f6ee00.png)

*   Далее идём к [**крану**](https://www.alchemy.com/faucets/base-sepolia) и запрашиваем тестовые **$ETH** в сети **Base Sepolia**
    

![](https://storage.googleapis.com/papyrus_images/de3995fd2a6b7bf21ed0436ea047a2ee350f3ecce2604fccbf60bef72872ce45.png)

*   Переходим к [**Remix**](https://remix.ethereum.org/#lang=en&optimize=false&runs=200&evmVersion=null) и сбрасываем **куки**
    
*   Слева тыкаем значок **двух папок** — далее снизу на папку **contracts** — теперь тыкаем на **2\_Owner.sol**
    

![](https://storage.googleapis.com/papyrus_images/be93fdef000316956a90f182907cf549dc9bc03bf48acefcbc479f5e548251bf.png)

*   Далее слева тыкаем на **значок** и прожимаем **синюю кнопку**
    

![](https://storage.googleapis.com/papyrus_images/510cb68df75bedabde1e15bfb585964394283a5666aa9704037ff975cb8e77ea.png)

*   Далее тыкаем на значок **Ethereum** — сверху выбираем **EVM** кошелек (**Metamask или Rabby**) — Коннектим кошелек
    

![](https://storage.googleapis.com/papyrus_images/969cb18d68e09c6596e17d39ba5fdf07cfcb472221030ab05bf71d7de8e3a629.png)

*   Прожимаем кнопку **Deploy**
    
*   Но за ранее в **EVM** кошельке поставьте **Base Sepolia**
    

![](https://storage.googleapis.com/papyrus_images/d152864d924b235603d400ba67cacce78ef6fedaf30da4557fb3a420a64bbe2f.png)

*   Подтверждаем транзакцию в сети **Base Sepolia**
    

> **_Отлично!_** Теперь давайте сделаем еще один контракт

*   Тыкаем по **значку папок** — далее создаем файл — называем его **BasicMath**— тыкаем на него
    

![](https://storage.googleapis.com/papyrus_images/7926eb94cd6701ece005246423025f204f9db1f502b0adf0d2dcb857c230f2a0.png)

*   Справа откроется консолька, вписываем туда вот это:
    

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    
    contract BasicMath {
        uint256 constant MAX_INT = type(uint256).max;    function adder(uint256 _a, uint256 _b) external pure returns (uint256 sum, bool error) {
            if (_b > MAX_INT - _a) {
                return (0, true); // Overflow occurred
            }
            return (_a + _b, false);
        }    function subtractor(uint256 _a, uint256 _b) external pure returns (uint256 difference, bool error) {
            if (_b > _a) {
                return (0, true); // Underflow occurred
            }
            return (_a - _b, false);
        }
    }//CHASE
    

*   Далее тыкаем слева на значок и прожимаем синюю кнопку
    

![](https://storage.googleapis.com/papyrus_images/4ada1f056b4334ab35054b4634cb004b4d57c7748996f8f835477aee94a5a80c.png)

*   Делаем **Deploy**
    
*   Подтверждаем транзакцию в **EVM**
    

![](https://storage.googleapis.com/papyrus_images/13eac5244f6889d9029efaf073ac83c4e63a71ebd7041cbfe9a628d69684fc2d.png)

*   После успешного развертывания контракта перейдите на левую боковую панель и прокрутите вниз, чтобы просмотреть код контракта **BaseToken**
    
*   Копируем адрес
    

![](https://storage.googleapis.com/papyrus_images/2e1d8d7a8d57dd8f0dc89975476cb3c405c755fee8df7af423959b03a6885975.png)

*   Переходим на [**страничку разработчика**](https://docs.base.org/base-camp/docs/deployment-to-testnet/deployment-to-testnet-exercise/) и вставляем этот адрес — тыкаем **Sumbit**
    

![](https://storage.googleapis.com/papyrus_images/5c6e9a9da9a278c73acbb8820be880319e16e1ce2262618dc4fc6862bf58eb74.png)

*   Отлично! Вот должно получиться что то тип такого (**как скрине**)
    

![](https://storage.googleapis.com/papyrus_images/50a87d61815243bc33c85fdaa539992bcd8e0da7276a992ad3a1dd25d9625986.png)

> _Осталось осталось сделать 13 контрактов, и процесс будет аналогичным_

*   Слева тыкаем значок **двух папок** — далее снизу на папку **contracts** — создаем файл **ControlStructures — тыкаем на него**
    

![](https://storage.googleapis.com/papyrus_images/6f7b29e03326a6bff561ec5a881ba2242553c82ef1329f07cc9dca87560776cc.png)

*   Вставляем этот текст в пустую консольку справа
    

    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.17;
    
    contract ControlStructures {
        // Define custom errors for use within the contract
        error AfterHours(uint256 time);
        error AtLunch();    // Function to determine the response based on the input number
        function fizzBuzz(uint256 _number) public pure returns (string memory response) {
            // Check if the number is divisible by both 3 and 5
            if (_number % 3 == 0 && _number % 5 == 0) {
                return "FizzBuzz"; // Return "FizzBuzz" if divisible by both 3 and 5
            } 
            // Check if the number is divisible by 3
            else if (_number % 3 == 0) {
                return "Fizz"; // Return "Fizz" if divisible by 3
            } 
            // Check if the number is divisible by 5
            else if (_number % 5 == 0) {
                return "Buzz"; // Return "Buzz" if divisible by 5
            } 
            // If none of the above conditions are met
            else {
                return "Splat"; // Return "Splat" if none of the conditions are met
            }
        }    // Function to determine the response based on the input time
        function doNotDisturb(uint256 _time) public pure returns (string memory result) {
            // Ensure the input time is within valid bounds (less than 2400)
            assert(_time < 2400);        // Check different time ranges and return appropriate responses or revert with errors
            if (_time > 2200 || _time < 800) {
                revert AfterHours(_time); // Revert with custom error if it's after 10:00 PM or before 8:00 AM
            } 
            else if (_time >= 1200 && _time <= 1299) {
                revert AtLunch(); // Revert with custom error if it's between 12:00 PM and 1:00 PM
            } 
            else if (_time >= 800 && _time <= 1199) {
                return "Morning!"; // Return "Morning!" if it's between 8:00 AM and 11:59 AM
            } 
            else if (_time >= 1300 && _time <= 1799) {
                return "Afternoon!"; // Return "Afternoon!" if it's between 1:00 PM and 5:59 PM
            } 
            else if (_time >= 1800 && _time <= 2200) {
                return "Evening!"; // Return "Evening!" if it's between 6:00 PM and 10:00 PM
            }
        }
    }//CHASE
    

![](https://storage.googleapis.com/papyrus_images/9f57b36f89f3b98f076344cc78db4f3032f01d365024135e07aedb7d840d0f2d.png)

*   Делаем все тоже самое, что и делали ранее
    
*   Приложу скрины
    

![](https://storage.googleapis.com/papyrus_images/61d282aa3e68f0eb177709196aea7b2ec5ea85f26e3be3fcba24d73cb0371585.png)

![](https://storage.googleapis.com/papyrus_images/bc6c2150ce381e09a0b0d9fb97141c5a9c87617d86297c1c2654b90251fe0676.png)

*   Копируем контракт
    

![](https://storage.googleapis.com/papyrus_images/641f9779d2e2a6d01d19a38003c55cc8c25ce54f1771c0f12ebc7c8eee3797b4.png)

*   Отправляем [**сюда**](https://docs.base.org/base-camp/docs/control-structures/control-structures-exercise) и вставляем контракт — прожимаем **Sumbit**
    
*   Должно быть **2 галочки (как на скрине)**
    

![](https://storage.googleapis.com/papyrus_images/c6189777b00a7ce014c9413f059d066eac3e50fd68ce2c1353302a4cbe751939.png)

*   Продолжаем! Создаем новый файл **Storage**
    

![](https://storage.googleapis.com/papyrus_images/f1b414ff462879ab2f6f8c4fead4ca87394cb16c92a369ac4d7bbd88454d4c51.png)

*   Копируем текст и вставляем в консольку
    

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.17;
    
    contract EmployeeStorage {
        // Declare private state variables to store employee data
        uint16 private shares; // Number of shares owned by the employee (private to contract)
        uint32 private salary; // Monthly salary of the employee (private to contract)
        uint256 public idNumber; // Unique identification number of the employee (publicly accessible)
        string public name; // Name of the employee (publicly accessible)    // Constructor to initialize employee data when contract is deployed
        constructor(uint16 _shares, string memory _name, uint32 _salary, uint _idNumber) {
            shares = _shares; // Initialize shares
            name = _name; // Initialize name
            salary = _salary; // Initialize salary
            idNumber = _idNumber; // Initialize idNumber
        }    // View function to retrieve the number of shares owned by the employee
        function viewShares() public view returns (uint16) {
            return shares;
        }
        
        // View function to retrieve the monthly salary of the employee
        function viewSalary() public view returns (uint32) {
            return salary;
        }    // Custom error declaration
        error TooManyShares(uint16 _shares);
        
        // Function to grant additional shares to the employee
        function grantShares(uint16 _newShares) public {
            // Check if the requested shares exceed the limit
            if (_newShares > 5000) {
                revert("Too many shares"); // Revert with error message
            } else if (shares + _newShares > 5000) {
                revert TooManyShares(shares + _newShares); // Revert with custom error message
            }
            shares += _newShares; // Grant the new shares
        }    // Function used for testing packing of storage variables (not relevant to main functionality)
        function checkForPacking(uint _slot) public view returns (uint r) {
            assembly {
                r := sload (_slot)
            }
        }    // Function to reset shares for debugging purposes (not relevant to main functionality)
        function debugResetShares() public {
            shares = 1000; // Reset shares to 1000
        }
    }//CHASE
    

*   Далее синюю кнопку
    

![](https://storage.googleapis.com/papyrus_images/a2106bbf06cbde27cf87a21fb2267d95684ddfcefb7c51a571882f9d627dabc0.png)

*   Далее выбираем **EVM** — и вписываем данные снизу
    
*   `shares` - 1000
    
*   `name` - Pat
    
*   `salary` - 50000
    
*   `idNumber` - 112358132134
    

![](https://storage.googleapis.com/papyrus_images/4b8cff2da6f8fcf7c4ee476f092a8f69ee6ac80f9fb86185c6962831197423e2.png)

*   Копируем деплой
    

![](https://storage.googleapis.com/papyrus_images/988fd7c4ce4b1c3a215fdc1b1591f2c9251bc4b657dd573281b2c984fa8a3cca.png)

*   Отправляем [**сюда**](https://docs.base.org/base-camp/docs/storage/storage-exercise) и вставляем контракт — прожимаем **Sumbit**
    

![](https://storage.googleapis.com/papyrus_images/c0175d385509ab6c0fb4d3ccce0d64868f18fb4a087efe9f5a1d7acfdcfbaaeb.png)

*   Должно быть **4 галочки (как на скрине)**
    

![](https://storage.googleapis.com/papyrus_images/0de67587a14dc9e72279020917915d8754f87a43fcf4bdb86b1b13a1fe193483.png)

*   Далее создаем файл **Arrays**
    
*   Копируем текст и вставляем в консольку
    

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.17;
    
    contract ArraysExercise {
        // Declare state variables to store arrays of numbers, timestamps, and senders
        uint[] numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; // Array of numbers initialized with values
        uint[] timestamps; // Dynamic array to store timestamps
        address[] senders; // Dynamic array to store sender addresses
    
        uint256 constant Y2K = 946702800; // Constant representing the Unix timestamp for the year 2000
    
        // Function to retrieve the array of numbers
        function getNumbers() external view returns (uint[] memory) {
            // Create a memory array to hold the numbers
            uint[] memory results = new uintUnsupported embed;
    
            // Copy the numbers from the state array to the memory array
            for(uint i=0; i<numbers.length; i++) {
                results[i] = numbers[i];
            }
    
            // Return the memory array
            return results;
        }
    
        // Function to reset the numbers array to its initial values
        function resetNumbers() public {
            numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
        }
    
        // Function to append new numbers to the numbers array
        function appendToNumbers(uint[] calldata _toAppend) public {
            // Iterate through the array to be appended
            for (uint i = 0; i < _toAppend.length; i++) {
                // Push each element of the array to be appended to the numbers array
                numbers.push(_toAppend[i]);
            }
        }
    
        // Function to save a timestamp along with the sender's address
        function saveTimestamp(uint _unixTimestamp) public {
            // Push the timestamp and sender's address to their respective arrays
            timestamps.push(_unixTimestamp);
            senders.push(msg.sender);
        }
    
        // Function to retrieve timestamps and senders after the year 2000
        function afterY2K() public view returns (uint256[] memory, address[] memory) {
            // Initialize counter for timestamps after Y2K
            uint256 counter = 0;
    
            // Count the number of timestamps after Y2K
            for (uint i = 0; i < timestamps.length; i++) {
                if (timestamps[i] > Y2K) {
                    counter++;
                }
            }
    
            // Initialize memory arrays to hold timestamps and senders after Y2K
            uint256[] memory timestampsAfterY2K = new uint256Unsupported embed;
            address[] memory sendersAfterY2K = new addressUnsupported embed;
    
            // Initialize index for inserting elements into memory arrays
            uint256 index = 0;
    
            // Iterate through timestamps and senders arrays to extract elements after Y2K
            for (uint i = 0; i < timestamps.length; i++) {
                if (timestamps[i] > Y2K) {
                    timestampsAfterY2K[index] = timestamps[i];
                    sendersAfterY2K[index] = senders[i];
                    index++;
                }
            }
    
            // Return timestamps and senders after Y2K
            return (timestampsAfterY2K, sendersAfterY2K);
        }
    
        // Function to reset the senders array
        function resetSenders() public {
            delete senders;
        }
    
        // Function to reset the timestamps array
        function resetTimestamps() public {
            delete timestamps;
        }
    }
    

*   Тыкаем на синюю кнопку
    

![](https://storage.googleapis.com/papyrus_images/2b53705979f970e700b5a776076a01856ecf8e672e9449f49fc4c442cefefaa0.png)

*   Делаем деплой
    

![](https://storage.googleapis.com/papyrus_images/fd22ea0b31452e3074a8857c55979871f5ab70debeff6d59c8168264694f511c.png)

*   Копируем контракт
    

![](https://storage.googleapis.com/papyrus_images/02a45a236ae91e8dbffd3cfd80f095f472ed4c2b39708a75c8db0ecbb95f0d98.png)

*   Отправляем [**сюда**](https://docs.base.org/base-camp/docs/storage/storage-exercise) и вставляем контракт — прожимаем **Sumbit**
    

![](https://storage.googleapis.com/papyrus_images/813d77ad239cfd1698bfc204ea36b2240f95a3ad17ea6fe68b64dc1e61e46cc4.png)

*   Должно быть **2 галочки (как на скрине)**
    

![](https://storage.googleapis.com/papyrus_images/1de779af993a5310704ca052de27cc72ba8aeaa2b15b1c8f410c52dbf48a2b4a.png)

*   Создаем файл **Mapping**
    

![](https://storage.googleapis.com/papyrus_images/3a67a819d502081019cde0c2a555a5f3c1c666e72275c3901df7c42f9cdf1047.png)

*   Копируем текст и вставляем в консольку
    

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.17;
    
    /**
     * @title FavoriteRecords
     * @dev Contract to manage a list of approved music records and allow users to add them to their favorites
     */
    contract FavoriteRecords {
        // Mapping to store whether a record is approved
        mapping(string => bool) private approvedRecords;
        // Array to store the index of approved records
        string[] private approvedRecordsIndex;
    
        // Mapping to store user's favorite records
        mapping(address => mapping(string => bool)) public userFavorites;
        // Mapping to store the index of user's favorite records
        mapping(address => string[]) private userFavoritesIndex;
    
        // Custom error to handle unapproved records
        error NotApproved(string albumName);
    
        /**
         * @dev Constructor that initializes the approved records list
         */
        constructor() {
            // Predefined list of approved records
            approvedRecordsIndex = [
                "Thriller", 
                "Back in Black", 
                "The Bodyguard", 
                "The Dark Side of the Moon", 
                "Their Greatest Hits (1971-1975)", 
                "Hotel California", 
                "Come On Over", 
                "Rumours", 
                "Saturday Night Fever"
            ];
            // Initialize the approved records mapping
            for (uint i = 0; i < approvedRecordsIndex.length; i++) {
                approvedRecords[approvedRecordsIndex[i]] = true;
            }
        }
    
        /**
         * @dev Returns the list of approved records
         * @return An array of approved record names
         */
        function getApprovedRecords() public view returns (string[] memory) {
            return approvedRecordsIndex;
        }
    
        /**
         * @dev Adds an approved record to the user's favorites
         * @param _albumName The name of the album to be added
         */
        function addRecord(string memory _albumName) public {
            // Check if the record is approved
            if (!approvedRecords[_albumName]) {
                revert NotApproved({albumName: _albumName});
            }
            // Check if the record is not already in the user's favorites
            if (!userFavorites[msg.sender][_albumName]) {
                // Add the record to the user's favorites
                userFavorites[msg.sender][_albumName] = true;
                // Add the record to the user's favorites index
                userFavoritesIndex[msg.sender].push(_albumName);
            }
        }
    
        /**
         * @dev Returns the list of a user's favorite records
         * @param _address The address of the user
         * @return An array of user's favorite record names
         */
        function getUserFavorites(address _address) public view returns (string[] memory) {
            return userFavoritesIndex[_address];
        }
    
        /**
         * @dev Resets the caller's list of favorite records
         */
        function resetUserFavorites() public {
            // Iterate through the user's favorite records
            for (uint i = 0; i < userFavoritesIndex[msg.sender].length; i++) {
                // Delete each record from the user's favorites mapping
                delete userFavorites[msg.sender][userFavoritesIndex[msg.sender][i]];
            }
            // Delete the user's favorites index
            delete userFavoritesIndex[msg.sender];
        }
    }
    

*   Тыкаем на синюю кнопку
    

![](https://storage.googleapis.com/papyrus_images/e6fa3147989b6cb6fa87d42f97c58a83deb908e123528f460c7d3e9f3c7bb6d1.png)

*   Делаем деплой
    

![](https://storage.googleapis.com/papyrus_images/1f2ad55708d2bdce48f07a620e3ea9e51dcc31568277993f4a11c8584c236bb1.png)

*   Копируем адрес контракта
    

![](https://storage.googleapis.com/papyrus_images/02c26ac23ac48e99c5e9e6307aecd9124924f6ad8f3b8bf4c6ce1818ba31f852.png)

*   Отправляем [**сюда**](https://docs.base.org/base-camp/docs/mappings/mappings-exercise/) и вставляем контракт — прожимаем **Sumbit**
    

![](https://storage.googleapis.com/papyrus_images/f3fdfb282dd93d6a3973fe3305e56420cc8e7c28e58c68fdabd491db77999d8e.png)

*   Должно быть **2 галочки (как на скрине)**
    

![](https://storage.googleapis.com/papyrus_images/87b2f6b987d2e8b4c5c0912687d603f360eea27eb6fac5f293192077ed6ec437.png)

*   Создаем файл **Structs**
    

![](https://storage.googleapis.com/papyrus_images/88b9fbd9a84431d9310938d2e50180ed55cac56961a0187b5586de8105019c03.png)

*   Копируем текст и вставляем в консольку
    

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.17;
    
    /**
     * @title GarageManager
     * @dev Contract to manage a garage of cars for each user
     */
    contract GarageManager {
        // Mapping to store the garage of cars for each user
        mapping(address => Car[]) private garages;
    
        // Struct to represent a car
        struct Car {
            string make; // Make of the car
            string model; // Model of the car
            string color; // Color of the car
            uint numberOfDoors; // Number of doors of the car
        }
    
        // Custom error for handling invalid car index
        error BadCarIndex(uint256 index);
    
        /**
         * @dev Adds a new car to the caller's garage
         * @param _make The make of the car
         * @param _model The model of the car
         * @param _color The color of the car
         * @param _numberOfDoors The number of doors of the car
         */
        function addCar(string memory _make, string memory _model, string memory _color, uint _numberOfDoors) external {
            // Push a new car struct with the provided details to the caller's garage
            garages[msg.sender].push(Car(_make, _model, _color, _numberOfDoors));
        }
    
        /**
         * @dev Retrieves the caller's array of cars
         * @return An array of `Car` structs
         */
        function getMyCars() external view returns (Car[] memory) {
            // Return the array of cars stored in the caller's garage
            return garages[msg.sender];
        }
    
        /**
         * @dev Retrieves a specific user's array of cars
         * @param _user The address of the user
         * @return An array of `Car` structs
         */
        function getUserCars(address _user) external view returns (Car[] memory) {
            // Return the array of cars stored in the garage of the specified user
            return garages[_user];
        }
    
        /**
         * @dev Updates a specific car in the caller's garage
         * @param _index The index of the car in the garage array
         * @param _make The new make of the car
         * @param _model The new model of the car
         * @param _color The new color of the car
         * @param _numberOfDoors The new number of doors of the car
         */
        function updateCar(uint256 _index, string memory _make, string memory _model, string memory _color, uint _numberOfDoors) external {
            // Check if the provided index is valid
            if (_index >= garages[msg.sender].length) {
                revert BadCarIndex({index: _index}); // Revert with custom error if the index is invalid
            }
            // Update the specified car with the new details
            garages[msg.sender][_index] = Car(_make, _model, _color, _numberOfDoors);
        }
    
        /**
         * @dev Deletes all cars in the caller's garage
         */
        function resetMyGarage() external {
            // Delete all cars from the caller's garage
            delete garages[msg.sender];
        }
    }
    

*   Тыкаем на синюю кнопку
    

![](https://storage.googleapis.com/papyrus_images/30d1ffb4d2513e7eeec6e602759e8b539101f9363641027e21a5a9a978cf1ed5.png)

*   Делаем деплой
    

![](https://storage.googleapis.com/papyrus_images/5c50a1df80daed92722a1bb107277d86700fffc87d4c8675a7e4f56ff59ca829.png)

*   Копируем адрес контракта
    

![](https://storage.googleapis.com/papyrus_images/726dc146110db044f73d6704de44ceb499ceaa472e0df557c2268a47c2d19bc2.png)

*   Отправляем [**сюда**](https://docs.base.org/base-camp/docs/structs/structs-exercise/) и вставляем контракт — прожимаем **Sumbit**
    

![](https://storage.googleapis.com/papyrus_images/8cc732d6d7b2d205638e304ae6309d432724dcd3bd23f048367ca590227108f5.png)

*   Должно быть 1 **галочка (как на скрине)**
    

![](https://storage.googleapis.com/papyrus_images/69b29d9f8e2e18d858f3f11f177fbfcfc7d6264f77af7ba47516648b12f4c318.png)

*   Создаем файл **Inheritance**
    

![](https://storage.googleapis.com/papyrus_images/feda1b5300c612d57ec471bd60b829ead4bd189899f3074737f764f626196395.png)

*   Копируем текст и вставляем в консольку
    

    // SPDX-License-Identifier: MIT
    
    pragma solidity 0.8.17;
    
    /**
     * @title Employee
     * @dev Abstract contract defining common properties and behavior for employees.
     */
    abstract contract Employee {
        uint public idNumber; // Unique identifier for the employee
        uint public managerId; // Identifier of the manager overseeing the employee
    
        /**
         * @dev Constructor to initialize idNumber and managerId.
         * @param _idNumber The unique identifier for the employee.
         * @param _managerId The identifier of the manager overseeing the employee.
         */
        constructor(uint _idNumber, uint _managerId) {
            idNumber = _idNumber;
            managerId = _managerId;
        }
    
        /**
         * @dev Abstract function to be implemented by derived contracts to get the annual cost of the employee.
         * @return The annual cost of the employee.
         */
        function getAnnualCost() public virtual returns (uint);
    }
    
    /**
     * @title Salaried
     * @dev Contract representing employees who are paid an annual salary.
     */
    contract Salaried is Employee {
        uint public annualSalary; // The annual salary of the employee
    
        /**
         * @dev Constructor to initialize the Salaried contract.
         * @param _idNumber The unique identifier for the employee.
         * @param _managerId The identifier of the manager overseeing the employee.
         * @param _annualSalary The annual salary of the employee.
         */
        constructor(uint _idNumber, uint _managerId, uint _annualSalary) Employee(_idNumber, _managerId) {
            annualSalary = _annualSalary;
        }
    
        /**
         * @dev Overrides the getAnnualCost function to return the annual salary of the employee.
         * @return The annual salary of the employee.
         */
        function getAnnualCost() public override view returns (uint) {
            return annualSalary;
        }
    }
    
    /**
     * @title Hourly
     * @dev Contract representing employees who are paid an hourly rate.
     */
    contract Hourly is Employee {
        uint public hourlyRate; // The hourly rate of the employee
    
        /**
         * @dev Constructor to initialize the Hourly contract.
         * @param _idNumber The unique identifier for the employee.
         * @param _managerId The identifier of the manager overseeing the employee.
         * @param _hourlyRate The hourly rate of the employee.
         */
        constructor(uint _idNumber, uint _managerId, uint _hourlyRate) Employee(_idNumber, _managerId) {
            hourlyRate = _hourlyRate;
        }
    
        /**
         * @dev Overrides the getAnnualCost function to calculate the annual cost based on the hourly rate.
         * Assuming a full-time workload of 2080 hours per year.
         * @return The annual cost of the employee.
         */
        function getAnnualCost() public override view returns (uint) {
            return hourlyRate * 2080;
        }
    }
    
    /**
     * @title Manager
     * @dev Contract managing a list of employee IDs.
     */
    contract Manager {
        uint[] public employeeIds; // List of employee IDs
    
        /**
         * @dev Function to add a new employee ID to the list.
         * @param _reportId The ID of the employee to be added.
         */
        function addReport(uint _reportId) public {
            employeeIds.push(_reportId);
        }
    
        /**
         * @dev Function to reset the list of employee IDs.
         */
        function resetReports() public {
            delete employeeIds;
        }
    }
    
    /**
     * @title Salesperson
     * @dev Contract representing salespeople who are paid hourly.
     */
    contract Salesperson is Hourly {
        /**
         * @dev Constructor to initialize the Salesperson contract.
         * @param _idNumber The unique identifier for the employee.
         * @param _managerId The identifier of the manager overseeing the employee.
         * @param _hourlyRate The hourly rate of the employee.
         */
        constructor(uint _idNumber, uint _managerId, uint _hourlyRate) 
            Hourly(_idNumber, _managerId, _hourlyRate) {}
    }
    
    /**
     * @title EngineeringManager
     * @dev Contract representing engineering managers who are paid an annual salary and have managerial responsibilities.
     */
    contract EngineeringManager is Salaried, Manager {
        /**
         * @dev Constructor to initialize the EngineeringManager contract.
         * @param _idNumber The unique identifier for the employee.
         * @param _managerId The identifier of the manager overseeing the employee.
         * @param _annualSalary The annual salary of the employee.
         */
        constructor(uint _idNumber, uint _managerId, uint _annualSalary) 
            Salaried(_idNumber, _managerId, _annualSalary) {}
    }
    
    /**
     * @title InheritanceSubmission
     * @dev Contract for deploying instances of Salesperson and EngineeringManager.
     */
    contract InheritanceSubmission {
        address public salesPerson; // Address of the deployed Salesperson instance
        address public engineeringManager; // Address of the deployed EngineeringManager instance
    
        /**
         * @dev Constructor to initialize the InheritanceSubmission contract.
         * @param _salesPerson Address of the deployed Salesperson instance.
         * @param _engineeringManager Address of the deployed EngineeringManager instance.
         */
        constructor(address _salesPerson, address _engineeringManager) {
            salesPerson = _salesPerson;
            engineeringManager = _engineeringManager;
        }
    }
    

*   Тыкаем на синюю кнопку
    

![](https://storage.googleapis.com/papyrus_images/6d7847a2cb36061e94337758934ab31542c870af6756d74aa567380c90777dbc.png)

*   Далее делаем деплой, но в **Contract** выбираем **Salesperson**
    

![](https://storage.googleapis.com/papyrus_images/987796945c028679658f37d6015351a10fd3c466f2218c8f42991347e0d9c0c6.png)

*   Тыкаем на стрелочку и вписываем цифры — тыкаем на **transact** — подтверждаем транзакцию
    

Id Number: **55555**  
Manager id: **12345**  
Salary: **20**

![](https://storage.googleapis.com/papyrus_images/ae2864a1a67c28d4e3061b2bbe8abf78a1570be9e1f812dbc25103b1ab2d8a20.png)

*   Далее снова выбираем **Contract** и тыкаем на **EngineeringManager**
    

![](https://storage.googleapis.com/papyrus_images/8b3b1b9756fe61b0adf9b83ab9aef10ce8dc5b0d5f976e9840ea7d622705b3e2.png)

*   Вписываем эти данные
    

Id Number: **54321**  
Manager id: **11111**  
Annual salary: **200000**

*   Тыкаем на стрелочку и вписываем цифры — тыкаем на **transact** — подтверждаем транзакцию
    

![](https://storage.googleapis.com/papyrus_images/fa48847eb998c7d60e774a23e36153433fa7cbf4b74daa4f18ec3f75bfa0ba45.png)

*   Далее тыкаем на **Contract** выбираем **InheritanceSubmission**
    

![](https://storage.googleapis.com/papyrus_images/bdef051ebe07b4f88a57ba6e28a1cf24f5610fd93eb64732cd13b6dad71e163e.png)

*   Спускаемся вниз и копируем 1. **Salesperon** контракт адрес; 2. **EngineeringManager** контракт адрес и вписываем их выше (**как на скрине**)
    

![](https://storage.googleapis.com/papyrus_images/aca83d8f37020c7ddd57aee29602b0f9d7dc7c62b82daab0ef57b19c6a261e2f.png)

*   Тыкаем **transact** и подтверждаем транзу
    

![](https://storage.googleapis.com/papyrus_images/9facfafaef394346d7606e85350a6994ce941572db28506ec56db685852be2a2.png)

*   Копируем **Inheritance** контракт адрес
    

![](https://storage.googleapis.com/papyrus_images/d13032925091f4ea4b67b240200d8bd71a4ae034e34ec1c6dde2c1f117a3c607.png)

*   Отправляем [**сюда**](https://docs.base.org/base-camp/docs/inheritance/inheritance-exercise/) и вставляем контракт — прожимаем **Sumbit**
    

![](https://storage.googleapis.com/papyrus_images/d945caf68ce560fd186c6bd3e34ffb3fd2a175b4125d2db822929a8268449a2a.png)

*   Должно быть **4 галочки (как на скрине)**
    

![](https://storage.googleapis.com/papyrus_images/8b5536fe8ae5f22909f0eb66e76ea6c315b9894c9ca78216693a0a713f093eda.png)

*   Создаем новый файл **SillyStringUtils**
    

![](https://storage.googleapis.com/papyrus_images/e37c4fee2d24f40dba73bf02bdca061987003a73a1fde7f798d3112aab043839.png)

*   Копируем текст и вставляем в консольку
    

    // SPDX-License-Identifier: MIT
    
    pragma solidity ^0.8.17;
    
    library SillyStringUtils {
    
        struct Haiku {
            string line1;
            string line2;
            string line3;
        }
    
        function shruggie(string memory _input) internal pure returns (string memory) {
            return string.concat(_input, unicode" 🤷");
        }
    }
    

*   Копируем и вставляем текст
    

![](https://storage.googleapis.com/papyrus_images/bb8dd7b7cb088270ed2fceae3b4bf81c81a827d3eff04a9c7d05ba320cd95a2f.png)

*   Далее создаем файл **Imports**
    

![](https://storage.googleapis.com/papyrus_images/33abc31c2c64b0f88b3fbf30af9379cb715992635fa2551fe8abde52d2cab1e8.png)

*   Копируем текст и вставляем в консольку
    

    // SPDX-License-Identifier: MIT
    
    // Importing the SillyStringUtils library
    import "./SillyStringUtils.sol";
    
    pragma solidity 0.8.17;
    
    contract ImportsExercise {
        // Using the SillyStringUtils library for string manipulation
        using SillyStringUtils for string;
    
        // Declaring a public variable to store a Haiku
        SillyStringUtils.Haiku public haiku;
    
        // Function to save a Haiku
        function saveHaiku(string memory _line1, string memory _line2, string memory _line3) public {
            haiku.line1 = _line1;
            haiku.line2 = _line2;
            haiku.line3 = _line3;
        }
    
        // Function to retrieve the saved Haiku
        function getHaiku() public view returns (SillyStringUtils.Haiku memory) {
            return haiku;
        }
    
        // Function to append a shrugging emoji to the third line of the Haiku
        function shruggieHaiku() public view returns (SillyStringUtils.Haiku memory) {
            // Creating a copy of the Haiku
            SillyStringUtils.Haiku memory newHaiku = haiku;
            // Appending the shrugging emoji to the third line using the shruggie function from the SillyStringUtils library
            newHaiku.line3 = newHaiku.line3.shruggie();
            return newHaiku;
        }
    }
    

*   Синяя кнопка
    

![](https://storage.googleapis.com/papyrus_images/1d161f3a3d4a06f14967ae2011c708ba43999d601b0569d5811f50355a0f6ce3.png)

*   Делаем деплой и копируем адрес контракта
    

![](https://storage.googleapis.com/papyrus_images/d8b14e4f9684aef463786126d68553217d640ad53e64b645bd8c23432c90288f.png)

*   Отправляем [**сюда**](https://docs.base.org/base-camp/docs/imports/imports-exercise/) и вставляем контракт — прожимаем **Sumbit**
    

![](https://storage.googleapis.com/papyrus_images/7bbfb62ad2f3b2a6802c3fc377423d51d80567b161cff184d61c2b9cae124673.png)

*   Должно быть 1 **галочка (как на скрине)**
    

![](https://storage.googleapis.com/papyrus_images/e0808e561091ec4b5d27257171de8760d0d76bbd773110310843263821e3948d.png)

*   Далее создаем файл **Errors**
    

![](https://storage.googleapis.com/papyrus_images/5a5939c69caf6dd904c887553b54002c60002629001734e4f5e62debb5cacaf8.png)

*   Копируем текст и вставляем в консольку
    

    // SPDX-License-Identifier: MIT
    
    pragma solidity ^0.8.17;
    
    contract ErrorTriageExercise {
        /**
         * @dev Finds the difference between each uint with its neighbor (a to b, b to c, etc.)
         * and returns a uint array with the absolute integer difference of each pairing.
         * 
         * @param _a The first unsigned integer.
         * @param _b The second unsigned integer.
         * @param _c The third unsigned integer.
         * @param _d The fourth unsigned integer.
         * 
         * @return results An array containing the absolute differences between each pair of integers.
         */
        function diffWithNeighbor(
            uint _a,
            uint _b,
            uint _c,
            uint _d
        ) public pure returns (uint[] memory) {
            // Initialize an array to store the differences
            uint[] memory results = new uintUnsupported embed;
    
            // Calculate the absolute difference between each pair of integers and store it in the results array
            results[0] = _a > _b ? _a - _b : _b - _a;
            results[1] = _b > _c ? _b - _c : _c - _b;
            results[2] = _c > _d ? _c - _d : _d - _c;
    
            // Return the array of differences
            return results;
        }
    
        /**
         * @dev Changes the base by the value of the modifier. Base is always >= 1000. Modifiers can be
         * between positive and negative 100.
         * 
         * @param _base The base value to be modified.
         * @param _modifier The value by which the base should be modified.
         * 
         * @return returnValue The modified value of the base.
         */
        function applyModifier(
            uint _base,
            int _modifier
        ) public pure returns (uint returnValue) {
            // Apply the modifier to the base value
            if(_modifier > 0) {
                return _base + uint(_modifier);
            }
            return _base - uint(-_modifier);
        }
    
    
        uint[] arr;
    
        function popWithReturn() public returns (uint returnNum) {
            if(arr.length > 0) {
                uint result = arr[arr.length - 1];
                arr.pop();
                return result;
            }
        }
    
        // The utility functions below are working as expected
        function addToArr(uint _num) public {
            arr.push(_num);
        }
    
        function getArr() public view returns (uint[] memory) {
            return arr;
        }
    
        function resetArr() public {
            delete arr;
        }
    }
    

*   Синяя кнопка
    

![](https://storage.googleapis.com/papyrus_images/5347bb49f4092ef4fb588631feef97d43214f4d3fcd107f8e6c23514edacef1e.png)

*   Делаем деплой и копируем адрес контракта
    

![](https://storage.googleapis.com/papyrus_images/f9e58f697b7aa5cf118550de1e8f9ee7a2979160160bd80edf1b076c0f1be156.png)

*   Отправляем [**сюда**](https://docs.base.org/base-camp/docs/error-triage/error-triage-exercise/) и вставляем контракт — прожимаем **Sumbit**
    

![](https://storage.googleapis.com/papyrus_images/77a6c6a83ee5d21052a3ee84727e4bbd38887babf675bf5c9fb19eb759296e51.png)

*   Должно быть **3 галочки (как на скрине)**
    

![](https://storage.googleapis.com/papyrus_images/1407116739492deae8e686d3344b7e3899c295991168072bce06dbb2e9396b74.png)

*   Создаем файл **AddressBook**
    

![](https://storage.googleapis.com/papyrus_images/9fcca0d35a39d3cee32355bd1e3bb173df374ee9143be20f1d70de7d4f4997fe.png)

*   Копируем текст и вставляем в консольку
    

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.8;
    
    import "@openzeppelin/contracts/access/Ownable.sol";
    
    contract AddressBook is Ownable(msg.sender) {
        // Define a private salt value for internal use
        string private salt = "value"; 
    
        // Define a struct to represent a contact
        struct Contact {
            uint id; // Unique identifier for the contact
            string firstName; // First name of the contact
            string lastName; // Last name of the contact
            uint[] phoneNumbers; // Array to store multiple phone numbers for the contact
        }
    
        // Array to store all contacts
        Contact[] private contacts;
    
        // Mapping to store the index of each contact in the contacts array using its ID
        mapping(uint => uint) private idToIndex;
    
        // Variable to keep track of the ID for the next contact
        uint private nextId = 1;
    
        // Custom error for when a contact is not found
        error ContactNotFound(uint id);
    
        // Function to add a new contact
        function addContact(string calldata firstName, string calldata lastName, uint[] calldata phoneNumbers) external onlyOwner {
            // Create a new contact with the provided details and add it to the contacts array
            contacts.push(Contact(nextId, firstName, lastName, phoneNumbers));
            // Map the ID of the new contact to its index in the array
            idToIndex[nextId] = contacts.length - 1;
            // Increment the nextId for the next contact
            nextId++;
        }
    
        // Function to delete a contact by its ID
        function deleteContact(uint id) external onlyOwner {
            // Get the index of the contact to be deleted
            uint index = idToIndex[id];
            // Check if the index is valid and if the contact with the provided ID exists
            if (index >= contacts.length || contacts[index].id != id) revert ContactNotFound(id);
    
            // Replace the contact to be deleted with the last contact in the array
            contacts[index] = contacts[contacts.length - 1];
            // Update the index mapping for the moved contact
            idToIndex[contacts[index].id] = index;
            // Remove the last contact from the array
            contacts.pop();
            // Delete the mapping entry for the deleted contact ID
            delete idToIndex[id];
        }
    
        // Function to retrieve a contact by its ID
        function getContact(uint id) external view returns (Contact memory) {
            // Get the index of the contact
            uint index = idToIndex[id];
            // Check if the index is valid and if the contact with the provided ID exists
            if (index >= contacts.length || contacts[index].id != id) revert ContactNotFound(id);
            // Return the contact details
            return contacts[index];
        }
    
        // Function to retrieve all contacts
        function getAllContacts() external view returns (Contact[] memory) {
            // Return the array of all contacts
            return contacts;
        }
    }
    

*   Далее создаем файл **Other Contracts**
    
*   Копируем текст и вставляем в консольку
    

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.8;
    
    // Import the AddressBook contract to interact with it
    import "./AddressBook.sol";
    
    // Contract for creating new instances of AddressBook
    contract AddressBookFactory {
        // Define a private salt value for internal use
        string private salt = "value";
    
        // Function to deploy a new instance of AddressBook
        function deploy() external returns (AddressBook) {
            // Create a new instance of AddressBook
            AddressBook newAddressBook = new AddressBook();
    
            // Transfer ownership of the new AddressBook contract to the caller of this function
            newAddressBook.transferOwnership(msg.sender);
    
            // Return the newly created AddressBook contract
            return newAddressBook;
        }
    }
    

*   Далее отправляемся к синей кнопке, и сверху ставим версию **0.8.20**
    
*   Тыкаем на синюю кнопку
    

![](https://storage.googleapis.com/papyrus_images/923b46020e1b1be8d879ae0f35273613915b693481bdc8dc3a3dcaca44a6a769.png)

*   Делаем деплой и копируем адрес контракта
    

![](https://storage.googleapis.com/papyrus_images/cdc53cc8dbe6edc5ca02e4985e9156f7ce632ba4795056fdd2617548d2876089.png)

*   Отправляем [**сюда**](https://docs.base.org/base-camp/docs/new-keyword/new-keyword-exercise/) и вставляем контракт — прожимаем **Sumbit**
    

![](https://storage.googleapis.com/papyrus_images/696d9ce9b0d1bbf30315ab3f0ff01335fca5c516e2ab403d69dbf5303bb46111.png)

*   Должно быть **2 галочки (как на скрине)**
    

![](https://storage.googleapis.com/papyrus_images/980e88b43234550b60a679e3920f10c4eaf33a68479fc01edbc444bbd375a358.png)

*   Создаем файл **Minimal Token**
    

![](https://storage.googleapis.com/papyrus_images/c648ec1bf8e7b80fdd216d65a4969040e1788c5e8868f726971b1a0dca8ebe3a.png)

*   Копируем текст и вставляем в консольку
    

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    
    // Contract for an unburnable token
    contract UnburnableToken {
        string private salt = "123456"; // A private string variable
    
        // Mapping to track token balances of addresses
        mapping(address => uint256) public balances;
    
        uint256 public totalSupply; // Total supply of tokens
        uint256 public totalClaimed; // Total number of tokens claimed
        mapping(address => bool) private claimed; // Mapping to track whether an address has claimed tokens
    
        // Custom errors
        error TokensClaimed(); // Error for attempting to claim tokens again
        error AllTokensClaimed(); // Error for attempting to claim tokens when all are already claimed
        error UnsafeTransfer(address _to); // Error for unsafe token transfer
    
        // Constructor to set the total supply of tokens
        constructor() {
            totalSupply = 100000000; // Set the total supply of tokens
        }
    
        // Public function to claim tokens
        function claim() public {
            // Check if all tokens have been claimed
            if (totalClaimed >= totalSupply) revert AllTokensClaimed();
            
            // Check if the caller has already claimed tokens
            if (claimed[msg.sender]) revert TokensClaimed();
    
            // Update balances and claimed status
            balances[msg.sender] += 1000;
            totalClaimed += 1000;
            claimed[msg.sender] = true;
        }
    
        // Public function for safe token transfer
        function safeTransfer(address _to, uint256 _amount) public {
            // Check for unsafe transfer conditions, including if the target address has a non-zero ether balance
            if (_to == address(0) || _to.balance == 0) revert UnsafeTransfer(_to);
    
            // Ensure the sender has enough balance to transfer
            require(balances[msg.sender] >= _amount, "Insufficient balance");
    
            // Perform the transfer
            balances[msg.sender] -= _amount;
            balances[_to] += _amount;
        }
    }
    

*   Синяя кнопка
    

![](https://storage.googleapis.com/papyrus_images/53c8265b7449b40dddfaf44485c79f0d2960c3a7b9af0baa9a29a03227ef1c08.png)

*   Делаем деплой и копируем адрес контракта
    

![](https://storage.googleapis.com/papyrus_images/817de21dc7b53152a98a5b561b968299675c2701cbc1e9e79243631741b7fecb.png)

*   Отправляем [**сюда**](https://docs.base.org/base-camp/docs/minimal-tokens/minimal-tokens-exercise/) и вставляем контракт — прожимаем **Sumbit**
    

![](https://storage.googleapis.com/papyrus_images/1cad41822aabe115d8591b567213acf4feea9c58e39b06cdda88d6349a8a1cae.png)

*   Должно быть **3 галочки (как на скрине)**
    

![](https://storage.googleapis.com/papyrus_images/1f9f2f276c7dbbb25871d2101bdbbd4f3f18b26fccc19c5ac480c121738b5986.png)

*   Создаем файл **ERC20**
    

![](https://storage.googleapis.com/papyrus_images/eeca04f016335c0d1fd394d01b9b29b2ceaa13a6135c52d39e810508988bc11d.png)

*   Копируем текст и вставляем в консольку
    

    // SPDX-License-Identifier: UNLICENSED
    pragma solidity ^0.8.17;
    
    // Importing OpenZeppelin contracts for ERC20 and EnumerableSet functionalities
    import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
    import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";// Contract for weighted voting using ERC20 token
    contract WeightedVoting is ERC20 {
        string private salt = "CHASE"; // A private string variable
        using EnumerableSet for EnumerableSet.AddressSet; // Importing EnumerableSet for address set functionality    // Custom errors
        error TokensClaimed(); // Error for attempting to claim tokens again
        error AllTokensClaimed(); // Error for attempting to claim tokens when all are already claimed
        error NoTokensHeld(); // Error for attempting to perform an action without holding tokens
        error QuorumTooHigh(); // Error for setting a quorum higher than total supply
        error AlreadyVoted(); // Error for attempting to vote more than once
        error VotingClosed(); // Error for attempting to vote on a closed issue    // Struct to represent an issue
        struct Issue {
            EnumerableSet.AddressSet voters; // Set of voters
            string issueDesc; // Description of the issue
            uint256 quorum; // Quorum required to close the issue
            uint256 totalVotes; // Total number of votes casted
            uint256 votesFor; // Total number of votes in favor
            uint256 votesAgainst; // Total number of votes against
            uint256 votesAbstain; // Total number of abstained votes
            bool passed; // Flag indicating if the issue passed
            bool closed; // Flag indicating if the issue is closed
        }    // Struct to represent a serialized issue
        struct SerializedIssue {
            address[] voters; // Array of voters
            string issueDesc; // Description of the issue
            uint256 quorum; // Quorum required to close the issue
            uint256 totalVotes; // Total number of votes casted
            uint256 votesFor; // Total number of votes in favor
            uint256 votesAgainst; // Total number of votes against
            uint256 votesAbstain; // Total number of abstained votes
            bool passed; // Flag indicating if the issue passed
            bool closed; // Flag indicating if the issue is closed
        }    // Enum to represent different vote options
        enum Vote {
            AGAINST,
            FOR,
            ABSTAIN
        }    // Array to store all issues
        Issue[] internal issues;    // Mapping to track if tokens are claimed by an address
        mapping(address => bool) public tokensClaimed;    uint256 public maxSupply = 1000000; // Maximum supply of tokens
        uint256 public claimAmount = 100; // Amount of tokens to be claimed    string saltt = "any"; // Another string variable    // Constructor to initialize ERC20 token with a name and symbol
        constructor(string memory _name, string memory _symbol)
            ERC20(_name, _symbol)
        {
            issues.push(); // Pushing an empty issue to start from index 1
        }    // Function to claim tokens
        function claim() public {
            // Check if all tokens have been claimed
            if (totalSupply() + claimAmount > maxSupply) {
                revert AllTokensClaimed();
            }
            // Check if the caller has already claimed tokens
            if (tokensClaimed[msg.sender]) {
                revert TokensClaimed();
            }
            // Mint tokens to the caller
            _mint(msg.sender, claimAmount);
            tokensClaimed[msg.sender] = true; // Mark tokens as claimed
        }    // Function to create a new voting issue
        function createIssue(string calldata _issueDesc, uint256 _quorum)
            external
            returns (uint256)
        {
            // Check if the caller holds any tokens
            if (balanceOf(msg.sender) == 0) {
                revert NoTokensHeld();
            }
            // Check if the specified quorum is higher than total supply
            if (_quorum > totalSupply()) {
                revert QuorumTooHigh();
            }
            // Create a new issue and return its index
            Issue storage _issue = issues.push();
            _issue.issueDesc = _issueDesc;
            _issue.quorum = _quorum;
            return issues.length - 1;
        }    // Function to get details of a voting issue
        function getIssue(uint256 _issueId)
            external
            view
            returns (SerializedIssue memory)
        {
            Issue storage _issue = issues[_issueId];
            return
                SerializedIssue({
                    voters: _issue.voters.values(),
                    issueDesc: _issue.issueDesc,
                    quorum: _issue.quorum,
                    totalVotes: _issue.totalVotes,
                    votesFor: _issue.votesFor,
                    votesAgainst: _issue.votesAgainst,
                    votesAbstain: _issue.votesAbstain,
                    passed: _issue.passed,
                    closed: _issue.closed
                });
        }    // Function to cast a vote on a voting issue
        function vote(uint256 _issueId, Vote _vote) public {
            Issue storage _issue = issues[_issueId];        // Check if the issue is closed
            if (_issue.closed) {
                revert VotingClosed();
            }
            // Check if the caller has already voted
            if (_issue.voters.contains(msg.sender)) {
                revert AlreadyVoted();
            }        uint256 nTokens = balanceOf(msg.sender);
            // Check if the caller holds any tokens
            if (nTokens == 0) {
                revert NoTokensHeld();
            }        // Update vote counts based on the vote option
            if (_vote == Vote.AGAINST) {
                _issue.votesAgainst += nTokens;
            } else if (_vote == Vote.FOR) {
                _issue.votesFor += nTokens;
            } else {
                _issue.votesAbstain += nTokens;
            }        // Add the caller to the list of voters and update total votes count
            _issue.voters.add(msg.sender);
            _issue.totalVotes += nTokens;        // Close the issue if quorum is reached and determine if it passed
            if (_issue.totalVotes >= _issue.quorum) {
                _issue.closed = true;
                if (_issue.votesFor > _issue.votesAgainst) {
                    _issue.passed = true;
                }
            }
        }
    }//CHASE
    

*   Синяя кнопка
    

![](https://storage.googleapis.com/papyrus_images/e8594d684f1168d757caa7fea9060c6b1f424df7056e94b0df1ce588ae2c65f5.png)

*   Делаем деплой, но для начала тыкаем на **стрелку** и вписываем **CHASE —** далее **transact**
    
*   Теперь **Deploy** и копируем адрес контракта
    

![](https://storage.googleapis.com/papyrus_images/d8187ee06b54111e4728c40b4f3eaf8ef206e982c46d3913bdc9e942f82262ed.png)

*   Отправляем [**сюда**](https://docs.base.org/base-camp/docs/erc-20-token/erc-20-exercise/) и вставляем контракт — прожимаем **Sumbit**
    

![](https://storage.googleapis.com/papyrus_images/7ea8b79ac02b40c0d473b3a59fa745f08cd6da26f5d4b11c2225f767519b99c3.png)

*   Должно быть **3 галочки (как на скрине)**
    

![](https://storage.googleapis.com/papyrus_images/ebf2bb017d47c202350d41cff0bba3998f8f767ca11a89e80f9b4ebb752ecfe1.png)

*   Создаем файл **ERC721**
    

![](https://storage.googleapis.com/papyrus_images/d12bb5ba60acf86dd08c8d47433e14c4076ef2906a4e02c11b370175f32992cd.png)

*   Копируем текст и вставляем в консольку
    

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    
    // Importing OpenZeppelin ERC721 contract
    import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/ERC721.sol";// Interface for interacting with a submission contract
    interface ISubmission {
        // Struct representing a haiku
        struct Haiku {
            address author; // Address of the haiku author
            string line1; // First line of the haiku
            string line2; // Second line of the haiku
            string line3; // Third line of the haiku
        }    // Function to mint a new haiku
        function mintHaiku(
            string memory _line1,
            string memory _line2,
            string memory _line3
        ) external;    // Function to get the total number of haikus
        function counter() external view returns (uint256);    // Function to share a haiku with another address
        function shareHaiku(uint256 _id, address _to) external;    // Function to get haikus shared with the caller
        function getMySharedHaikus() external view returns (Haiku[] memory);
    }// Contract for managing Haiku NFTs
    contract HaikuNFT is ERC721, ISubmission {
        Haiku[] public haikus; // Array to store haikus
        mapping(address => mapping(uint256 => bool)) public sharedHaikus; // Mapping to track shared haikus
        uint256 public haikuCounter; // Counter for total haikus minted    // Constructor to initialize the ERC721 contract
        constructor() ERC721("HaikuNFT", "HAIKU") {
            haikuCounter = 1; // Initialize haiku counter
        }    string salt = "value"; // A private string variable    // Function to get the total number of haikus
        function counter() external view override returns (uint256) {
            return haikuCounter;
        }    // Function to mint a new haiku
        function mintHaiku(
            string memory _line1,
            string memory _line2,
            string memory _line3
        ) external override {
            // Check if the haiku is unique
            string[3] memory haikusStrings = [_line1, _line2, _line3];
            for (uint256 li = 0; li < haikusStrings.length; li++) {
                string memory newLine = haikusStrings[li];
                for (uint256 i = 0; i < haikus.length; i++) {
                    Haiku memory existingHaiku = haikus[i];
                    string[3] memory existingHaikuStrings = [
                        existingHaiku.line1,
                        existingHaiku.line2,
                        existingHaiku.line3
                    ];
                    for (uint256 eHsi = 0; eHsi < 3; eHsi++) {
                        string memory existingHaikuString = existingHaikuStrings[
                            eHsi
                        ];
                        if (
                            keccak256(abi.encodePacked(existingHaikuString)) ==
                            keccak256(abi.encodePacked(newLine))
                        ) {
                            revert HaikuNotUnique();
                        }
                    }
                }
            }        // Mint the haiku NFT
            _safeMint(msg.sender, haikuCounter);
            haikus.push(Haiku(msg.sender, _line1, _line2, _line3));
            haikuCounter++;
        }    // Function to share a haiku with another address
        function shareHaiku(uint256 _id, address _to) external override {
            require(_id > 0 && _id <= haikuCounter, "Invalid haiku ID");        Haiku memory haikuToShare = haikus[_id - 1];
            require(haikuToShare.author == msg.sender, "NotYourHaiku");        sharedHaikus[_to][_id] = true;
        }    // Function to get haikus shared with the caller
        function getMySharedHaikus()
            external
            view
            override
            returns (Haiku[] memory)
        {
            uint256 sharedHaikuCount;
            for (uint256 i = 0; i < haikus.length; i++) {
                if (sharedHaikus[msg.sender][i + 1]) {
                    sharedHaikuCount++;
                }
            }        Haiku[] memory result = new HaikuUnsupported embed;
            uint256 currentIndex;
            for (uint256 i = 0; i < haikus.length; i++) {
                if (sharedHaikus[msg.sender][i + 1]) {
                    result[currentIndex] = haikus[i];
                    currentIndex++;
                }
            }        if (sharedHaikuCount == 0) {
                revert NoHaikusShared();
            }        return result;
        }    // Custom errors
        error HaikuNotUnique(); // Error for attempting to mint a non-unique haiku
        error NotYourHaiku(); // Error for attempting to share a haiku not owned by the caller
        error NoHaikusShared(); // Error for no haikus shared with the caller
    }//CHASE
    

*   Синяя кнопка
    

![](https://storage.googleapis.com/papyrus_images/6c338ebb18af4642543005e828bb727439a6e6758eba2e49692a8989400a6da6.png)

*   Делаем деплой и копируем адрес контракта
    

![](https://storage.googleapis.com/papyrus_images/d7e0013ba8133fd9d8281144dd32e08dbb2453be7b1fa2b88c2273914e28b58d.png)

*   Отправляем [**сюда**](https://docs.base.org/base-camp/docs/erc-721-token/erc-721-exercise/) и вставляем контракт — прожимаем **Sumbit**
    

![](https://storage.googleapis.com/papyrus_images/3884d7c6db401060710c029de8a9b67abfe535b11b2f8cb80e49146b3999013a.png)

*   Должно быть 2 **галочки (как на скрине)**
    

![](https://storage.googleapis.com/papyrus_images/ffca967aebc283622187ebad730c56bf0611841c287f33787e399a097508a2ca.png)

> _Молодцы! На этом мы закончили делать деплои_

*   Теперь вступаем в дискорд [**Base**](https://discord.com/invite/buildonbase) и переходим к [**Guild**](https://guild.xyz/base/base-camp) и забираем все роли
    

![](https://storage.googleapis.com/papyrus_images/05dbc961858f7e36e06a1095adb1b843a10f8c4f01c327ce079a6313f1ddd136.png)

*   Еще можно получить дополнительную роль, нужно будет привязать **Github**
    

![](https://storage.googleapis.com/papyrus_images/2521a0e4be00468a8cac5da0d889e21b51e7fac1e8d3909de660b569c5960ce9.png)

*   Также забираем немного **Score** в [**Talent Protocol**](https://passport.talentprotocol.com/wallet)
    

![](https://storage.googleapis.com/papyrus_images/567bf2b5f00bf46babe1d7bbee3ef04c9a9dbec9431e808ac5c972c33279c37f.png)

*   [**Телеграм канал с гайдами**](https://t.me/cryptoforto)
    
*   [**DeBank Profile**](https://debank.com/profile/0x05bb279648e4e4cbcdecf2d4d6ec310999d444e7?t=1696236908255&r=994)

---

*Originally published on [CryptoFortochka](https://paragraph.com/@sosew/base)*
