July 9

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

CryptoFortochka — гайды, ноды, новости, тестнеты

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

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

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

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

Что делать?

  • Переходим по ссылке и коннектим EVM кошелек
  • Добавиться сеть Base Sepolia — добавляем
  • Далее идём к крану и запрашиваем тестовые $ETH в сети Base Sepolia
  • Переходим к Remix и сбрасываем куки
  • Слева тыкаем значок двух папок — далее снизу на папку contracts — теперь тыкаем на 2_Owner.sol
  • Далее слева тыкаем на значок и прожимаем синюю кнопку
  • Далее тыкаем на значок Ethereum — сверху выбираем EVM кошелек (Metamask или Rabby) — Коннектим кошелек
  • Прожимаем кнопку Deploy
  • Но за ранее в EVM кошельке поставьте Base Sepolia
  • Подтверждаем транзакцию в сети Base Sepolia
Отлично! Теперь давайте сделаем еще один контракт
  • Тыкаем по значку папок — далее создаем файл — называем его BasicMath— тыкаем на него
  • Справа откроется консолька, вписываем туда вот это:
// 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
  • Далее тыкаем слева на значок и прожимаем синюю кнопку
  • Делаем Deploy
  • Подтверждаем транзакцию в EVM
  • После успешного развертывания контракта перейдите на левую боковую панель и прокрутите вниз, чтобы просмотреть код контракта BaseToken
  • Копируем адрес
  • Отлично! Вот должно получиться что то тип такого (как скрине)
Осталось осталось сделать 13 контрактов, и процесс будет аналогичным
  • Слева тыкаем значок двух папок — далее снизу на папку contracts — создаем файл ControlStructures — тыкаем на него
  • Вставляем этот текст в пустую консольку справа
// 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
  • Делаем все тоже самое, что и делали ранее
  • Приложу скрины
  • Копируем контракт
  • Отправляем сюда и вставляем контракт — прожимаем Sumbit
  • Должно быть 2 галочки (как на скрине)
  • Продолжаем! Создаем новый файл Storage
  • Копируем текст и вставляем в консольку
// 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
  • Далее синюю кнопку
  • Далее выбираем EVM — и вписываем данные снизу
  • shares - 1000
  • name - Pat
  • salary - 50000
  • idNumber - 112358132134
  • Копируем деплой
  • Отправляем сюда и вставляем контракт — прожимаем Sumbit
  • Должно быть 4 галочки (как на скрине)
  • Далее создаем файл 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 uint[](numbers.length);

        // 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 uint256[](counter);
        address[] memory sendersAfterY2K = new address[](counter);

        // 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;
    }
}
  • Тыкаем на синюю кнопку
  • Делаем деплой
  • Копируем контракт
  • Отправляем сюда и вставляем контракт — прожимаем Sumbit
  • Должно быть 2 галочки (как на скрине)
  • Создаем файл Mapping
  • Копируем текст и вставляем в консольку
// 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];
    }
}
  • Тыкаем на синюю кнопку
  • Делаем деплой
  • Копируем адрес контракта
  • Отправляем сюда и вставляем контракт — прожимаем Sumbit
  • Должно быть 2 галочки (как на скрине)
  • Создаем файл Structs
  • Копируем текст и вставляем в консольку
// 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];
    }
}
  • Тыкаем на синюю кнопку
  • Делаем деплой
  • Копируем адрес контракта
  • Отправляем сюда и вставляем контракт — прожимаем Sumbit
  • Должно быть 1 галочка (как на скрине)
  • Создаем файл Inheritance
  • Копируем текст и вставляем в консольку
// 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;
    }
}
  • Тыкаем на синюю кнопку
  • Далее делаем деплой, но в Contract выбираем Salesperson
  • Тыкаем на стрелочку и вписываем цифры — тыкаем на transact — подтверждаем транзакцию

Id Number: 55555 Manager id: 12345 Salary: 20

  • Далее снова выбираем Contract и тыкаем на EngineeringManager
  • Вписываем эти данные

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

  • Тыкаем на стрелочку и вписываем цифры — тыкаем на transact — подтверждаем транзакцию
  • Далее тыкаем на Contract выбираем InheritanceSubmission
  • Спускаемся вниз и копируем 1. Salesperon контракт адрес; 2. EngineeringManager контракт адрес и вписываем их выше (как на скрине)
  • Тыкаем transact и подтверждаем транзу
  • Копируем Inheritance контракт адрес
  • Отправляем сюда и вставляем контракт — прожимаем Sumbit
  • Должно быть 4 галочки (как на скрине)
  • Создаем новый файл SillyStringUtils
  • Копируем текст и вставляем в консольку
// 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" 🤷");
    }
}
  • Копируем и вставляем текст
  • Далее создаем файл Imports
  • Копируем текст и вставляем в консольку
// 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;
    }
}
  • Синяя кнопка
  • Делаем деплой и копируем адрес контракта
  • Отправляем сюда и вставляем контракт — прожимаем Sumbit
  • Должно быть 1 галочка (как на скрине)
  • Далее создаем файл Errors
  • Копируем текст и вставляем в консольку
// 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 uint[](3);

        // 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;
    }
}
  • Синяя кнопка
  • Делаем деплой и копируем адрес контракта
  • Отправляем сюда и вставляем контракт — прожимаем Sumbit
  • Должно быть 3 галочки (как на скрине)
  • Создаем файл AddressBook
  • Копируем текст и вставляем в консольку
// 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
  • Тыкаем на синюю кнопку
  • Делаем деплой и копируем адрес контракта
  • Отправляем сюда и вставляем контракт — прожимаем Sumbit
  • Должно быть 2 галочки (как на скрине)
  • Создаем файл Minimal Token
  • Копируем текст и вставляем в консольку
// 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;
    }
}
  • Синяя кнопка
  • Делаем деплой и копируем адрес контракта
  • Отправляем сюда и вставляем контракт — прожимаем Sumbit
  • Должно быть 3 галочки (как на скрине)
  • Создаем файл ERC20
  • Копируем текст и вставляем в консольку
// 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 = "gedt"; // 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
  • Синяя кнопка
  • Делаем деплой, но для начала тыкаем на стрелку и вписываем CHASE — далее transact
  • Теперь Deploy и копируем адрес контракта
  • Отправляем сюда и вставляем контракт — прожимаем Sumbit
  • Должно быть 3 галочки (как на скрине)
  • Создаем файл ERC721
  • Копируем текст и вставляем в консольку
// 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 Haiku[](sharedHaikuCount);
        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
  • Синяя кнопка
  • Делаем деплой и копируем адрес контракта
  • Отправляем сюда и вставляем контракт — прожимаем Sumbit
  • Должно быть 2 галочки (как на скрине)
Молодцы! На этом мы закончили делать деплои
  • Теперь вступаем в дискорд Base и переходим к Guild и забираем все роли
  • Еще можно получить дополнительную роль, нужно будет привязать Github