概要
トランザクションの核心情報にアクセスする方法を解説します。呼び出し元を特定するmsg.senderを使った所有権管理(constructor, modifier)パターンを紹介。
さらに、関数がETHを受け取るための最重要要素msg.valueとpayableキーワードを学習。簡単な決済機能の実装を通じ、商用DAppの根幹をなす「価値の受け渡し」を実装するスキルが身につきます。
-

-
Solidity学習講座:最終版 目次(全20話)
基礎編 第1話:未来のインターネットへようこそ!Solidityとスマートコントラクトの全体像 第2話:準備は1分!ブラウザだけで開発できる「Remix IDE」の基本操作 第3話:記念すべき初コント ...
続きを見る
目次
はじめに
第10話で、あなたはif文とforループという制御構文を手にし、コントラクトに「判断力」と「繰り返し処理能力」を与えました。あなたのコードは、もはや単なる命令の羅列ではなく、知的なロジックを持つに至りました。
今回は、視点を変えて、スマートコントラクトが受け取る「メッセージ」そのものに注目します。ユーザーが関数を呼び出す行為は、ブロックチェーンに対する一つの**「トランザクション(取引)」です。そのトランザクションには、「誰が」「いくらのETHを添えて」といった、重要な文脈(コンテキスト)情報**が含まれています。
Solidityでは、こうしたトランザクションの文脈情報にアクセスするための、特別な**「グローバル変数」**が用意されています。
あなたはmsg.sender(誰が)については既に知っていますね。今回はそれをさらに深掘りするとともに、関数呼び出しに添えられたETHの量を示す**msg.valueと、ETHを受け取るための必須キーワードpayable**について学びます。
このレッスンを終えるとき、あなたのスマートコントラクトは、単なるロジックの塊から、現実の価値(ETH)を直接扱える、商用アプリケーションの基盤へと進化を遂げます。
msg.senderの深掘り:所有権とアクセス制御
msg.senderは、**「その関数を直接呼び出したアカウントのアドレス」**を指す、address型のグローバル変数です。これは、ユーザーごとのデータを操作するmappingや、特定のユーザーにのみ操作を許可するアクセス制御において、心臓部とも言える役割を果たします。
ここで、スマートコントラクト開発における極めて重要な設計パターン、「所有者(Owner)」の概念を導入しましょう。多くのコントラクトには、管理者だけが実行できる特権的な機能が必要です。これを安全に実装するのが**modifier(修飾子)**です。
Solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract Ownable {
address public owner;
// constructorは、コントラクトがデプロイされる時に一度だけ実行される特別な関数
constructor() {
// デプロイした人を、このコントラクトの所有者(owner)に設定
owner = msg.sender;
}
// "この修飾子が付いた関数は、ownerだけが実行できる" というルールを定義
modifier onlyOwner() {
require(msg.sender == owner, "You are not the owner.");
_; // ← このセミコロン付きアンダースコアが重要!
}
}
constructor:constructorは、コントラクトがブロックチェーンにデプロイされる際に、たった一度だけ実行される初期化用の特殊な関数です。ここでowner = msg.sender;とすることで、「このコントラクトをデプロイした人」を自動的に所有者として設定できます。modifier:modifierは、関数の振る舞いを修飾(modify)するための再利用可能なコードブロックです。onlyOwner修飾子では、まずrequire文で関数の呼び出し元がownerであるかを確認します。もし条件を満たせば、_;の部分で、修飾子が付けられた関数の本体が実行されます。条件を満たさなければ、そこで処理は中断されます。
このonlyOwner修飾子を使えば、特権的な機能を安全かつ簡潔に実装できます。
Solidity
function changeOwner(address _newOwner) public onlyOwner {
// この関数は、ownerだけが実行できる
owner = _newOwner;
}
このように、msg.senderはコントラクトのセキュリティと所有権の基盤となるのです。
msg.valueとpayable:ETHを受け取るための鍵 💰
いよいよ本題です。あなたのコントラクトが、ユーザーからETHを直接受け取るにはどうすればよいでしょうか。その鍵を握るのがmsg.valueとpayableです。
msg.value: msg.valueは、**「その関数呼び出しトランザクションに添付されたETHの量」を示すuint型のグローバル変数です。注意すべきは、この値の単位がETHではなく、ETHの最小単位であるwei(ウェイ)**であることです。(1 ether = 10^18 wei)
payable: デフォルトでは、Solidityの関数はETHを受け取ることができません。もしETHを非対応の関数に送ろうとすると、トランザクション自体が失敗します。関数がETHを受け取れるようにするには、関数に**payable**というキーワードを明示的に付ける必要があります。
それでは、簡単な寄付を受け付けるコントラクトを見てみましょう。
Solidity
contract DonationBox {
mapping(address => uint) public donations;
// payableを付けたことで、この関数はETHの受け取りが可能になる
function donate() public payable {
// msg.valueには、送られてきたETHの量(wei単位)が入っている
require(msg.value > 0, "Please send some Ether.");
// 誰が(msg.sender)いくら(msg.value)寄付したかを記録
donations[msg.sender] += msg.value;
}
// コントラクトが現在保持しているETHの総量を確認する
function getBalance() public view returns (uint) {
return address(this).balance;
}
}
donate関数にpayableを付けたことで、ユーザーはこの関数を呼び出す際にETHを一緒に送ることができます。送られたETHは、このコントラクトのアドレスに自動的に保管されます。その総額は、address(this).balanceで確認できます。address(this)は、そのコントラクト自体のアドレスを指します。
Remixでのpayable関数の試し方
Remixの「Deploy & Run Transactions」タブに、「VALUE」という入力フィールドがあるのを覚えていますか? ここで、トランザクションに添付するETHの量を設定します。単位を「wei」や「ether」から選び、数値を入力してからpayableなdonate関数を実行すると、トランザクションが成功し、getBalanceでコントラクトの残高が増えているのが確認できるはずです。
より実践的な例:商品の購入
1ETHの商品を販売するコントラクトを考えてみましょう。
Solidity
contract SimpleStore {
uint public itemPrice = 1 ether; // Ether単位での記述
mapping(address => bool) public hasPurchased;
function purchase() public payable {
require(hasPurchased[msg.sender] == false, "You already bought it.");
// 送られてきたETHの量が、商品価格と正確に一致するかを確認
require(msg.value == itemPrice, "Incorrect amount of Ether sent.");
hasPurchased[msg.sender] = true;
// (実際には、ここで商品の所有権を付与したり、売上をオーナーに送金したりする)
}
}
ここで1 etherという書き方が登場しました。Solidityでは、wei, gwei, etherといった単位を数値の後ろに付けることができます。これにより、1000000000000000000と書く代わりに1 etherと書けるため、コードの可読性が劇的に向上します。
まとめ:価値を扱うコントラクトへ
お疲れ様でした!今回のレッスンで、あなたはスマートコントラクトが外部のトランザクション情報、特に「誰が」(msg.sender) と「いくらで」(msg.value) という核心情報にアクセスする方法を学びました。
constructorは、デプロイ時に一度だけ実行される初期化関数である。modifierは、関数のアクセス制御などを再利用可能にするための強力なツールである。payableキーワードを付けた関数だけが、ETHを受け取ることができる。msg.valueで、関数に送られてきたETHの量(wei単位)を取得できる。
payableな関数を作れるようになったことで、あなたはクラウドファンディング、有料コンテンツ販売、NFTマーケットプレイスといった、あらゆる商用DAppの根幹をなす「価値の受け渡し」を実装する能力を手に入れたのです。
さて、あなたはOwnableのような便利なコントラクトを作りました。もし、別の新しいコントラクトでも同じ「所有者管理機能」を使いたくなったら、またコードをコピー&ペーストしますか? それは非効率で、メンテナンス性も悪いですよね。
次回、**第12話「コードを再利用!「継承 (inheritance)」でスマートコントラクトを賢く拡張する」**では、既存のコントラクトの機能を引き継いで、新しいコントラクトを賢く、効率的に構築するための「継承」という概念について学びます。オブジェクト指向プログラミングの真髄に触れ、あなたの開発スタイルを次のレベルへと引き上げましょう。
-

-
Solidity学習講座:最終版 目次(全20話)
基礎編 第1話:未来のインターネットへようこそ!Solidityとスマートコントラクトの全体像 第2話:準備は1分!ブラウザだけで開発できる「Remix IDE」の基本操作 第3話:記念すべき初コント ...
続きを見る

