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

Solidityを使用した他のコントラクトの活用

スマートコントラクトSolidityRemixデプロイ構成可能性
上級
jdourlens
EthereumDev(opens in a new tab)
2020年4月5日
6 分の読書 minute read
comp-tutorial-metadata-tip-author 0x19dE91Af973F404EDF5B4c093983a7c6E3EC8ccE

これまでのチュートリアルでは、最初のスマートコントラクトをデプロイする方法と、修飾子によるアクセス制御(opens in a new tab)Solidityでのエラー処理(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, "You're not the owner of the contract");
12 _;
13 }
14
15 modifier onlyFactory() {
16 require(msg.sender == _factory, "You need to use the 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はコントラクトファクトリーのアドレスを参照します。 コントラクトを使用して他のコントラクトとやり取りすることはよくあることなので、これは理解しておくべき非常に重要なポイントです。 したがって、複雑なケースでは誰が送信者なのかに注意を払う必要があります。

このために、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}
5
6function 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)を使用してください。

このコントラクトをデプロイするためには、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, "You're not the owner of the contract");
12 _;
13 }
14
15 modifier onlyFactory() {
16 require(msg.sender == _factory, "You need to use the 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のアカウントの選択で別のアドレスに変更する必要があります。

最終編集者: @hesoponyo(opens in a new tab), 2024年1月18日

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