
WTF Solidity 第33講AirdropコントラクトでERC20トークンを一括エアドロップする【免费下载链接】WTF-SolidityWTF Solidity 极简入门教程供小白们使用。Now supports English! 官网: https://wtf.academy项目地址: https://gitcode.com/GitHub_Trending/wt/WTF-Solidityエアドロップ空投は仮想通貨プロジェクトの代表的なマーケティング戦略であり、プロジェクトチームが特定のユーザー群体へ無料でトークンを配布する仕組みです。本記事では、WTF-Solidity の第33講に基づき、Solidity でAirdropスマートコントラクトを実装し、1 回のトランザクションで複数アドレスへERC20トークンおよびETHを一括送信する方法を解説します。ソースコードの内部ロジック、approveによる承認フロー、Remix での実践手順まで、実際に動かせる知識を身につけられます。エアドロップとはエアドロップとは、プロジェクトチームが特定のユーザー群体に対してトークンを無料で配布するマーケティング手法です。ユーザーはエアドロップの資格を得るために、製品のテスト、ニュースの共有、友人紹介などの簡単なタスクを完了するのが一般的です。プロジェクトチームにとってはシードユーザーの獲得、ユーザーにとってはトークン価値の獲得という、双方に利益がある仕組みです。受取ユーザーは数百人・数千人規模に及ぶこともあるため、プロジェクトチームがアドレスごとに送金トランザクションを発行することは現実的ではありません。そこでスマートコントラクトを利用し、1 回のトランザクションで複数アドレスへ一括転送することで、エアドロップの効率を大幅に向上させることができます。本講で扱うAirdropコントラクトはまさにこの「一括転送」を実現するためのものです。Airdropコントラクトの全体像Airdropコントラクトのロジックは非常にシンプルです。ループを使用して、1 回の取引で複数のアドレスにERC20トークンを送信します。完全なソースコードは Languages/ja/33_Airdrop_ja/Airdrop.sol にあります中国語版は 33_Airdrop/Airdrop.sol。// SPDX-License-Identifier: MIT // By 0xAA pragma solidity ^0.8.34; import ./IERC20.sol; //import IERC20 /// notice 複数のアドレスに対してトークンをエアドロするコントラクト contract Airdrop { mapping(address uint256) failTransferList; // ... 以下に関数を実装 }このコントラクトは次の要素から構成されます。要素役割getSum()uint配列の合計を返す補助関数multiTransferToken()ERC20トークンのエアドロップを一括送信multiTransferETH()ETHのエアドロップを一括送信failTransferListETH送金に失敗したアドレスと金額を記録するマッピングwithdrawFromFailList()送金失敗者に払い戻しの機会を提供また、同じファイル内にはエアドロップ対象となる独自実装のERC20トークンコントラクトも同梱されており、実践手順でそのまま利用できます。getSum()関数空投総量の計算エアドロップの総量を計算するため、Airdropコントラクトはuint配列の合計を返す補助関数getSum()を持ちますLanguages/ja/33_Airdrop_ja/Airdrop.sol#L58-L63。// 配列の合計を計算する関数 function getSum(uint256[] calldata _arr) public pure returns (uint256 sum) { for (uint256 i 0; i _arr.length; i) { sum sum _arr[i]; } }ポイントは以下の通りです。calldataキーワードで外部引数の配列を読み取り専用として受け取り、ガスコストを削減します。pure指定のため、状態変数の読み書きを行わず、ブロックチェーンの状態を変更しません。戻り値は名前付き戻り値sumとして宣言されているため、関数末尾のreturn文を省略できます。multiTransferToken()関数ERC20トークンの一括エアドロップmultiTransferToken()はERC20トークンのエアドロップを送信するコア関数ですLanguages/ja/33_Airdrop_ja/Airdrop.sol#L16-L28。3 つのパラメータを受け取ります。パラメータ型説明_tokenaddress送信対象のERC20トークンコントラクトのアドレス_addressesaddress[]エアドロップを受け取るユーザーアドレスの配列_amountsuint256[]エアドロップ量の配列。_addressesの各アドレスに対応する数量/// notice 複数のアドレスに対してERC20トークンをエアドロする。使用前に承認が必要 /// /// param _token エアドロップするERC20トークンのアドレス /// param _addresses エアドロップするアドレスの配列 /// param _amounts トークンの数量の配列各アドレスにエアドロップするトークンの数量 function multiTransferToken(address _token, address[] calldata _addresses, uint256[] calldata _amounts) external { // チェック_addressesと_amounts配列の長さが等しいこと require(_addresses.length _amounts.length, Lengths of Addresses and Amounts NOT EQUAL); IERC20 token IERC20(_token); // IERC20コントラクトインスタンスを宣言 uint256 _amountSum getSum(_amounts); // エアドロップするトークンの総量を計算 // チェック承認されたトークン数 エアドロップするトークンの総量 require(token.allowance(msg.sender, address(this)) _amountSum, Need Approve ERC20 token); // forループを使用し、transferFrom関数でエアドロップを送信 for (uint256 i; i _addresses.length; i) { token.transferFrom(msg.sender, _addresses[i], _amounts[i]); } }この関数には 2 つの重要なチェックrequireがあります。配列長の一致チェック_addressesと_amountsの 2 つの配列の長さが等しいことを検証します。等しくない場合、アドレスと金額の対応関係が崩れ、誤送金や金額不足が発生するため、最初に必ず検証します。承認額チェックエアドロップコントラクトへの承認額allowanceが、エアドロップするトークン総量getSum()の結果より大きいことを検証します。承認が不足している場合はNeed Approve ERC20 tokenでリバートします。チェックを通過すると、forループでIERC20インターフェースのtransferFrom()を呼び出し、msg.senderエアドロップの主催者の残高から各受取アドレスへトークンを送信します。IERC20インターフェースの役割multiTransferToken()はトークンの実装に依存せず、Languages/ja/33_Airdrop_ja/IERC20.sol に定義された標準インターフェースIERC20を通じてトークンを操作します。インターフェースにはtotalSupply()、balanceOf()、transfer()、allowance()、approve()、transferFrom()が宣言されており、エアドロップで実際に使うのは主に次の 2 つです。allowance(owner, spender)ownerがspenderに対して承認した残高を返しますview関数。transferFrom(from, to, amount)承認メカニズムを通じてfromからtoへamountを転送し、転送分は呼び出し元のallowanceから差し引かれます。IERC20インターフェースを介することで、Airdropコントラクトは特定のトークン実装に結合せず、インターフェースを満たす任意のERC20トークンをエアドロップできます。本講に同梱されている Languages/ja/33_Airdrop_ja/Airdrop.sol#L67-L120 のERC20コントラクトはこのインターフェースを実装しており、allowance[sender][msg.sender] - amountの形でtransferFromの度に承認残高を減算する標準的なロジックを持ちます。エアドロップ前に主催者がapprove()で承認しておく必要があるのは、この仕組みのためです。multiTransferETH()関数ETHの一括エアドロップERC20に加えて、AirdropコントラクトはETHの一括エアドロップにも対応していますLanguages/ja/33_Airdrop_ja/Airdrop.sol#L31-L47。パラメータは 2 つです。パラメータ型説明_addressesaddress payable[]エアドロップを受け取るユーザーアドレスの配列_amountsuint256[]エアドロップ量の配列。_addressesの各アドレスに対応する数量/// 複数のアドレスにETHを送金する function multiTransferETH(address payable[] calldata _addresses, uint256[] calldata _amounts) public payable { // チェック_addressesと_amounts配列の長さが等しいこと require(_addresses.length _amounts.length, Lengths of Addresses and Amounts NOT EQUAL); uint256 _amountSum getSum(_amounts); // エアドロップするETHの総量を計算 // 送金されたETHがエアドロップの総量と等しいことをチェック require(msg.value _amountSum, Transfer amount error); // forループを使用し、call関数でETHを送信 for (uint256 i 0; i _addresses.length; i) { // コメントアウトされたコードにはDoS攻撃のリスクがあり、transferも推奨されない書き方です // DoS攻撃については WTF-Solidity の S09_DoS 講を参照 // _addresses[i].transfer(_amounts[i]); (bool success,) _addresses[i].call{value: _amounts[i]}(); if (!success) { failTransferList[_addresses[i]] _amounts[i]; } } }ETH版の特徴は次の通りです。payable修飾子により、関数はトランザクションとともにETHを受け取ります。送金総額の一致チェックrequire(msg.value _amountSum)で、トランザクションで送金されたETHがエアドロップ総量getSum()の結果と正確に一致することを検証します。過不足があればリバートします。callによる送金_addresses[i].call{value: _amounts[i]}()で各アドレスへETHを送信します。コメントアウトされたtransfer()は非推奨の送金方法です。なぜtransferではなくcallを使うのかDoS攻撃への対策コード内でコメントアウトされている_addresses[i].transfer(_amounts[i])は、かつて一般的だったETH送金方法ですが、現在は推奨されません。理由は次の 2 点です。DoS 攻撃のリスクtransfer()は 2300 gas しか受け取り先へ渡せず、受け取り先がコントラクトの場合、この gas 不足で送金が常に失敗します。1 つでも失敗するとtransfer()は例外を投げてトランザクション全体がリバートするため、悪意のあるあるいは偶発的なコントラクトアドレスが 1 つ含まれるだけで、エアドロップ全体が実行不可能になります。これは DoS 攻撃の典型例であり、WTF-Solidity では S09_DoS/readme.md として別講で詳しく解説されています。ガス上限の固定transfer()は送金先に渡す gas が 2300 に固定されており、ERC20の受信処理などを含むコントラクトではガス不足で失敗しやすくなります。そこで本コントラクトは低レベルcallを採用し、失敗した場合は例外を投げずにsuccessフラグを受け取って処理を継続します。failTransferListとwithdrawFromFailListcallによる送金が失敗した場合、そのアドレスと金額はfailTransferListマッピングに記録されます。if (!success) { failTransferList[_addresses[i]] _amounts[i]; }これは「失敗を無視してループを継続する」ための記録であり、あわせて Languages/ja/33_Airdrop_ja/Airdrop.sol#L50-L56 のwithdrawFromFailList()が失敗者への払い戻し機会を提供します。// エアドロップ失敗に対して能動的な操作の機会を提供 function withdrawFromFailList(address _to) public { uint256 failAmount failTransferList[msg.sender]; require(failAmount 0, You are not in failed list); failTransferList[msg.sender] 0; (bool success,) _to.call{value: failAmount}(); require(success, Fail withdraw); }この関数により、送金に失敗したアドレスの保有者が自らETHを取り戻せます。failTransferList[msg.sender]が 0 の場合はYou are not in failed listでリバートし、払い戻し後は記録を 0 にリセットして二重払い戻しを防ぎます。エアドロップの実践Remixで一括送信を試すここからは Remix IDEJavaScript VM 環境で実際にエアドロップを実行する手順を解説します。日本語版のチュートリアルLanguages/ja/33_Airdrop_ja/readme.mdおよび中文版33_Airdrop/readme.mdの手順に沿っています。ステップ1ERC20トークンコントラクトをデプロイし、10000トークンをmintまず Languages/ja/33_Airdrop_ja/Airdrop.sol を Remix で開き、ファイル末尾に定義されているERC20コントラクトを選択してデプロイします。コンストラクタに代幣名とシンボル例WTF/WTFを渡します。デプロイ後、ERC20コントラクトのmint関数を呼び出し、自分デプロイアドレスに 10000 単位のトークンをミントします。mintは0アドレスから呼び出し元へトークンを発行し、totalSupplyを増加させます。ステップ2Airdropエアドロップコントラクトをデプロイ次にAirdropコントラクトをデプロイします。コンストラクタ引数は不要で、そのままtransactでデプロイできます。ステップ3ERC20のapprove()でAirdropコントラクトを承認ERC20トークンコントラクトのapprove()関数を呼び出し、Airdropエアドロップコントラクトに対して 10000 単位のトークンを承認します。ここで指定するspenderはAirdropコントラクトのアドレスです。spender : Airdropコントラクトのアドレス amount : 10000この承認がmultiTransferToken()の 2 つ目のrequire承認額 ≥ 空投総量を満たすための前提となります。ステップ4multiTransferToken()を実行してエアドロップAirdropコントラクトのmultiTransferToken()関数を実行します。_tokenにはERC20トークンコントラクトのアドレスを、_addressesと_amountsには以下のように配列を入力します中文版チュートリアル記載のテスト用アドレス例。// _addresses に入力 [0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2, 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4] // _amounts に入力 [100, 200]トランザクション実行後、ログにTransferイベントが 2 件記録され、それぞれfrom主催者、to受取アドレス、value送金額 100 / 200が確認できます。ステップ5balanceOf()でエアドロップ結果を確認ERC20トークンコントラクトのbalanceOf()関数を使用して、エアドロップ先アドレスのトークン残高を確認します。上の例では 2 つのアドレスの残高がそれぞれ100と200に増加していれば、エアドロップ成功です。まとめ本講では、Solidityを使ってERC20トークンのエアドロップを送信する方法を学びました。AirdropコントラクトはforループとIERC20.transferFrom()を組み合わせ、1 回のトランザクションで複数アドレスへERC20トークンを一括送信します。配列長の一致チェックと承認額チェックという 2 つのrequireにより、誤送金と承認不足を事前に防ぎます。ETHエアドロップではcallを使用し、送金失敗をfailTransferListに記録した上でwithdrawFromFailList()による払い戻し機会を提供します。transfer()は DoS 攻撃のリスクがあるため推奨されません。実際の運用では、主催者は事前にapprove()でエアドロップコントラストへの承認を行う必要があり、承認額はエアドロップ総量以上でなければなりません。これにより、個別送金に比べてエアドロップの効率を大幅に向上させることができます。実際のエアドロップでは、この基本形に加えてマークルツリーによるオフチェーン白名单検証36_MerkleTree、署名による権限確認37_Signatureなどを組み合わせることで、より安全でスケーラブルな運用が可能になります。【免费下载链接】WTF-SolidityWTF Solidity 极简入门教程供小白们使用。Now supports English! 官网: https://wtf.academy项目地址: https://gitcode.com/GitHub_Trending/wt/WTF-Solidity创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考