Solidityから他のコントラクトとやり取りする
これまでのチュートリアルでは、最初のスマートコントラクトのデプロイ方法や、修飾子(modifier)を使ったアクセス制御 (opens in a new tab)、Solidityでのエラー処理 (opens in a new tab)といった機能の追加など、多くのことを学びました。 このチュートリアルでは、既存のコントラクトからスマートコントラクトをデプロイし、それとやり取りする方法を学びます。
ここでは、CounterFactoryという名前のファクトリーを作成することで、誰もが自分自身のCounterスマートコントラクトを持てるようにするコントラクトを作成します。 まず、これが最初のCounterスマートコントラクトのコードです。
pragma solidity 0.5.17;
contract Counter {
uint256 private _count;
address private _owner;
address private _factory;
modifier onlyOwner(address caller) {
require(caller == _owner, "あなたはこのコントラクトの所有者ではありません");
_;
}
modifier onlyFactory() {
require(msg.sender == _factory, "ファクトリーを使用する必要があります");
_;
}
constructor(address owner) public {
_owner = owner;
_factory = msg.sender;
}
function getCount() public view returns (uint256) {
return _count;
}
function increment(address caller) public onlyFactory onlyOwner(caller) {
_count++;
}
}
ファクトリーのアドレスとコントラクト所有者のアドレスを追跡するために、コントラクトコードを少し変更したことに注意してください。 他のコントラクトからコントラクトコードを呼び出すと、msg.senderは私たちのコントラクトファクトリーのアドレスを参照します。 コントラクトを使って他のコントラクトとやり取りするのは一般的な方法であるため、これは理解しておくべき、本当に重要な点です。 したがって、複雑なケースでは誰が送信者(sender)なのかに注意する必要があります。
このため、元の呼び出し元をパラメータとして渡すファクトリーによってのみ状態変更関数が呼び出されるように、onlyFactory修飾子も追加しました。
他のすべてのCounterを管理する新しいCounterFactoryの中に、所有者とそのカウンターコントラクトのアドレスを関連付けるマッピングを追加します。
mapping(address => Counter) _counters;
イーサリアムでは、マッピングはJavaScriptのオブジェクトに相当し、型Aのキーを型Bの値にマッピングできます。このケースでは、所有者のアドレスをそのCounterのインスタンスにマッピングします。
誰かのために新しいCounterをインスタンス化するには、次のようになります。
function createCounter() public {
require (_counters[msg.sender] == Counter(0));
_counters[msg.sender] = new Counter(msg.sender);
}
まず、その人がすでにカウンターを所有しているかどうかをチェックします。 その人がカウンターを所有していない場合、その人のアドレスをCounterのコンストラクタに渡して新しいカウンターをインスタンス化し、新しく作成されたインスタンスをマッピングに割り当てます。
特定のCounterのカウント数を取得するには、次のようになります。
function getCount(address account) public view returns (uint256) {
require (_counters[account] != Counter(0));
return (_counters[account].getCount());
}
function getMyCount() public view returns (uint256) {
return (getCount(msg.sender));
}
最初の関数は、指定されたアドレスに対してCounterコントラクトが存在するかどうかをチェックし、その後インスタンスからgetCountメソッドを呼び出します。 2番目の関数getMyCountは、msg.senderを直接getCount関数に渡すための、ただのショートカットです。
increment関数も非常によく似ていますが、元のトランザクションの送信者(sender)をCounterコントラクトに渡します。
function increment() public {
require (_counters[msg.sender] != Counter(0));
Counter(_counters[msg.sender]).increment(msg.sender);
}
何度も呼び出されると、カウンターがオーバーフローを起こす可能性があることに注意してください。 この可能性から保護するために、SafeMathライブラリ (opens in a new tab)をできるだけ使用すべきです。
このコントラクトをデプロイするには、CounterFactoryとCounterの両方のコードを提供する必要があります。 例えばRemixでデプロイする場合、CounterFactoryを選択する必要があります。
こちらが全コードです。
pragma solidity 0.5.17;
contract Counter {
uint256 private _count;
address private _owner;
address private _factory;
modifier onlyOwner(address caller) {
require(caller == _owner, "あなたはこのコントラクトの所有者ではありません");
_;
}
modifier onlyFactory() {
require(msg.sender == _factory, "ファクトリーを使用する必要があります");
_;
}
constructor(address owner) public {
_owner = owner;
_factory = msg.sender;
}
function getCount() public view returns (uint256) {
return _count;
}
function increment(address caller) public onlyFactory onlyOwner(caller) {
_count++;
}
}
contract CounterFactory {
mapping(address => Counter) _counters;
function createCounter() public {
require (_counters[msg.sender] == Counter(0));
_counters[msg.sender] = new Counter(msg.sender);
}
function increment() public {
require (_counters[msg.sender] != Counter(0));
Counter(_counters[msg.sender]).increment(msg.sender);
}
function getCount(address account) public view returns (uint256) {
require (_counters[account] != Counter(0));
return (_counters[account].getCount());
}
function getMyCount() public view returns (uint256) {
return (getCount(msg.sender));
}
}
コンパイル後、Remixのデプロイセクションで、デプロイするファクトリーを選択します。
その後、コントラクトファクトリーを操作して、値が変化することを確認できます。 もし、異なるアドレスからスマートコントラクトを呼び出したい場合は、Remixのアカウント選択でアドレスを変更する必要があります。
ページの最終更新: 2026年3月3日
