問題一覧に戻る
上級セキュリティパターン
問題78: プルペイメント
Solidityのプルペイメントパターンを学習 - 安全な資金配布に不可欠。プッシュペイメント(ループ内でETH送金)は、受信者がrevertするコントラクトの場合失敗し、全転送をブロックします。プルペイメントは残高を記録し、ユーザーが個別に引き出すことで解決。このパターンはDoS攻撃を防ぎ、送信者のガスコストを削減し、受信者に制御を与えます。エアドロップ、収益分配、複数受信者への支払いシステムに重要。プルvsプッシュペイメントの理解は堅牢なDeFiプロトコル構築の基本です。
pragma solidity ^0.8.0;
contract PullPayment {
mapping(address => uint256) public payments;
// 危険:ループ内プッシュペイメント
function badPayment(address[] memory recipients) public payable {
uint256 amount = msg.value / recipients.length;
for (uint i = 0; i < recipients.length; i++) {
// 失敗して全てブロック可能
payable(recipients[i]).(amount);
}
}
// 安全:プルペイメントパターン
function goodPayment(address[] memory recipients) public payable {
uint256 amount = msg.value / recipients.length;
for (uint i = 0; i < recipients.length; i++) {
// 引き出し用の残高を記録
payments[recipients[i]] amount;
}
}
// ユーザー主導の引き出し
function withdraw() public {
uint256 payment = payments[];
require(payment > 0, "No payment");
payments[msg.sender] = ;
(bool success, ) = payable(msg.sender).call{value: payment}("");
require(success, "Transfer failed");
}
}