Solidityを使用した他のコントラクトの活用
これまでのチュートリアルでは、最初のスマートコントラクトをデプロイする方法と、修飾子によるアクセス制御(opens in a new tab)やSolidityでのエラー処理(opens in a new tab)といったいくつかの機能を追加する方法について学びました。 このチュートリアルでは、既存のコントラクトからスマートコントラクトをデプロイし、それを活用する方法について説明します。
ここでは、CounterFactory
という名前のファクトリーを作成することで、誰でも自分のCounter
スマートコントラクトを所有できるようにするコントラクトを作成します。 初めに、これがCounter
スマートコントラクトの初期コードです。
1pragma solidity 0.5.17;23contract Counter {45 uint256 private _count;6 address private _owner;7 address private _factory;8910 modifier onlyOwner(address caller) {11 require(caller == _owner, "You're not the owner of the contract");12 _;13 }1415 modifier onlyFactory() {16 require(msg.sender == _factory, "You need to use the factory");17 _;18 }1920 constructor(address owner) public {21 _owner = owner;22 _factory = msg.sender;23 }2425 function getCount() public view returns (uint256) {26 return _count;27 }2829 function increment(address caller) public onlyFactory onlyOwner(caller) {30 _count++;31 }3233}すべて表示コピー
ファクトリーのアドレスとコントラクト所有者のアドレスを追跡するために、コントラクトコードを少し変更していることに注意してください。 他のコントラクトからコントラクトコードを呼び出した場合、msg.senderはコントラクトファクトリーのアドレスを参照します。 コントラクトを使用して他のコントラクトとやり取りすることはよくあることなので、これは理解しておくべき非常に重要なポイントです。 したがって、複雑なケースでは誰が送信者なのかに注意を払う必要があります。
このために、onlyFactory
という修飾子も追加しました。この修飾子は、元の呼び出し元をパラメータとして渡すファクトリーのみが、状態変更関数を呼び出せるようにします。
他のすべてのカウンターを管理する新しいCounterFactory
内で、所有者をカウンターコントラクトのアドレスに関連付けるマッピングを追加します。
1mapping(address => Counter) _counters;コピー
イーサリアムでは、マッピングはJavaScriptのオブジェクトに相当します。これは、型Aのキーを型Bの値にマッピングできます。ここでは、所有者のアドレスをそのカウンターのインスタンスにマッピングしています。
ユーザーのために新しいカウンターをインスタンス化する場合は、次のようになります。
1 function createCounter() public {2 require (_counters[msg.sender] == Counter(0));3 _counters[msg.sender] = new Counter(msg.sender);4 }コピー
まず、そのユーザーがすでにカウンターを所有しているかどうかを確認します。 もしカウンターを所有していなければ(カウンターの数が0ならば)、そのアドレスをCounter
コンストラクタに渡して新しいカウンターをインスタンス化し、新しく作成したインスタンスをマッピングに割り当てます。
特定のカウンターの数を取得する場合は、次のようになります。
1function getCount(address account) public view returns (uint256) {2 require (_counters[account] != Counter(0));3 return (_counters[account].getCount());4}56function getMyCount() public view returns (uint256) {7 return (getCount(msg.sender));8}コピー
最初の関数は、指定されたアドレスにCounterコントラクトが存在するかどうかをチェックし、存在する場合にインスタンスからgetCount
メソッドを呼び出します。 2番目の関数getMyCount
は、msg.senderを直接getCount
関数に渡す短い関数です。
increment
関数もかなり類似していますが、Counter
コントラクトに元のトランザクション送信者を渡します。
1function increment() public {2 require (_counters[msg.sender] != Counter(0));3 Counter(_counters[msg.sender]).increment(msg.sender);4 }コピー
この関数を何度も呼び出すと、カウンターがオーバーフローする可能性がありますので注意してください。 オーバーフローが発生しないように、できる限りSafeMathライブラリ(opens in a new tab)を使用してください。
このコントラクトをデプロイするためには、CounterFactory
とCounter
の両方のコードが必要です。 例えばRemixでデプロイする場合、CounterFactoryを選択する必要があります。
これが完成したコードです。
1pragma solidity 0.5.17;23contract Counter {45 uint256 private _count;6 address private _owner;7 address private _factory;8910 modifier onlyOwner(address caller) {11 require(caller == _owner, "You're not the owner of the contract");12 _;13 }1415 modifier onlyFactory() {16 require(msg.sender == _factory, "You need to use the factory");17 _;18 }1920 constructor(address owner) public {21 _owner = owner;22 _factory = msg.sender;23 }2425 function getCount() public view returns (uint256) {26 return _count;27 }2829 function increment(address caller) public onlyFactory onlyOwner(caller) {30 _count++;31 }3233}3435contract CounterFactory {3637 mapping(address => Counter) _counters;3839 function createCounter() public {40 require (_counters[msg.sender] == Counter(0));41 _counters[msg.sender] = new Counter(msg.sender);42 }4344 function increment() public {45 require (_counters[msg.sender] != Counter(0));46 Counter(_counters[msg.sender]).increment(msg.sender);47 }4849 function getCount(address account) public view returns (uint256) {50 require (_counters[account] != Counter(0));51 return (_counters[account].getCount());52 }5354 function getMyCount() public view returns (uint256) {55 return (getCount(msg.sender));56 }5758}すべて表示コピー
コンパイル後、Remixのデプロイセクションで、デプロイするファクトリーを選択します。
コントラクトファクトリーを使うと、値の変化を確認できます。 もし、別のアドレスからスマートコントラクトを呼び出したい場合は、Remixのアカウントの選択で別のアドレスに変更する必要があります。
最終編集者: @nhsz(opens in a new tab), 2023年8月15日