• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья Кодинг пакетных платежей на грани фантастики с помощью Solidity: метод, который необходимо знать

вавилонец

CPU register
Пользователь
Регистрация
17.06.2021
Сообщения
1 116
Реакции
1 265
1662963410033.png

ОРИГИНАЛЬНАЯ СТАТЬЯ
ПЕРЕВЕДЕНО СПЕЦИАЛЬНО ДЛЯ xss.pro плюс немного отсебятины для нашего развития
$10 на gas для Jolah Molivski ---> 0x5B1f2Ac9cF5616D9d7F1819d1519912e85eb5C09

Почему вы должны освоить пакетную обработку платежей в Solidity

Solidity — это специальный язык программирования для обработки платежей между учетными записями. Это редкая черта среди языков программирования в Интернете. Solidity была создана с целью управления транзакциями с цифровой валютой Ethereum, устраняя необходимость в посредниках и крупных корпорациях.
С программированием смарт-контрактов Solidity вам не нужен банк или какая-либо женщина из банка для обработки вашего платежа, все ваши платежи будут обрабатываться в сети. Но сам факт того, что Solidity дает вам возможность совершать цифровые транзакции быстрее, безопаснее и в больших масштабах, не означает, что вы можете делать это в совершенстве, не обучаясь.


Пример смарт-контракта пакетной оплаты

Я хочу проиллюстрировать это на примере созданного мною смарт-контракта под названием Payroll.

Код:
// SPDX-License-Identifier: MIT
pragma solidity >=0.7.0 <0.9.0;

//создали контракт Payroll в котором: адресс развертывания, толстый кошелек рабовладельцев, общее число рабов, выплата, общая з/п
contract Payroll {
    address public companyAcc;
    uint256 public companyBal;   // в целях безопасности его бы я сделал internal virtual - внутренний с возможностью переопледеления ниже по иерархии
    uint256 public totalWorkers = 0;
    uint256 public totalSalary = 0;
    uint256 public totalPayment = 0;

    mapping(address => bool) isWorker; // является ли адрес рабом



// создания событие "Дать_на_хлеб" - вклячает в себя, порядковый номер раба, адрес кассы выплаты зп, собственно зп, временная метка
    event Paid(
        uint256 id,
        address from,
        uint256 totalSalary,
        uint256 timestamp
    );


// СтруктураВыплат : идентификатор платежа, адрес кошеля раба, пособие на хлеб, время выдачи пособия на хлеб
    struct PaymentStruct {
        uint256 id;
        address worker;
        uint256 salary;
        uint256 timestamp;
    }


//СтректураВыплат объявляется массивом сотрудников
    PaymentStruct[] employees;


// модификатор принадлежности рабовладельцу возвращает тождество принадлежности
    modifier ownerOnly(){     // переменной состояния рабовладельцу, иначе
        require(msg.sender == companyAcc, "Owner reserved only");   // выпишет штрав в 100500 тыс рублей
        _;
    }

    constructor() {
        companyAcc = msg.sender;
    }
// функция поймать раба принимает местонахождения раба и его зп, может вызываться извне контракта рабовладельцем
    function addWorker(
        address worker,
        uint256 salary
    ) external ownerOnly returns (bool) {  // возвращает наличие или отсутствие нового раба
        require(salary > 0 ether, "Salary cannot be zero!");  // проверяет начисление ему зп
        require(!isWorker[worker], "Record already existing!"); // проверяет, не сбежавший ли это раб



        totalWorkers++;  // осуществляем инкрементарное добавление нового раба в книгу рабовладельца
        totalSalary += salary; // начисляем издержки в виде выплаты
        isWorker[worker] = true;

// в массив сотрудников добавляем "единицу СтруктурыВыплат" , содержащую и передающую все параметры
        employees.push(
            PaymentStruct(
                totalWorkers,
                worker,
                salary,
                block.timestamp
            )
        );
      
        return true;
    }

// функция выплаты зп, может быть вызвана только рабовладельцем, не может быть вызвана извнутри контракта
    function payWorkers() payable external ownerOnly returns (bool) {
        require(msg.value >= totalSalary, "Ethers too small");  // проверяет что денег у рабовладельца больше чем общая выплата
        require(totalSalary <= companyBal, "Insufficient balance"); // и на балансе компании тоже больше чем на зп надо

// итерацичный цикл обходящий длинну массива содрудников, при котором каждому сотруднику начисляется его зп
        for(uint i = 0; i < employees.length; i++) {
            payTo(employees[i].worker, employees[i].salary);
        }

        totalPayment++; // увеличение
        companyBal -= msg.value;


// вот и прищел праздник в семьи достопочтенных работяг - реализация события выдачи зп со всеми пологающимися документами
        emit Paid(
            totalPayment,
            companyAcc,
            totalSalary,
            block.timestamp
        );

        return true;
    }


// функция пополнения казны рабовладельцев, осуществляет возможность принятия платежей от сторонних лиц
    function fundCompanyAcc() payable external returns (bool) {
        require(companyAcc != msg.sender, "You can't fund yourself!");
        payTo(companyAcc, msg.value);
        companyBal += msg.value;
        return true;
    }

// создает список работников, ничего не меняет в контракте, выгружает данные из СтруктурыВыплат в memory - "оперативная паять блокчейна"
    function getWorkers() external view returns (PaymentStruct[] memory) {
        return employees; // возвращяет массив сотрудников
    }


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

    function payTo(address to, uint256 amount) internal returns (bool) {

        (bool success,) = payable(to).call{value: amount}("");  // платежный вызов call на адрес to  в колличестве amount
        require(success, "Payment failed"); // ghjdthrf jib,rb dthytn "успешно" или "Платеж провален"
        return true;
    }
}

Атеншон плииииз


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

Проверить данные Убедитесь, что вы проверили правильность данных перед обработкой платежей. Использование необходимых функций и специальных модификаторов, таких как ownerOnly, для обеспечения ввода в систему только точных записей.

Обработать платеж Прежде чем изменять переменные состояния, убедитесь, что вы взимаете плату со счета. Это поможет защититься от повторных атак.

Перекалибровать запись Обновляйте переменные состояния только после выполнения вышеуказанных действий. Например, если злоумышленник намеревается атаковать вашу платежную функцию, отправив несколько запросов одновременно. Он будет вынужден заплатить дважды, и при каждом запросе оплата должна производиться до того, как будут обновлены переменные состояния.
Хоть автор и должен был ручаться что предоставляет для изучения безопасный смарт-контракт, но мы же любим знания и опыт, иначе нахрен мы тут все сегодня собрались.
Открываем любимый терминал ( используем ZIION виртуальную машину, она основана на Ubuntu так что тут все просто) и выполняем:
Код:
-->  slither rab.sol

Payroll.payTo(address,uint256) (rab.sol#116-121) has external calls inside a loop: (success) = address(to).call{value: amount}() (rab.sol#118)


Reentrancy in Payroll.fundCompanyAcc() (rab.sol#101-106):
    External calls:
    - payTo(companyAcc,msg.value) (rab.sol#103)
        - (success) = address(to).call{value: amount}() (rab.sol#118)
    State variables written after the call(s):
    - companyBal += msg.value (rab.sol#104)


Pragma version>=0.7.0<0.9.0 (rab.sol#2) is too complex
solc-0.8.14 is not recommended for deployment


Low level call in Payroll.payTo(address,uint256) (rab.sol#116-121):
    - (success) = address(to).call{value: amount}() (rab.sol#118)

rab.sol analyzed (1 contracts with 78 detectors), 5 result(s) found

Что по нашему:

Код:
Payroll.payTo(address,uint256) (rab.sol#116-121) имеет внешние вызовы внутри цикла: (success) = address(to).call{value: amount}() (rab.sol#118)


Повторный вход в Payroll.fundCompanyAcc() (rab.sol#101-106):
    Внешние вызовы:
    - payTo(companyAcc,msg.value) (rab.sol#103)
        - (success) = address(to).call{value: amount}() (rab.sol#118)
    Переменные состояния, записанные после вызова(ов):
    - companyBal += msg.value (rab.sol#104)


Pragma version>=0.7.0<0.9.0 (rab.sol#2) 
solc-0.8.14 не рекомендуется для развертывания


Низкоуровневый вызов в Payroll.payTo(address,uint256) (rab.sol#116-121):
    - (success) = address(to).call{value: amount}() (rab.sol#118)

rab.sol проанализировал (1 контракт с 78 детекторами), найдено 5 результатов



Будем аккуратнее используя смарт-контракты, читать их лично перед финансовой сделкой- ОБЯЗАТЕЛЬНО!!!!!
 
Последнее редактирование:
Так слизер же реентраси нашел?
а я о чем и говорил, этот код с сайта, я его затестил он компильнулся думаю дай я его в слиз засуну - видишь результат, там еще есть ошибки. Почему и написал последнее предложение
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх