メインコンテンツへスキップ

Solidityから他のコントラクトとやり取りする

スマートコントラクト
Solidity
Remix
デプロイ
構成可能性
上級
jdourlens
2020年4月5日
6 分の読書

これまでのチュートリアルでは、最初のスマートコントラクトのデプロイ方法や、修飾子(modifier)を使ったアクセス制御opens in a new tabSolidityでのエラー処理opens in a new tabといった機能の追加など、多くのことを学びました。 このチュートリアルでは、既存のコントラクトからスマートコントラクトをデプロイし、それとやり取りする方法を学びます。

ここでは、CounterFactoryという名前のファクトリーを作成することで、誰もが自分自身のCounterスマートコントラクトを持てるようにするコントラクトを作成します。 まず、これが最初のCounterスマートコントラクトのコードです。

1pragma solidity 0.5.17;
2
3contract Counter {
4
5 uint256 private _count;
6 address private _owner;
7 address private _factory;
8
9
10 modifier onlyOwner(address caller) {
11 require(caller == _owner, "あなたはこのコントラクトの所有者ではありません");
12 _;
13 }
14
15 modifier onlyFactory() {
16 require(msg.sender == _factory, "ファクトリーを使用する必要があります");
17 _;
18 }
19
20 constructor(address owner) public {
21 _owner = owner;
22 _factory = msg.sender;
23 }
24
25 function getCount() public view returns (uint256) {
26 return _count;
27 }
28
29 function increment(address caller) public onlyFactory onlyOwner(caller) {
30 _count++;
31 }
32
33}
すべて表示

ファクトリーのアドレスとコントラクト所有者のアドレスを追跡するために、コントラクトコードを少し変更したことに注意してください。 他のコントラクトからコントラクトコードを呼び出すと、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}
5
6function 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をできるだけ使用すべきです。

このコントラクトをデプロイするには、CounterFactoryCounterの両方のコードを提供する必要があります。 例えばRemixでデプロイする場合、CounterFactoryを選択する必要があります。

こちらが全コードです。

1pragma solidity 0.5.17;
2
3contract Counter {
4
5 uint256 private _count;
6 address private _owner;
7 address private _factory;
8
9
10 modifier onlyOwner(address caller) {
11 require(caller == _owner, "あなたはこのコントラクトの所有者ではありません");
12 _;
13 }
14
15 modifier onlyFactory() {
16 require(msg.sender == _factory, "ファクトリーを使用する必要があります");
17 _;
18 }
19
20 constructor(address owner) public {
21 _owner = owner;
22 _factory = msg.sender;
23 }
24
25 function getCount() public view returns (uint256) {
26 return _count;
27 }
28
29 function increment(address caller) public onlyFactory onlyOwner(caller) {
30 _count++;
31 }
32
33}
34
35contract CounterFactory {
36
37 mapping(address => Counter) _counters;
38
39 function createCounter() public {
40 require (_counters[msg.sender] == Counter(0));
41 _counters[msg.sender] = new Counter(msg.sender);
42 }
43
44 function increment() public {
45 require (_counters[msg.sender] != Counter(0));
46 Counter(_counters[msg.sender]).increment(msg.sender);
47 }
48
49 function getCount(address account) public view returns (uint256) {
50 require (_counters[account] != Counter(0));
51 return (_counters[account].getCount());
52 }
53
54 function getMyCount() public view returns (uint256) {
55 return (getCount(msg.sender));
56 }
57
58}
すべて表示

コンパイル後、Remixのデプロイセクションで、デプロイするファクトリーを選択します。

Remixでデプロイするファクトリーの選択

その後、コントラクトファクトリーを操作して、値が変化することを確認できます。 もし、異なるアドレスからスマートコントラクトを呼び出したい場合は、Remixのアカウント選択でアドレスを変更する必要があります。

最終更新: 2023年8月15日

このチュートリアルは役に立ちましたか?