スマートコントラクトの解剖学
最終更新: 2026年2月23日
スマートコントラクトは、イーサリアム上のアドレスで実行されるプログラムです。 それらはトランザクションの受信時に実行できるデータと関数で構成されています。 ここでは、スマートコントラクトの構成要素の概要を説明します。
前提条件
まず「スマートコントラクト」についてお読みください。 このドキュメントは、JavaScriptやPythonなどのプログラミング言語に精通していることを前提としています。
データ
すべてのコントラクトデータは、storageまたはmemoryのいずれかの場所に割り当てる必要があります。 スマートコントラクトのストレージの変更にはコストがかかりますので、データをどこに格納するかを考える必要があります。
EVMストレージ
永続データはストレージと呼ばれ、状態変数で表されます。 これらの値は、ブロックチェーンに永続的に保存されます。 コントラクトがコンパイル時に必要なブロックチェーンのストレージ容量を追跡できるように、型を宣言する必要があります。
1// Solidityの例2contract SimpleStorage {3 uint storedData; // 状態変数4 // ...5}1# Vyperの例2storedData: int128オブジェクト指向言語でのプログラミングの経験がある場合は、ほとんどの型になじみがあるでしょう。 しかし、イーサリアムの開発が初めての場合、addressは目新しいかもしれません。
address型は、20バイトまたは160ビットに相当するイーサリアムアドレスを保持できます。 先頭が0xの16進数を返します。
その他の型には次のものがあります。
- ブール値
- 整数
- 固定小数点数
- 固定サイズのバイト配列
- 動的サイズのバイト配列
- 有理数リテラルと整数リテラル
- 文字列リテラル
- 16進数リテラル
- 列挙型
詳細については、以下のドキュメントをご覧ください。
メモリ
コントラクト関数の実行期間にのみ保存される値は、メモリ変数と呼ばれます。 これらはブロックチェーンに永続的に保存されることはないため、低コストで使用できます
EVMがどのようにデータを格納するか(ストレージ、メモリ、スタック)についての詳細は、Solidityドキュメント (opens in a new tab)を参照してください。
環境変数
コントラクトで定義した変数に加え、特別なグローバル変数がいくつかあります。 これらは主にブロックチェーンや現在のトランザクションに関する情報を提供するために使用されます。
例:
| プロパティ | 状態変数 | 説明 |
|---|---|---|
block.timestamp | uint256 | 現在のブロックエポックタイムスタンプ |
msg.sender | address | メッセージの送信者(現在の呼び出し) |
関数
簡単に言うと、関数は受信トランザクションに応じて情報を取得したり、情報を設定したりすることができます。
関数呼び出しには、以下の2種類があります。
internal– これらはEVMコールを作成しません- Internal関数と状態変数は、内部(つまり、現在のコントラクトまたはそこから派生したコントラクト内)からのみアクセスできます。
external– これらはEVMコールを作成します- external関数はコントラクトインターフェイスの一部であり、他のコントラクトから呼び出したり、トランザクションを介して呼び出したりすることができます。 external関数
fは内部では呼び出せません(つまり、f()は機能しませんが、this.f()は機能します)。
- external関数はコントラクトインターフェイスの一部であり、他のコントラクトから呼び出したり、トランザクションを介して呼び出したりすることができます。 external関数
publicまたはprivateにすることもできます
public関数は、コントラクト内から内部的に呼び出すことも、メッセージを介して外部から呼び出すこともできます。private関数は、それらが定義されたコントラクトからのみ参照でき、派生コントラクトからは参照できません。
関数と状態変数はどちらもpublicまたはprivateにすることができます。
コントラクトの状態変数を更新するための関数は次のとおりです。
1// Solidityの例2function update_name(string value) public {3 dapp_name = value;4}string型のvalueが、関数update_nameに渡されます。publicと宣言されており、誰でもアクセスできます。viewが宣言されていないため、コントラクトの状態を変更できます。
View関数
これらの関数によって、コントラクトのデータの状態を変更しないことを指定します。 一般的な例としては、「getter」関数があります。例えば、これを使用してユーザーの残高を受け取ることができます。
1// Solidityの例2function balanceOf(address _owner) public view returns (uint256 _balance) {3 return ownerPizzaCount[_owner];4}1dappName: public(string)23@view4@public5def readName() -> string:6 return dappName状態の変更と見なされるものは、以下のとおりです。
- 状態変数への書き込み。
- イベントの発行 (opens in a new tab)。
- 他のコントラクトの作成 (opens in a new tab)。
selfdestructの使用。- 呼び出しによるイーサ(ETH)の送信。
viewまたはpureが指定されていない関数の呼び出し。- 低レベル呼び出しの使用。
- 特定のオペコードを含むインラインアセンブリの使用。
コンストラクタ関数
constructor関数は、コントラクトが最初にデプロイされたときに1回だけ実行されます。 多くのクラスベースのプログラミング言語のconstructorと同様に、これらの関数はしばしば、指定された値に状態変数を初期化します。
1// Solidityの例2// コントラクトのデータを初期化し、`owner`を3// コントラクト作成者のアドレスに設定します。4constructor() public {5 // すべてのスマートコントラクトは、その関数をトリガーするために外部トランザクションに依存します。6 // `msg`は、送信者のアドレスやトランザクションに含まれるETHの量など、7 // 特定のトランザクションに関する関連データを含むグローバル変数です。8 // 詳細はこちら: https://solidity.readthedocs.io/en/v0.5.10/units-and-global-variables.html#block-and-transaction-properties9 owner = msg.sender;10}すべて表示1# Vyperの例23@external4def __init__(_beneficiary: address, _bidding_time: uint256):5 self.beneficiary = _beneficiary6 self.auctionStart = block.timestamp7 self.auctionEnd = self.auctionStart + _bidding_time組み込み関数
コントラクトで定義した変数と関数に加え、特別な組み込み関数がいくつかあります。 最もわかりやすい例は、以下のとおりです。
address.send()– Soliditysend(address)– Vyper
これらの関数により、コントラクトは他のアカウントにETHを送信することができます。
関数の記述
関数には以下のものが必要です。
- パラメータ変数と型(パラメータを受け取る場合)
- internal/externalの宣言
- pure/view/payableの宣言
- 戻り値の型(値を返す場合)
1pragma solidity >=0.4.0 <=0.6.0;23contract ExampleDapp {4 string dapp_name; // 状態変数56 // コントラクトがデプロイされたときに呼び出され、値を初期化します7 constructor() public {8 dapp_name = "My Example dapp";9 }1011 // Get関数12 function read_name() public view returns(string) {13 return dapp_name;14 }1516 // Set関数17 function update_name(string value) public {18 dapp_name = value;19 }20}すべて表示完全なコントラクトはこのようになります。 ここで、constructor関数は、dapp_name変数の初期値を提供します。
イベントとログ
イベントは、スマートコントラクトがフロントエンドや他のサブスクライブしているアプリケーションと通信することを可能にします。 トランザクションが検証されてブロックに追加されると、スマートコントラクトはイベントを発行し、情報をログに記録できます。これをフロントエンドが処理して活用します。
注釈付きの例
Solidityで書かれた例を以下に示します。 コードを試したい場合は、Remix (opens in a new tab)で操作できます。
Hello world
1// セマンティックバージョニングを使用して、Solidityのバージョンを指定します。2// 詳細はこちら: https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#pragma3pragma solidity ^0.5.10;45// `HelloWorld`という名前のコントラクトを定義します。6// コントラクトは、関数とデータ(その状態)のコレクションです。7// デプロイされると、コントラクトはイーサリアムブロックチェーン上の特定のアドレスに配置されます。8// 詳細はこちら: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html9contract HelloWorld {1011 // `string`型の状態変数`message`を宣言します。12 // 状態変数は、その値がコントラクトのストレージに永続的に保存される変数です。13 // `public`キーワードは、変数をコントラクトの外部からアクセス可能にし、14 // 他のコントラクトやクライアントが値をアクセスするために呼び出すことができる関数を作成します。15 string public message;1617 // 多くのクラスベースのオブジェクト指向言語と同様に、コンストラクタは18 // コントラクトの作成時にのみ実行される特別な関数です。19 // コンストラクタは、コントラクトのデータを初期化するために使用されます。20 // 詳細はこちら: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constructors21 constructor(string memory initMessage) public {22 // 文字列引数`initMessage`を受け入れ、その値を23 // コントラクトの`message`ストレージ変数に設定します)。24 message = initMessage;25 }2627 // 文字列引数を受け入れ、28 // `message`ストレージ変数を更新するpublic関数です。29 function update(string memory newMessage) public {30 message = newMessage;31 }32}すべて表示トークン
1pragma solidity ^0.5.10;23contract Token {4 // `address`はEメールアドレスに似ています - イーサリアム上のアカウントを識別するために使用されます。5 // アドレスは、スマートコントラクトまたは外部(ユーザー)アカウントを表すことができます。6 // 詳細はこちら: https://solidity.readthedocs.io/en/v0.5.10/types.html#address7 address public owner;89 // `mapping`は、本質的にハッシュテーブルのデータ構造です。10 // この`mapping`は、符号なし整数(トークン残高)をアドレス(トークン保有者)に割り当てます。11 // 詳細はこちら: https://solidity.readthedocs.io/en/v0.5.10/types.html#mapping-types12 mapping (address => uint) balances;1314 // イベントにより、ブロックチェーン上のアクティビティをログに記録できます。15 // イーサリアムクライアントは、コントラクトの状態変更に反応するためにイベントをリッスンできます。16 // 詳細はこちら: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#events17 event Transfer(address from, address to, uint amount);1819 // コントラクトのデータを初期化し、`owner`を20 // コントラクト作成者のアドレスに設定します。21 constructor() public {22 // すべてのスマートコントラクトは、その関数をトリガーするために外部トランザクションに依存します。23 // `msg`は、送信者のアドレスやトランザクションに含まれるETHの量など、24 // 特定のトランザクションに関する関連データを含むグローバル変数です。25 // 詳細はこちら: https://solidity.readthedocs.io/en/v0.5.10/units-and-global-variables.html#block-and-transaction-properties26 owner = msg.sender;27 }2829 // 新しいトークンを作成し、アドレスに送信します。30 function mint(address receiver, uint amount) public {31 // `require`は、特定の条件を強制するために使用される制御構造です。32 // `require`ステートメントが`false`と評価された場合、例外がトリガーされ、33 // 現在の呼び出し中に行われた状態へのすべての変更が元に戻されます。34 // 詳細はこちら: https://solidity.readthedocs.io/en/v0.5.10/control-structures.html#error-handling-assert-require-revert-and-exceptions3536 // コントラクトのオーナーのみがこの関数を呼び出すことができます37 require(msg.sender == owner, "You are not the owner.");3839 // トークンの最大量を強制します40 require(amount < 1e60, "Maximum issuance exceeded");4142 // `receiver`の残高を`amount`だけ増やします43 balances[receiver] += amount;44 }4546 // 任意の呼び出し元からアドレスに既存のトークンを送信します。47 function transfer(address receiver, uint amount) public {48 // 送信者は送信するのに十分なトークンを持っている必要があります49 require(amount <= balances[msg.sender], "Insufficient balance.");5051 // 2つのアドレスのトークン残高を調整します52 balances[msg.sender] -= amount;53 balances[receiver] += amount;5455 // 先に定義されたイベントを発行します56 emit Transfer(msg.sender, receiver, amount);57 }58}すべて表示ユニークなデジタル資産
1pragma solidity ^0.5.10;23// 他のファイルから現在のコントラクトにシンボルをインポートします。4// このケースでは、OpenZeppelinの一連のヘルパーコントラクトです。5// 詳細はこちら: https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#importing-other-source-files67import "../node_modules/@openzeppelin/contracts/token/ERC721/IERC721.sol";8import "../node_modules/@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";9import "../node_modules/@openzeppelin/contracts/introspection/ERC165.sol";10import "../node_modules/@openzeppelin/contracts/math/SafeMath.sol";1112// `is`キーワードは、外部コントラクトから関数とキーワードを継承するために使用されます。13// このケースでは、`CryptoPizza`は`IERC721`と`ERC165`コントラクトから継承します。14// 詳細はこちら: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#inheritance15contract CryptoPizza is IERC721, ERC165 {16 // OpenZeppelinのSafeMathライブラリを使用して、算術演算を安全に実行します。17 // 詳細はこちら: https://docs.openzeppelin.com/contracts/2.x/api/math#SafeMath18 using SafeMath for uint256;1920 // Solidityの定数状態変数は他の言語に似ていますが、21 // コンパイル時に定数である式から代入する必要があります。22 // 詳細はこちら: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constant-state-variables23 uint256 constant dnaDigits = 10;24 uint256 constant dnaModulus = 10 ** dnaDigits;25 bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;2627 // Struct型を使用すると、独自の型を定義できます28 // 詳細はこちら: https://solidity.readthedocs.io/en/v0.5.10/types.html#structs29 struct Pizza {30 string name;31 uint256 dna;32 }3334 // Pizza構造体の空の配列を作成します35 Pizza[] public pizzas;3637 // ピザIDからそのオーナーのアドレスへのマッピング38 mapping(uint256 => address) public pizzaToOwner;3940 // オーナーのアドレスから所有トークン数へのマッピング41 mapping(address => uint256) public ownerPizzaCount;4243 // トークンIDから承認済みアドレスへのマッピング44 mapping(uint256 => address) pizzaApprovals;4546 // マッピングをネストすることができます。この例では、オーナーをオペレーターの承認にマッピングします47 mapping(address => mapping(address => bool)) private operatorApprovals;4849 // 文字列(名前)とDNAからランダムなピザを作成する内部関数50 function _createPizza(string memory _name, uint256 _dna)51 // `internal`キーワードは、この関数がこのコントラクトおよび52 // このコントラクトを派生するコントラクト内でのみ参照可能であることを意味します53 // 詳細はこちら: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#visibility-and-getters54 internal55 // `isUnique`は、ピザがすでに存在するかどうかをチェックする関数修飾子です56 // 詳細はこちら: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html#function-modifiers57 isUnique(_name, _dna)58 {59 // ピザをピザ配列に追加し、IDを取得します60 uint256 id = SafeMath.sub(pizzas.push(Pizza(_name, _dna)), 1);6162 // ピザのオーナーが現在のユーザーと同じであることを確認します63 // 詳細はこちら: https://solidity.readthedocs.io/en/v0.5.10/control-structures.html#error-handling-assert-require-revert-and-exceptions6465 // address(0)はゼロアドレスであり、66 // pizza[id]がまだ特定のユーザーに割り当てられていないことを示します。6768 assert(pizzaToOwner[id] == address(0));6970 // ピザをオーナーにマッピングします71 pizzaToOwner[id] = msg.sender;72 ownerPizzaCount[msg.sender] = SafeMath.add(73 ownerPizzaCount[msg.sender],74 175 );76 }7778 // 文字列(名前)からランダムなピザを作成します79 function createRandomPizza(string memory _name) public {80 uint256 randDna = generateRandomDna(_name, msg.sender);81 _createPizza(_name, randDna);82 }8384 // 文字列(名前)とオーナーのアドレス(作成者)からランダムなDNAを生成します85 function generateRandomDna(string memory _str, address _owner)86 public87 // `pure`とマークされた関数は、状態の読み取りや変更を行わないことを約束します88 // 詳細はこちら: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#pure-functions89 pure90 returns (uint256)91 {92 // 文字列(名前) + アドレス(オーナー)からランダムなuintを生成します93 uint256 rand = uint256(keccak256(abi.encodePacked(_str))) +94 uint256(_owner);95 rand = rand % dnaModulus;96 return rand;97 }9899 // オーナーによって見つかったピザの配列を返します100 function getPizzasByOwner(address _owner)101 public102 // `view`とマークされた関数は、状態を変更しないことを約束します103 // 詳細はこちら: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#view-functions104 view105 returns (uint256[] memory)106 {107 // `memory`ストレージの場所を使用して、この関数呼び出しの108 // ライフサイクル中のみ値を格納します。109 // 詳細はこちら: https://solidity.readthedocs.io/en/v0.5.10/introduction-to-smart-contracts.html#storage-memory-and-the-stack110 uint256[] memory result = new uint256[](ownerPizzaCount[_owner]);111 uint256 counter = 0;112 for (uint256 i = 0; i < pizzas.length; i++) {113 if (pizzaToOwner[i] == _owner) {114 result[counter] = i;115 counter++;116 }117 }118 return result;119 }120121 // ピザと所有権を他のアドレスに転送します122 function transferFrom(address _from, address _to, uint256 _pizzaId) public {123 require(_from != address(0) && _to != address(0), "Invalid address.");124 require(_exists(_pizzaId), "Pizza does not exist.");125 require(_from != _to, "Cannot transfer to the same address.");126 require(_isApprovedOrOwner(msg.sender, _pizzaId), "Address is not approved.");127128 ownerPizzaCount[_to] = SafeMath.add(ownerPizzaCount[_to], 1);129 ownerPizzaCount[_from] = SafeMath.sub(ownerPizzaCount[_from], 1);130 pizzaToOwner[_pizzaId] = _to;131132 // インポートされたIERC721コントラクトで定義されたイベントを発行します133 emit Transfer(_from, _to, _pizzaId);134 _clearApproval(_to, _pizzaId);135 }136137 /**138 * 指定されたトークンIDの所有権を別のアドレスに安全に転送します139 * ターゲットアドレスがコントラクトの場合、`onERC721Received`を実装する必要があります。140 * これは安全な転送時に呼び出され、マジック値を返します141 * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`;142 * そうでない場合、転送は取り消されます。143 */144 function safeTransferFrom(address from, address to, uint256 pizzaId)145 public146 {147 // solium-disable-next-line arg-overflow148 this.safeTransferFrom(from, to, pizzaId, "");149 }150151 /**152 * 指定されたトークンIDの所有権を別のアドレスに安全に転送します153 * ターゲットアドレスがコントラクトの場合、`onERC721Received`を実装する必要があります。154 * これは安全な転送時に呼び出され、マジック値を返します155 * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`;156 * そうでない場合、転送は取り消されます。157 */158 function safeTransferFrom(159 address from,160 address to,161 uint256 pizzaId,162 bytes memory _data163 ) public {164 this.transferFrom(from, to, pizzaId);165 require(_checkOnERC721Received(from, to, pizzaId, _data), "Must implement onERC721Received.");166 }167168 /**169 * ターゲットアドレスで`onERC721Received`を呼び出す内部関数170 * ターゲットアドレスがコントラクトでない場合、呼び出しは実行されません171 */172 function _checkOnERC721Received(173 address from,174 address to,175 uint256 pizzaId,176 bytes memory _data177 ) internal returns (bool) {178 if (!isContract(to)) {179 return true;180 }181182 bytes4 retval = IERC721Receiver(to).onERC721Received(183 msg.sender,184 from,185 pizzaId,186 _data187 );188 return (retval == _ERC721_RECEIVED);189 }190191 // ピザを燃やす - トークンを完全に破壊する192 // `external`関数修飾子は、この関数が193 // コントラクトインターフェースの一部であり、他のコントラクトがそれを呼び出すことができることを意味します194 function burn(uint256 _pizzaId) external {195 require(msg.sender != address(0), "Invalid address.");196 require(_exists(_pizzaId), "Pizza does not exist.");197 require(_isApprovedOrOwner(msg.sender, _pizzaId), "Address is not approved.");198199 ownerPizzaCount[msg.sender] = SafeMath.sub(200 ownerPizzaCount[msg.sender],201 1202 );203 pizzaToOwner[_pizzaId] = address(0);204 }205206 // アドレスごとのピザの数を返します207 function balanceOf(address _owner) public view returns (uint256 _balance) {208 return ownerPizzaCount[_owner];209 }210211 // IDで見つかったピザのオーナーを返します212 function ownerOf(uint256 _pizzaId) public view returns (address _owner) {213 address owner = pizzaToOwner[_pizzaId];214 require(owner != address(0), "Invalid Pizza ID.");215 return owner;216 }217218 // 他のアドレスがピザの所有権を転送することを承認します219 function approve(address _to, uint256 _pizzaId) public {220 require(msg.sender == pizzaToOwner[_pizzaId], "Must be the Pizza owner.");221 pizzaApprovals[_pizzaId] = _to;222 emit Approval(msg.sender, _to, _pizzaId);223 }224225 // 特定のピザの承認済みアドレスを返します226 function getApproved(uint256 _pizzaId)227 public228 view229 returns (address operator)230 {231 require(_exists(_pizzaId), "Pizza does not exist.");232 return pizzaApprovals[_pizzaId];233 }234235 /**236 * 指定されたトークンIDの現在の承認をクリアするプライベート関数237 * 指定されたアドレスがトークンのオーナーでない場合、取り消されます238 */239 function _clearApproval(address owner, uint256 _pizzaId) private {240 require(pizzaToOwner[_pizzaId] == owner, "Must be pizza owner.");241 require(_exists(_pizzaId), "Pizza does not exist.");242 if (pizzaApprovals[_pizzaId] != address(0)) {243 pizzaApprovals[_pizzaId] = address(0);244 }245 }246247 /*248 * 指定されたオペレーターの承認を設定または解除します249 * オペレーターは、送信者に代わってすべてのトークンを転送することが許可されます250 */251 function setApprovalForAll(address to, bool approved) public {252 require(to != msg.sender, "Cannot approve own address");253 operatorApprovals[msg.sender][to] = approved;254 emit ApprovalForAll(msg.sender, to, approved);255 }256257 // オペレーターが指定されたオーナーによって承認されているかどうかを通知します258 function isApprovedForAll(address owner, address operator)259 public260 view261 returns (bool)262 {263 return operatorApprovals[owner][operator];264 }265266 // ピザの所有権を取得する - 承認されたユーザーのみ267 function takeOwnership(uint256 _pizzaId) public {268 require(_isApprovedOrOwner(msg.sender, _pizzaId), "Address is not approved.");269 address owner = this.ownerOf(_pizzaId);270 this.transferFrom(owner, msg.sender, _pizzaId);271 }272273 // ピザが存在するかどうかを確認します274 function _exists(uint256 pizzaId) internal view returns (bool) {275 address owner = pizzaToOwner[pizzaId];276 return owner != address(0);277 }278279 // アドレスがオーナーであるか、ピザの転送が承認されているかを確認します280 function _isApprovedOrOwner(address spender, uint256 pizzaId)281 internal282 view283 returns (bool)284 {285 address owner = pizzaToOwner[pizzaId];286 // 以下によるソリウムチェックの無効化287 // https://github.com/duaraghav8/Solium/issues/175288 // solium-disable-next-line operator-whitespace289 return (spender == owner ||290 this.getApproved(pizzaId) == spender ||291 this.isApprovedForAll(owner, spender));292 }293294 // ピザがユニークでまだ存在しないかを確認します295 modifier isUnique(string memory _name, uint256 _dna) {296 bool result = true;297 for (uint256 i = 0; i < pizzas.length; i++) {298 if (299 keccak256(abi.encodePacked(pizzas[i].name)) ==300 keccak256(abi.encodePacked(_name)) &&301 pizzas[i].dna == _dna302 ) {303 result = false;304 }305 }306 require(result, "Pizza with such name already exists.");307 _;308 }309310 // ターゲットアドレスがコントラクトであるかどうかを返します311 function isContract(address account) internal view returns (bool) {312 uint256 size;313 // 現在、アドレスにコントラクトがあるかどうかを確認するのに、314 // そのアドレスのコードのサイズを確認するより良い方法はありません。315 // これがどのように機能するかについての詳細は、https://ethereum.stackexchange.com/a/14016/36603316 // を参照してください。317 // TODO Serenityリリースの前にこれを再確認してください。すべての318 // アドレスがコントラクトになるためです。319 // solium-disable-next-line security/no-inline-assembly320 assembly {321 size := extcodesize(account)322 }323 return size > 0;324 }325}すべて表示参考リンク
スマートコントラクトの全体的な概要については、SolidityとVyperのドキュメントをご確認ください。
関連トピック
関連チュートリアル
- コントラクトサイズ制限と戦うためのコントラクトの縮小 – スマートコントラクトのサイズを縮小するための実践的なヒント。
- イベントを使用してスマートコントラクトからデータをログに記録する – スマートコントラクトのイベントの紹介と、それらを使用してデータをログに記録する方法。
- Solidityから他のコントラクトと対話する – 既存のコントラクトからスマートコントラクトをデプロイし、それと対話する方法。