Remix IDEにはデフォルトでSolidityのサンプルコードが3本が格納されています。非常にシンプルなコードですが、Solidityの基礎的な要素が盛り込まれていますので、初心者の方にはとても良い教材となっています。
今回はその2つ目のOwnerコントラクトのソースコードを解析してみます。1つ目のStorageコントラクトについては以下の記事をご覧ください。なお、1つ目で解説した要素についても、記載していますので、必要に応じて読み飛ばしてください。
Remix IDEサンプルコード:Ownerコントラクト
2つ目のOwnerコントラクトのソースコードを解析していきましょう。コードの頭から順に見ていきましょう。
version pragma:コンパイラバージョン
ソースコードの3行目にある “pragma solidity” は、Solidityのコンパイラーバージョンを指定している箇所になります。
pragma solidity >=0.7.0 <0.9.0;
この場合、バージョン0.7.0以上、0.9.0未満のコンパイラーバージョンに対応したソースということを宣言しています。これは、バージョンが上がることにより仕様が変わり、コードが意図した動きをしなくなることを避ける目的があります。
範囲指定ではなく、単一バージョンを指定して書くことも可能です。
pragma solidity ^0.8.12
バージョンの頭に「^」(ハット)が付いている場合は、0.8.12 バージョン固定ということではなく、0.8.12以降で0.8.xx最新のコンパイラーバージョンを指定したことになります。
(参考:Solidity Docs の version pragma解説)
import:別ファイルソースの読み込み
importは別ファイルソースの読み込みを行う指示文です。
ここでは hardhatフォルダ配下の console.solというファイルを読み込んでいます。
import "hardhat/console.sol";
Remix IDE内では、実際にはサンプルコードが格納されている contracts フォルダと同じ default_workspace内の .deps フォルダ内に格納されています。
.deps > npm > hardhat > console.sol
/* */:コメント
/* から */ はコメント行になります。単行のコメントは // でも記載可能です。複数行の場合は、/* から */ の間がコメントになります。
コメントの中に、@dev, @param といった記載がありますが、これは NatSpec(ナットスペック:Ethereum Natural Language Specification Format) と呼ばれる、Solidityにおけるコメント記載の標準ルールのタグになります。NatSpecについてはまた別途ご説明いたします。
/**
* @title Owner
* @dev Set & change owner
*/
(参考:Solidity DocsのNatSpec解説)
contract:コントラクト
“contract” で始まり、波括弧(Curly Brackets)で括られた部分がコントラクト本体になります。contractに続く文字列がコントラクト名称です。コントラクト名称は通常、最初の文字が大文字になります。
contract Owner {
}
address:アドレス型宣言
Ownerコントラクト内で最初に記載されている address は変数の型になります。
address private owner;
ownerという状態変数をaddress型で定義していることになります。このaddressは Ethereumのアドレスを格納する20バイトの領域です。
(参考:Solidity Docsのaddress解説)
owner の前にある private はこの状態変数 ownerのVisibility(視認性、可視性)を定義しています。この関数のアクセスレベルを表しています。privateはこのContract内のみで使用ができます。外部からは見えません。また、継承したContractでも見ることができません。状態変数のVisibilityにはprivateの他に public, internalがあります。internal は private に似ていますが、internalは継承先のContractから見えるということが異なる点になります。
ちなみに、関数のVisibilityにはexternalがありますが、状態変数にはありません。
(参考:Solidity DocsのState Variable Visibility解説)
event:EVMのログ出力
eventはEVM(Ethereum Virtual Machine)へのログ出力機能になります。関数と同様にeventで定義し、実際の呼び出しは emit を使用します。
// event for EVM logging
event OwnerSet(address indexed oldOwner, address indexed newOwner);
ここでは OwnerSet という event を定義しています。第1引数、第2引数ともにaddress型の変数を与えています。この OwnerSetをコントラクト内で emit を使用し呼び出すと、引数の値がログに出力されます。
modifier:関数修飾子
modifierは関数に付加することのできるコードをまとめたものです。複数の関数で利用できます。
以下の isOwner では、require の行が本体となっています。この部分が関数に付加されます。
modifier の中には、_(アンダーバー)の記載があります。このアンダーバーの位置に修飾する関数の内容が置き換わります。
// modifier to check if caller is owner
modifier isOwner() {
// If the first argument of 'require' evaluates to 'false', execution terminates and all
// changes to the state and to Ether balances are reverted.
// This used to consume all gas in old EVM versions, but not anymore.
// It is often a good idea to use 'require' to check if functions are called correctly.
// As a second argument, you can also provide an explanation about what went wrong.
require(msg.sender == owner, "Caller is not owner");
_;
}
modifierは、関数の宣言の最後に付加して使用します。以下の関数changeOwnerでは関数宣言の一番後、丸括弧の前に modifier の isOwner が記述されています。
function changeOwner(address newOwner) public isOwner {
constructor:deploy時実行コード
constructor は、特殊なコードです。Contract をオンチェーンにdeployするときのみに実行されます。
このOwnerコントラクトの constructor では、主にコンソールロギングにDeployしたアドレスを表示しています。
(参考:Solidity Docsの constructor)
/**
* @dev Set contract deployer as owner
*/
constructor() {
console.log("Owner contract deployed by:", msg.sender);
owner = msg.sender; // 'msg.sender' is sender of current call, contract deployer for a constructor
emit OwnerSet(address(0), owner);
}
function:関数 ー changeOwner
function は関数の定義です。最初の関数は changeOwner という関数名を定義しています。
function changeOwner(address newOwner) public isOwner {
emit OwnerSet(owner, newOwner);
owner = newOwner;
}
関数名の後に丸括弧で括られている部分は引数になります。この changeOwner 関数は address型の newOwner という一つの引数を持っています。
引数の定義の後にある public は関数のVisibility(視認性、可視性)と呼ばれるものです。この関数のアクセスレベルを表しています。publicは外部からの呼び出しが可能な関数の宣言です。関数のVisibilityには他に external, internal, privateがあります。(参考:Solidity DocsのFunction Visibility)
この changeOwner 関数は、引数の newOwner を受け取り、その値をコントラクト内の状態変数 owner に格納しています。
function:関数 ー getOwner
2つ目の関数 getOwner は引数はありませんが、復帰値を持つ関数です。関数の宣言に returns (address) との記載があり、関数内で、return owner と記載があります。関数が呼び出された時に、コントラクト内の状態変数 owner に格納されている値を返す関数になっています。
function getOwner() external view returns (address) {
return owner;
}
また、この retrieve 関数には external というVisibilityの後に view という記載があります。これは State Mutabilityと呼ばれるもので、状態変数の変更可能性の宣言になります。viewは、「状態変数の参照はするが、変更はしない」という宣言になります。State Mutabilityには他に、pure, payable, nonpayable があります。(参考:Solidity DocsのState Mutability)
Ownerコントラクトのまとめ
Remix IDEにデフォルトで格納されているSolidityサンプルコードのひとつである Owner コントラクトの解析を行いました。非常にシンプルですが、コンパイラバージョン、コントラクト、関数、型、コメント等のSolidityコードの基本的な要素が含まれていました。また、constructor, modifier, eventといったSolidityに特徴的な要素もあり、とても参考になるコードです。
Solidity初心者には勉強になりますね。他のSolidityコードも読み解いていきましょう。
コメント