読了時間:14分
概要
これまで最も普及しているトークン規格はERC-20でした(それには十分な理由があります)。しかし、開発者たちは常に革新的な新たな方法を模索しています。ERC-777の策定者たちは、ERC-20との下位互換性を保ちつつ、「オペレーター」を導入する新しいトークン規格を提案しました。これにより、承認されたアドレスが保有者に代わってトークンを管理できるようになり、トークン転送時に送受信フックが実装されます。
このガイドでは、ERC-777の実装について、中核となる概念を含めて詳しく解説し、その後、Foundryを使用してERC-777コントラクトを自分で作成、デプロイ、テストする方法を学びます。Foundryについてまだご存じない方は、こちらのガイド「Foundry入門」をご覧ください。
さあ、始めましょう!
視覚的な解説をご希望ですか?サヒルと一緒に、ERC-777トークンの作成とデプロイ方法を学び、ERC-777トークン規格のユニークな機能を詳しく見ていきましょう。
必要なもの
- イーサリアムとスマートコントラクトについて中級レベルの理解があること
- Quicknodeアカウント(こちらから作成してください)
- セポリア・ネットワーク上にETHが保管されているイーサリアムウォレット(Quicknodeのファウセットを使ってテスト用のETHを入手できます)
- Node.jsがインストールされました
- Foundryがインストールされました
主な業務内容
- ERC-777トークン規格について理解する
- Foundry を使った開発環境のセットアップ
- ERC-777スマートコントラクトの作成とデプロイ
- スマートコントラクトをローカル環境でテストする
- スマートコントラクトをイーサリアム・セポリア・テストネットにデプロイする
| 依存関係 | バージョン |
|---|---|
| ノード | 20.17 |
| 鋳造所 | 0.8.10 |
ERC-777とは何ですか?
ERC-777は、ERC-20を基盤とした高度なトークン規格です。その主な特徴は以下の通りです:
- フック:トークンの送信者および受信者が、トークンの送信または受信の前にカスタムロジックを実行できるようにします。
- オペレーター:保有者に代わってトークンを管理できる、承認済みのアドレス。
- ERC-1820 レジストリ:特定のインターフェースの実装者を登録・検索するために使用されます。
- UXの向上: を使用します
送信関数の代わりに転送、これにより、別途用意する必要がなくなる可能性がある承認するそしてtransferFrom呼び出し。 - 下位互換性:ERC-20の機能およびイベントとの互換性を維持しています。
ERC-777のフック機能を実装するには:
- ERC-1820レジストリにスマートコントラクトのアドレスを登録してください。すべてのチェーンにおけるレジストリのアドレスは次のとおりです:
0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24 - 次の機能を実装する
ERC777トークン送信者そしてERC777トークン受取人登録済み契約内のインターフェース。
これらのフックを使用することで、不要なトークンの拒否や、複雑な転送ロジックの実装といった機能を実現できます。
ERC-777は高度な機能を提供する一方で、特に再入攻撃に関連する潜在的なセキュリティリスクも伴う点に留意することが重要です(詳細はこちら)。主要なスマートコントラクトライブラリであるOpenZeppelinは、こうした懸念からERC-777のサポートを非推奨としています。開発者は、ERC-777トークンを実装する際には細心の注意を払う必要があります。
フック
フックを使用すると、トークンの送受信前に独自のロジックを実行することができ、具体的には以下の通りです:
- 実装の検索にはERC-1820レジストリを使用してください
- 送信者フック:
送信するトークン数トークンの移動前に呼び出される関数 - 受信側フック:
受信したトークン数トークンの移動後に呼び出される関数 - 不要な送金を拒否し、取引を元に戻すことができます
- 転送時に追加データを受信する
オペレーター
オペレーターとは、保有者に代わってトークンを管理する権限を与えられたアドレスであり、以下の特徴があります:
- トークン保有者は、オペレーターを承認または承認を取り消すことができます
- トークンには、作成時にデフォルトの演算子を定義することができます
- オペレーターは以下を使用します
operatorSendそしてoperatorBurn関数 - 以下の方法を使えば、誰でもその住所が事業者かどうかを確認できます。
isOperatorFor
次のセクションでは、ERC-777を実際に作成、テスト、デプロイすることで、その仕組みについてさらに深く掘り下げていきます。
プロジェクトの設定
ターミナルを開き、以下のコマンドを実行して新しいプロジェクトを作成します:
mkdir erc777-token
cd erc777-token
forge init
次に、OpenZeppelin ライブラリをインストールします:
forge install OpenZeppelin/openzeppelin-contracts@v4.9.6
次に、以下のファイルを作成してマッピングを設定します。 remappings.txt プロジェクトのルートディレクトリにファイルを作成し(これにより、プロジェクトの推論されたリマッピングが自動的に取得されます)、以下の行を追加してください:
@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/
次に、本番環境のテストネットにデプロイできるよう、Quicknode上でエンドポイントを作成する手順を順を追って説明します。
Quicknode RPC エンドポイントを作成する
イーサリアムネットワークとやり取りし、このガイドで説明するスマートコントラクトをデプロイするには、RPCエンドポイントが必要です。Quicknodeを使用してRPCエンドポイントを作成するには、以下の手順に従ってください:
- Quicknodeでアカウントを作成する
- Ethereum Sepoliaの新しいエンドポイントを作成する
- 次の手順のために、HTTPプロバイダーのURLを手元に用意しておいてください
このプロジェクトでRPCエンドポイントを設定する方法の一つは、それを foundry.toml ファイルですが、このコードをオープンソース化する予定がある場合は、このコードをファイルから除外することをお勧めします。代わりに、RPCエンドポイントと(スマートコントラクトのデプロイに使用する)秘密鍵を指定するための環境変数を作成しましょう。これらはコマンドラインウィンドウから設定します:
export RPC_URL=<Your RPC endpoint>
export PRIVATE_KEY=<Your wallets private key>
Quicknodeのファウセットでウォレットに資金を入金する
ERC-777コントラクトをSepoliaテストネットにデプロイするには、ガス代を支払うためのSepoliaテストネットのETHが必要です。Multi-Chain Quicknode Faucetを使えば、テスト用ETHを簡単に手に入れることができます!
Multi-Chain Quicknode Faucet にアクセスし、ウォレット(MetaMask、Coinbase Wallet など)を接続するか、ウォレットアドレスを貼り付けてテスト用 ETH を受け取ってください。なお、EVM ファウセットを利用するには、イーサリアムメインネット上に 0.001 ETH の残高がある必要があります。また、ツイートしたり、Quicknode アカウントでログインしたりすることで、ボーナスとしてテストネットトークンを獲得することもできます!
ERC-777 コントラクトを作成する
新しいファイルを作成する src/TestERC777.sol そして、以下のコードを追加してください:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "@openzeppelin/contracts/token/ERC777/ERC777.sol";
contract TestERC777 is ERC777 {
constructor(string memory name, string memory symbol, address[] memory defaultOperators)
ERC777(name, symbol, defaultOperators)
{}
function mint(address account, uint256 amount, bytes memory userData, bytes memory operatorData) public {
_mint(account, amount, userData, operatorData);
}
}
本契約は、OpenZeppelinが提供するERC-777の実装を基にしています。トークン名を「Gold」、シンボルを「GLD」に設定し、指定されたアドレスにトークンを発行するためのミント関数が含まれています。また、 defaultOperators 契約のデプロイ時に設定したい演算子を渡すために使用する引数です。
ERC-777の受信者コントラクトを作成する
次に、ERC-777が持つフック機能を紹介します。そのために、別のコントラクトを作成します src/TestERC777Recipient.sol, ここにはトークンを受信した際の処理ロジックが記述されます。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "@openzeppelin/contracts/token/ERC777/IERC777Recipient.sol";
import "@openzeppelin/contracts/utils/introspection/IERC1820Registry.sol";
contract TestERC777Recipient is IERC777Recipient {
IERC1820Registry private constant _ERC1820_REGISTRY = IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24);
bytes32 private constant _TOKENS_RECIPIENT_INTERFACE_HASH = keccak256("ERC777TokensRecipient");
uint256 public receivedTokens;
uint256 public lastReceivedAmount;
address public lastOperator;
address public lastSender;
event TokensReceived(
address operator,
address from,
address to,
uint256 amount,
bytes userData,
bytes operatorData
);
constructor() {
_ERC1820_REGISTRY.setInterfaceImplementer(address(this), _TOKENS_RECIPIENT_INTERFACE_HASH, address(this));
}
function tokensReceived(
address operator,
address from,
address to,
uint256 amount,
bytes calldata userData,
bytes calldata operatorData
) external override {
receivedTokens += amount;
lastReceivedAmount = amount;
lastOperator = operator;
lastSender = from;
emit TokensReceived(operator, from, to, amount, userData, operatorData);
}
function getReceivedTokens() public view returns (uint256) {
return receivedTokens;
}
function getLastReceivedInfo() public view returns (uint256, address, address) {
return (lastReceivedAmount, lastOperator, lastSender);
}
}
上記の契約内容を振り返ってみましょう。これは IERC777受領者 ERC777トークンの受信転送を処理するためのインターフェースです。このインターフェースは、ERC1820レジストリに登録され、ERC777トークンの受信者として認識されます。このコントラクトは、受信したトークンの総量に加え、直近の転送の詳細も追跡します(金額, 演算子、および 送信者). トークンを受信すると、 受信したトークン数 この関数は、コントラクトの状態を更新し、送金詳細を含むイベントを発行します。さらに、2つのパブリック関数、 getReceivedTokens そして getLastReceivedInfo、受信したトークンや直近の送金に関する外部からの照会を許可する。
なお、 受信したトークン数 function は、このコントラクトが ERC-777 トークンを受け取るたびに呼び出される実際のフックです。これは(トークンを受け取った場合)、コントラクトの状態を更新し、イベントを発行します。
それでは、ファイルを保存して、テストネットにデプロイする前に、すべてが想定通りに動作しているかを確認するためのテストを作成していきましょう。
ERC-777の機能テスト
テストファイルを作成する test/TestERC777.t.sol そして、次のコードを入力してください:
1. コントラクトの初期化
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "forge-std/Test.sol";
import "@openzeppelin/contracts/token/ERC777/ERC777.sol";
import "@openzeppelin/contracts/utils/introspection/IERC1820Registry.sol";
import "../src/TestERC777Recipient.sol";
import "../src/TestERC777.sol";
contract ERC777SetupTest is Test {
TestERC777 public token;
TestERC777Recipient public recipient;
IERC1820Registry public erc1820Registry;
address public deployer;
address public user1;
address public user2;
bytes32 private constant _TOKENS_RECIPIENT_INTERFACE_HASH = keccak256("ERC777TokensRecipient");
}
上記では、次のような必要なファイルをインポートしています。 TestERC777 契約および テスト Foundryでのテストに必要なコントラクト。次に、そのコントラクトを宣言します ERC777セットアップテスト そして、その テスト 契約。その契約内で、以下の宣言を行います。 TestERC777 そして TestERC777受信者 契約。
2. テスト環境の構築
「」を追加します。 setUp テスト環境を初期化する関数:
function setUp() public {
// Deploy mock ERC1820 registry
vm.etch(
address(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24),
bytes(
hex"608060405234801561001057600080fd5b50600436106100a5576000357c010000000000000000000000000000000000000000000000000000000090048063a41e7d5111610078578063a41e7d51146101d4578063aabbb8ca1461020a578063b705676514610236578063f712f3e814610280576100a5565b806329965a1d146100aa5780633d584063146100e25780635df8122f1461012457806365ba36c114610152575b600080fd5b6100e0600480360360608110156100c057600080fd5b50600160a060020a038135811691602081013591604090910135166102b6565b005b610108600480360360208110156100f857600080fd5b5035600160a060020a0316610570565b60408051600160a060020a039092168252519081900360200190f35b6100e06004803603604081101561013a57600080fd5b50600160a060020a03813581169160200135166105bc565b6101c26004803603602081101561016857600080fd5b81019060208101813564010000000081111561018357600080fd5b82018360208201111561019557600080fd5b803590602001918460018302840111640100000000831117156101b757600080fd5b5090925090506106b3565b60408051918252519081900360200190f35b6100e0600480360360408110156101ea57600080fd5b508035600160a060020a03169060200135600160e060020a0319166106ee565b6101086004803603604081101561022057600080fd5b50600160a060020a038135169060200135610778565b61026c6004803603604081101561024c57600080fd5b508035600160a060020a03169060200135600160e060020a0319166107ef565b604080519115158252519081900360200190f35b61026c6004803603604081101561029657600080fd5b508035600160a060020a03169060200135600160e060020a0319166108aa565b6000600160a060020a038416156102cd57836102cf565b335b9050336102db82610570565b600160a060020a031614610339576040805160e560020a62461bcd02815260206004820152600f60248201527f4e6f7420746865206d616e616765720000000000000000000000000000000000604482015290519081900360640190fd5b6103428361092a565b15610397576040805160e560020a62461bcd02815260206004820152601a60248201527f4d757374206e6f7420626520616e204552433136352068617368000000000000604482015290519081900360640190fd5b600160a060020a038216158015906103b85750600160a060020a0382163314155b156104ff5760405160200180807f455243313832305f4143434550545f4d4147494300000000000000000000000081525060140190506040516020818303038152906040528051906020012082600160a060020a031663249cb3fa85846040518363ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018083815260200182600160a060020a0316600160a060020a031681526020019250505060206040518083038186803b15801561047e57600080fd5b505afa158015610492573d6000803e3d6000fd5b505050506040513d60208110156104a857600080fd5b5051146104ff576040805160e560020a62461bcd02815260206004820181905260248201527f446f6573206e6f7420696d706c656d656e742074686520696e74657266616365604482015290519081900360640190fd5b600160a060020a03818116600081815260208181526040808320888452909152808220805473ffffffffffffffffffffffffffffffffffffffff19169487169485179055518692917f93baa6efbd2244243bfee6ce4cfdd1d04fc4c0e9a786abd3a41313bd352db15391a450505050565b600160a060020a03818116600090815260016020526040812054909116151561059a5750806105b7565b50600160a060020a03808216600090815260016020526040902054165b919050565b336105c683610570565b600160a060020a031614610624576040805160e560020a62461bcd02815260206004820152600f60248201527f4e6f7420746865206d616e616765720000000000000000000000000000000000604482015290519081900360640190fd5b81600160a060020a031681600160a060020a0316146106435780610646565b60005b600160a060020a03838116600081815260016020526040808220805473ffffffffffffffffffffffffffffffffffffffff19169585169590951790945592519184169290917f605c2dbf762e5f7d60a546d42e7205dcb1b011ebc62a61736a57c9089d3a43509190a35050565b600082826040516020018083838082843780830192505050925050506040516020818303038152906040528051906020012090505b92915050565b6106f882826107ef565b610703576000610705565b815b600160a060020a03928316600081815260208181526040808320600160e060020a031996909616808452958252808320805473ffffffffffffffffffffffffffffffffffffffff19169590971694909417909555908152600284528181209281529190925220805460ff19166001179055565b600080600160a060020a038416156107905783610792565b335b905061079d8361092a565b156107c357826107ad82826108aa565b6107b85760006107ba565b815b925050506106e8565b600160a060020a0390811660009081526020818152604080832086845290915290205416905092915050565b6000808061081d857f01ffc9a70000000000000000000000000000000000000000000000000000000061094c565b909250905081158061082d575080155b1561083d576000925050506106e8565b61084f85600160e060020a031961094c565b909250905081158061086057508015155b15610870576000925050506106e8565b61087a858561094c565b909250905060018214801561088f5750806001145b1561089f576001925050506106e8565b506000949350505050565b600160a060020a0382166000908152600260209081526040808320600160e060020a03198516845290915281205460ff1615156108f2576108eb83836107ef565b90506106e8565b50600160a060020a03808316600081815260208181526040808320600160e060020a0319871684529091529020549091161492915050565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff161590565b6040517f01ffc9a7000000000000000000000000000000000000000000000000000000008082526004820183905260009182919060208160248189617530fa90519096909550935050505056fea165627a7a72305820377f4a2d4301ede9949f163f319021a6e9c687c292a5e2b2c4734c126b524e6c0029"
)
);
erc1820Registry = IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24);
deployer = address(this);
user1 = address(0x1);
user2 = address(0x2);
// Deploy custom ERC777 token
address[] memory defaultOperators = new address[](0);
token = new TestERC777("Gold", "GLD", defaultOperators);
// Deploy ERC777Recipient
recipient = new TestERC777Recipient();
vm.label(address(token), "GoldToken");
vm.label(address(recipient), "TokenRecipient");
vm.label(user1, "User1");
vm.label(user2, "User2");
}
この関数は各テストの前に実行され、状態を初期化します。所有者アドレスとオペレーターアドレスを初期化し、初期供給量を持つトークンを作成し、 ERC777受信者 契約。
3. 初期設定のテスト
設定が正しいかどうかを確認するための最初のテストを追加してみましょう:
function testERC777Setup() public {
// Verify ERC1820 registry is deployed
assertTrue(address(erc1820Registry).code.length > 0, "ERC1820 registry should be deployed");
// Verify ERC777 token is deployed
assertTrue(address(token).code.length > 0, "ERC777 token should be deployed");
// Check token details
assertEq(token.name(), "Gold", "Token name should be Gold");
assertEq(token.symbol(), "GLD", "Token symbol should be GLD");
assertEq(token.totalSupply(), 0, "Initial supply should be 0");
// Mint some tokens to user1
token.mint(user1, 1000 * 10**18, "", "");
// Check balance
assertEq(token.balanceOf(user1), 1000 * 10**18, "User1 balance should be 1000 GLD");
}
4. 転送機能のテスト
それでは、トークンの転送機能をテストしてみましょう:
function testERC777TransferToAddress() public {
// Mint tokens to user1
token.mint(user1, 1000 * 10**18, "", "");
// User1 sends tokens to user2 (regular address)
vm.prank(user1);
token.send(user2, 100 * 10**18, "");
// Check token balances
assertEq(token.balanceOf(user1), 900 * 10**18, "User1 balance should be 900 GLD after sending");
assertEq(token.balanceOf(user2), 100 * 10**18, "User2 balance should be 100 GLD after receiving");
}
このスニペットは、以下をシミュレートします。 user1 トークンを送信する先 user2 そして、その結果として算出された残高を確認します。
5. 送信フックのテスト
ERC777の送信フック機能をテストしてみましょう:
function testERC777TransferToRegisteredRecipient() public {
// Mint tokens to user1
token.mint(user1, 1000 * 10**18, "", "");
vm.prank(address(recipient)); // The recipient must call this as it's its own manager by default
erc1820Registry.setManager(address(recipient), address(this));
// Register the recipient contract
vm.prank(address(this));
erc1820Registry.setInterfaceImplementer(address(this), _TOKENS_RECIPIENT_INTERFACE_HASH, address(this));
// User1 sends tokens to the recipient contract
vm.prank(user1);
token.send(address(recipient), 150 * 10**18, "");
// Check recipient contract state
assertEq(recipient.getReceivedTokens(), 150 * 10**18, "Recipient should have received 150 GLD");
(uint256 lastAmount, address lastOperator, address lastSender) = recipient.getLastReceivedInfo();
assertEq(lastAmount, 150 * 10**18, "Last received amount should be 150 GLD");
assertEq(lastOperator, user1, "Last operator should be user1");
assertEq(lastSender, user1, "Last sender should be user1");
// Check token balances
assertEq(token.balanceOf(user1), 850 * 10**18, "User1 balance should be 850 GLD after sending");
assertEq(token.balanceOf(address(recipient)), 150 * 10**18, "Recipient balance should be 150 GLD after receiving");
}
このテストは、TestERC777Recipient コントラクトがトークンを正しく受信し、その状態を更新し、トランザクションに関する必要な詳細をログに記録することを検証するものです。
6. オペレーター送信テスト
それでは、別のユーザーに代わってトークンを送信するオペレーターの機能をテストしてみましょう:
function testERC777OperatorSend() public {
// Mint tokens to user1
token.mint(user1, 1000 * 10**18, "", "");
// Set user2 as an operator for user1
vm.prank(user1);
token.authorizeOperator(user2);
// Ensure the recipient contract is properly set up
vm.prank(address(recipient));
erc1820Registry.setInterfaceImplementer(address(recipient), _TOKENS_RECIPIENT_INTERFACE_HASH, address(recipient));
// User2 sends tokens from user1 to the recipient contract
vm.prank(user2);
token.operatorSend(user1, address(recipient), 200 * 10**18, "", "");
// Check recipient contract state
assertEq(recipient.getReceivedTokens(), 200 * 10**18, "Recipient should have received 200 GLD");
(uint256 lastAmount, address lastOperator, address lastSender) = recipient.getLastReceivedInfo();
assertEq(lastAmount, 200 * 10**18, "Last received amount should be 200 GLD");
assertEq(lastOperator, user2, "Last operator should be user2");
assertEq(lastSender, user1, "Last sender should be user1");
// Check token balances
assertEq(token.balanceOf(user1), 800 * 10**18, "User1 balance should be 800 GLD after sending");
assertEq(token.balanceOf(address(recipient)), 200 * 10**18, "Recipient balance should be 200 GLD after receiving");
}
このテストは、演算子が user2 他のユーザーのアカウントからトークンを送信できる user1 また、受信側のコントラクトが受信したトークンを正しく処理していることを確認します。
これらのテストを実行するには、ターミナルで次のコマンドを実行してください:
フォージテスト
以下のような出力が表示されます:
ERC777-Foundry % forge test -vvv
[⠊] コンパイル中...
[⠘] Solc 0.8.22 を使用して 1 つのファイルをコンパイル中
[⠃] Solc 0.8.22 のコンパイルが 1.76 秒で完了しました
コンパイラの実行に成功しました!
test/GLDToken.t.sol:ERC777SetupTest に対して 4 つのテストを実行しました
[PASS] testERC777OperatorSend() (ガス: 252056)
[PASS] testERC777Setup() (ガス: 86202)
[PASS] testERC777TransferToAddress() (ガス: 110695)
[PASS] testERC777TransferToRegisteredRecipient() (ガス: 268863)
スイート結果: OK。4件が合格、0件が失敗、0件がスキップ、6.20msで完了 (CPU時間 1.13ms)
テストに合格したので、これを本番用のテストネットにデプロイしましょう。
テストネットへのデプロイ
「」という名前のファイルを作成します。 script/DeployERC777Contracts.s.sol そして、以下のコードを追加してください:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "forge-std/Script.sol";
import "../src/TestERC777.sol";
import "../src/TestERC777Recipient.sol";
contract DeployERC777Contracts is Script {
IERC1820Registry constant _ERC1820_REGISTRY = IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24);
bytes32 constant _TOKENS_RECIPIENT_INTERFACE_HASH = keccak256("ERC777TokensRecipient");
function deployTestERC777() external {
vm.startBroadcast();
// Deploy TestERC777 token
address[] memory defaultOperators = new address[](0);
uint256 initialSupply = 1000000 * 10**18; // 1 million tokens with 18 decimals
TestERC777 token = new TestERC777("Gold", "GLD", defaultOperators);
token.mint(msg.sender, initialSupply, "", "");
vm.stopBroadcast();
console.log("TestERC777 token deployed at:", address(token));
console.log("Tokens minted to:", msg.sender);
console.log("Initial supply:", initialSupply);
}
function deployTestERC777Recipient() external {
vm.startBroadcast();
// Deploy TestERC777Recipient
TestERC777Recipient recipient = new TestERC777Recipient();
vm.stopBroadcast();
console.log("TestERC777Recipient deployed at:", address(recipient));
console.log("ERC1820 Registry address:", address(_ERC1820_REGISTRY));
}
}
スクリプトの内容を振り返ってみましょう。
このスクリプトには、2つの独立したデプロイメント関数が含まれており、それぞれがERC-777トークンの特定のコンポーネントと、受信者コントラクトのフックを設定します。これらは別々のコントラクトであり、ERC-1820レジストリにそれぞれ独立して登録される点に注意してください。レジストリは動的なインターフェース検出を可能にしており、これによりトークンコントラクトは、あるアドレス(受信者コントラクトなど)がトークンを受け取るために必要なインターフェースを実装しているかどうかを判別します。
それでは、以下の各ターミナルコマンドを、両方に対して実行してください。 TestERC777 そして ERC777受信者 契約。
forge script script/DeployERC777Contracts.s.sol:DeployERC777Contracts --sig "deployTestERC777()" --rpc-url $RPC_URL --broadcast -vvv --private-key $PRIVATE_KEY
forge script script/DeployERC777Contracts.s.sol:DeployERC777Contracts --sig "deployTestERC777Recipient()" --rpc-url $RPC_URL --broadcast -vvv --private-key $PRIVATE_KEY
出力にはトレースが表示され、コントラクトアドレスも表示されます:
...
チェーン 11155111
推定ガス価格:0.269606234 gwei
スクリプトの推定総ガス使用量:2035187
必要と推定される金額:0.000548699102555758 ETH
==========================
##
トランザクションの送信 [0 - 1]。
⠉ [00:00:00] [##################################################################################################################################################################################] 2/2 トランザクション (0.0秒)##
受信を待機中。
⠙ [00:00:07] [##############################################################################################################################################################################] 2/2 レシート (0.0秒)
##### sepolia
✅ [成功]ハッシュ: 0x12451b5a7e8cb5fe13389d01c9c86a2ac18610dd5d35932a810e39d263e8c935
コントラクトアドレス: 0x7258c917eBE13c54a71a81D50e9652a847dceA21
ブロック: 6572863
支払額:0.000235367593825194 ETH (1481877 ガス * 0.158830722 gwei)
これで完了です!ここまでたどり着いたなら、よく頑張りましたね。ERC-777は複雑なトークン規格ですが、常に元のEIPを参照するようにしてください。
まとめ
このガイドでは、Foundry を使用した ERC-777 トークンおよび ERC-777 受信者コントラクトの作成、テスト、デプロイについて解説しました。これで、ERC-777 トークンの仕組みに関する基礎的な理解が得られたほか、フックやオペレーターの機能を実証するために、トークンコントラクトと受信者コントラクトの両方を実装しました。
Twitter(@Quicknode)をフォローするか、Discordのコミュニティに参加して、最新のブロックチェーン開発ツールやインサイトに関する最新情報を入手してください。皆さんが次にどんなものを作られるのか、楽しみにしています!
皆様からのフィードバックを心よりお待ちしております!❤️
ご意見や新しいトピックに関するご要望などがありましたら、ぜひお知らせください。皆様からのご連絡を心よりお待ちしております。
