Solidityから他のコントラクトとやり取りする
これまでのチュートリアルでは、最初のスマートコントラクトのデプロイ方法や、修飾子(modifier)を使ったアクセス制御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, "あなたはこのコントラクトの所有者ではありません");12 _;13 }1415 modifier onlyFactory() {16 require(msg.sender == _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は私たちのコントラクトファクトリーのアドレスを参照します。 コントラクトを使って他のコントラクトとやり取りするのは一般的な方法であるため、これは理解しておくべき、本当に重要な点です。 したがって、複雑なケースでは誰が送信者(sender)なのかに注意する必要があります。
このため、元の呼び出し元をパラメータとして渡すファクトリーによってのみ状態変更関数が呼び出されるように、onlyFactory修飾子も追加しました。
他のすべてのCounterを管理する新しいCounterFactoryの中に、所有者とそのカウンターコントラクトのアドレスを関連付けるマッピングを追加します。
1mapping(address => Counter) _counters;イーサリアムでは、マッピングはJavaScriptのオブジェクトに相当し、型Aのキーを型Bの値にマッピングできます。このケースでは、所有者のアドレスをそのCounterのインスタンスにマッピングします。
誰かのために新しいCounterをインスタンス化するには、次のようになります。
1 function createCounter() public {2 require (_counters[msg.sender] == Counter(0));3 _counters[msg.sender] = new Counter(msg.sender);4 }まず、その人がすでにカウンターを所有しているかどうかをチェックします。 その人がカウンターを所有していない場合、その人のアドレスをCounterのコンストラクタに渡して新しいカウンターをインスタンス化し、新しく作成されたインスタンスをマッピングに割り当てます。
特定の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関数も非常によく似ていますが、元のトランザクションの送信者(sender)を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, "あなたはこのコントラクトの所有者ではありません");12 _;13 }1415 modifier onlyFactory() {16 require(msg.sender == _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のアカウント選択でアドレスを変更する必要があります。
最終更新: 2023年8月15日
