Solidityから他のコントラクトと対話する
これまでのチュートリアルでは、初めてのスマート・コントラクトをデプロイする方法や、修飾子を使用したアクセス制御 (opens in a new tab)、Solidityでのエラー処理 (opens in a new tab)などの機能を追加する方法について多くを学びました。このチュートリアルでは、既存のコントラクトからスマート・コントラクトをデプロイし、それと対話する方法を学びます。
ファクトリを作成することで、誰でも独自のCounterスマート・コントラクトを持てるようにするコントラクトを作成します。その名前はCounterFactoryになります。まず、最初のCounterスマート・コントラクトのコードを以下に示します。
pragma solidity 0.5.17;
contract Counter {
uint256 private _count;
address private _owner;
address private _factory;
modifier onlyOwner(address caller) {
require(caller == _owner, "You're not the owner of the contract");
_;
}
modifier onlyFactory() {
require(msg.sender == _factory, "You need to use the 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はコントラクトファクトリのアドレスを参照します。コントラクトを使用して他のコントラクトと対話することは一般的な手法であるため、これは理解しておくべき非常に重要なポイントです。したがって、複雑なケースでは誰が送信者であるかに注意する必要があります。
このため、状態を変更する関数が、元の呼び出し元をパラメータとして渡すファクトリによってのみ呼び出されることを保証するonlyFactory修飾子も追加しました。
他のすべてのCounterを管理する新しいCounterFactoryの中に、所有者とそのCounterコントラクトのアドレスを関連付けるマッピングを追加します。
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を所有していない場合は、その人のアドレスをCounterコンストラクタに渡して新しい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関数も非常に似ていますが、元のトランザクション送信者をCounterコントラクトに渡します。
function increment() public {
require (_counters[msg.sender] != Counter(0));
Counter(_counters[msg.sender]).increment(msg.sender);
}
何度も呼び出されると、Counterがオーバーフローの被害に遭う可能性があることに注意してください。このような可能性から保護するために、可能な限り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, "You're not the owner of the contract");
_;
}
modifier onlyFactory() {
require(msg.sender == _factory, "You need to use the 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日
