Существует ли минимальная сумма транзакции?
Намек: Вы предотвращаете «пылевые» транзакции (крошечные, незначительные суммы), которые забивают ваш контракт и делают все неиспользуемым?
Здесь речь идет о предотвращении спама, просто и понятно. Если ваш контракт позволяет пользователям взаимодействовать с ним на любую сумму (даже на крошечные, незначительные доли токенов), злоумышленники могут затопить его бесчисленными транзакциями с нулевой или почти нулевой стоимостью. Все эти транзакции потребляют газ и делают законные операции гораздо более дорогостоящими. Это увеличение затрат может потенциально достичь предела лимита газа в блоке. Если это произойдет, нормальные пользователи не смогут взаимодействовать с вашим протоколом. Вот как выглядит уязвимый код:
// Vulnerable to dust attacks
struct WithdrawalRequest {
address user;
uint amount;
}
WithdrawalRequest[] public withdrawalRequests;
// Anyone can submit withdrawal requests for ANY amount (even 1 wei!)
function requestWithdrawal(uint amount) external {
require(balances[msg.sender] >= amount, "Insufficient balance");
balances[msg.sender] -= amount;
// Add to the global withdrawal queue - no minimum amount check!
withdrawalRequests.push(WithdrawalRequest(msg.sender, amount));
}
function processWithdrawals() external onlyOwner {
for (uint256 i = 0; i < withdrawalRequests.length; i++) { // This amplifies the attack even more because it tries to handle all the requests at once
WithdrawalRequest memory request = withdrawalRequests[i];
request.user.transfer(request.amount);
}
withdrawalRequests = new WithdrawalRequest[](0);
}
Решение: ввести минимальное требование!
Простой оператор require может значительно улучшить ситуацию. Введите пороговое значение с помощью оператора require и действуйте как охранник, проверяющий удостоверение личности на входе в клуб. Нам также необходимо обеспечить возможность обработки запросов на снятие средств пакетами. Вот как это сделать:
uint public minimumWithdrawal = 0.1 ether;
function requestWithdrawal(uint amount) external {
require(balances[msg.sender] >= amount, "Insufficient balance");
require(amount >= minimumWithdrawal, "Amount below minimum withdrawal threshold"); // Bouncer!
balances[msg.sender] -= amount;
withdrawalRequests.push(WithdrawalRequest(msg.sender, amount));
}
function processWithdrawals(uint count) external onlyOwner { // We can process in batches now
for (uint256 i = 0; i < count; i++) {
WithdrawalRequest memory request = withdrawalRequests[i];
request.user.transfer(request.amount);
}
for (uint i = 0; i < withdrawalRequests.length - count; i++) {
withdrawalRequests[i] = withdrawalRequests[i + count];
}
withdrawalRequests.length = withdrawalRequests.length - count;
}
В примере чеклиста показан контракт, в котором пользователи могут запрашивать вывод буквально любой суммы (даже нулевой), независимо от ее размера. Злоумышленник может воспользоваться этим, чтобы создать огромную очередь запросов на вывод с нулевой стоимостью. Это делает обработку законных запросов на вывод чрезмерно дорогой, что обходится пользователям в огромные расходы на газ. Минимальный пример и PoC, написанные в Foundry, доступны здесь.
#foundry #dos