現役エンジニアが教えるSolidityの基礎

# 概要

Solidityは、Ethereumブロックチェーン上で動作する分散アプリケーション（dApps）を開発するためのスマートコントラクト言語です。この記事では、Solidityの基本的な概念と用法について解説します。

Solidityとは？
-----------

Solidityは、スマートコントラクト言語です。Viatalik Buterin氏によって作成されたイーサリアムネットワークが使用されます。Solidityは、EVM上のスマートコントラクトの実装に使用されます。

EVMとは
-----------
EVM（Ethereum Virtual Machine）は、分散アプリケーションとスマートコントラクトの実行環境であり、Ethereum上で動作するDApps(Distributed Applications)の重要な要素です。

EVMはSolidityなどのスマートコントラクト用の高水準言語で記述されたコードを、Ethereumネットワークで実行可能な機械語バイトコードにコンパイルすることができます。

EVM互換のブロックチェーンネットワークにはSolidityのソースコードが使えます。
EVM互換のブロックチェーンネットワークには、以下のようなものがあります。

- Ethereum
- Binance Smart Chain
- Polygon(Matic)
- xDai
- Optimism
- Arbitrum

スマートコントラクトとは？
-------------

スマートコントラクトは、ブロックチェーン上に配置される自己実行コードです。コードは条件に基づいて自動的に実行され、相手に支払われたり、特定の条件を満たした場合にアクションが実行されることがあります。たとえば、スマートコントラクトを使って、不動産取引や投票プロセスを自動化することができます。

Solidityの文法
-----------

Solidityの文法は、他のプログラム言語に似ています。たとえば、変数を宣言する方法、関数を宣言する方法、制御フローを制御する方法が含まれています。

### 変数の宣言

Solidityでは、以下のようにして変数を宣言できます：

```solidity
 uint x = 10;
 string name = "John";
```

### 関数宣言

Solidityでは、以下のようにして関数を宣言できます：

```solidity
function add(uint x, uint y) public returns (uint) {
  return x + y;
}
```

### スマートコントラクト宣言
```
contract HelloWorld {
  string public message;

  constructor(string memory initMessage) {
    message = initMessage;
  }

  function setMessage(string memory newMessage) public {
    message = newMessage;
  }
}
```

### 制御フロー

制御フローは、条件によってプログラムの挙動を変更するために使用されます。Solidityでは、一般的なif-else文が含まれており、forまたはwhileループもサポートされています。

```solidity
uint inputNumber = 100;

if (inputNumber == 100) {
    // trueの処理
} else {
   // falseの処理
}

for (uint i = 0; i < 10; i++) {
    // 繰り返し処理
}

while (true) {
    // 条件がtrueである限り繰り返す
}
```


## データ型

*   **ブール値 (Boolean)** : `true` か `false` のどちらかを表します。
*   **整数 (Integer)** : 符号付き、符号なしのいずれかを指定できます。例えば、`int8`, `int256`, `uint64` などが挙げられます。
*   **バイト (Byte)** : `byte` と `bytes` の二種類があります。 `byte` 型は1バイト(8ビット）を持つ完全に符号なしの整数で、 `bytes` 型は任意の長さのバイト列を表します。
*   **アドレス (Address)** : Ethereumネットワークに参加しているアカウントを示す20バイトの16進数表現です。
*   **配列 (Array)** : 同じ型を持つ変数のリストを意味します。固定サイズのもの (`uint[6]`) もあれば、可変長サイズのもの (`uint[]`) もあります。
*   **文字列 (String)** : 可変長の UTF-8 エンコード文字列を表します。
*   **構造体 (Struct)** : 複数の異なる型の変数が必要な場合に使用されます。C言語の構造体に似ています。
*   **関数 (Function)** : Solidityでは、関数もオブジェクトであり、他のオブジェクト（例えば、また別の関数）から参照されることができます。関数を表す型として、 `function` があります。
他にもあるようですが、これらは基礎的なデータ型の一部です。


## スマートコントラクト実装手順

Solidityでスマートコントラクトを実装するには、以下のような手順が必要です。

1.  Solidityファイルの作成: Contractを定義したSolidityファイルを作成します。  
    例えば、`Hello World`Contractを作る場合は `HelloWorld.sol` というファイル名を使用します。

```solidity
pragma solidity ^0.8.0;

contract HelloWorld {
  string public message;

  constructor(string memory initMessage) {
    message = initMessage;
  }

  function setMessage(string memory newMessage) public {
    message = newMessage;
  }
}
```

2.  ソースコードのコンパイル: SolidityファイルをEthereum Virtual Machine(EVM)バイトコードに変換します。これにより、SmartContractを実行可能なバイナリにすることができます。
    
3.  EVM上でContractをデプロイ: Solidityソースコードをコンパイルし、そのバイトコードをEVMに移行して、契約をデプロイします。本番Ethereumネットワークでデプロイする前に、テストネットワーク（Rinkeby、Kovanh、Ropsten）などのテスト環境でテストすることをお勧めします。
    
4.  Web3や他のクライアントからの接続: Web3.jsやTruffleなどの各種Ethereumクライアントライブラリを使用してSmart Contractに接続することができます。これにより、JavaScriptから契約関数を呼び出すことができます。
    

以上が、SolidityでContractを実装するための手順です。

## スマートコントラクトを作成し、デプロイする方法
Solidityを使用してスマートコントラクトを作成し、デプロイするためには、以下の手順が必要です。

[Remix IDE](https://remix.ethereum.org/)を開いて、「新しいファイル」を選択します。
コントラクトを作成します。お好みの名前を入力し、.sol拡張子で保存します。
コントラクトの実装を行います。引数や戻り値、関数、状態変数、イベントなどを定義します。
「Run」タブに移動し、「Create」または「Deploy」を選択して、コントラクトを発行できます。
ガスとGweiの価格を調整し、マイニング対象のネットワーク（Rinkeby、ROPSTENなど）を指定します。
トランザクションの発生前にWalletと接続します。特定のウォレットに接続する方法についてのRemixのドキュメントを参照してください。
デプロイに関する情報を表示して、トランザクションの発生を確認し、トランザクションの完了を待ちます。
以上の手順で Solidity を使用したスマートコントラクトをデプロイすることができます。ただし、スマートコントラクトに固有の問題がある場合、発生したエラーを解決するために追加の調査が必要になる場合もあります。

## Solidityのスマートコントラクトをweb3.jsで呼び出す
Solidityのスマートコントラクトをweb3.jsで呼び出すには、以下の手順が必要です。

1.  web3.jsライブラリとWeb3オブジェクトをインポートする。

```javascript
const Web3 = require('web3');
const web3 = new Web3('https://ropsten.infura.io/v3/YOUR-PROJECT-ID');
```

2.  デプロイされたSolidityスマートコントラクトのアビを取得する。

```javascript
const contractABI = [{
  "constant": true,
  "inputs": [],
  "name": "getTotalSupply",
  "outputs": [{ "name": "", "type": "uint256", "value": "1000" }],
  "payable": false,
  "stateMutability": "view",
  "type": "function"
}];
```

3.  アドレスでデプロイされたスマートコントラクトのインスタンスを生成する。

```javascript
const contractAddress = "0x123456...";
    
const myContract = new web3.eth.Contract(contractABI, contractAddress);
```

4.  スマートコントラクトのメソッドを呼び出して、結果を受け取ります。

```javascript
myContract.methods.getTotalSupply().call()
    .then(result => console.log(result))
    .catch(error => console.error(error));
```

これらの手順に従って、web3.jsでSolidityスマートコントラクトを呼び出すことができます。ただし、この例ではRopstenテストネットワークを使用し、Infuraから提供されるAPIキーを使用しています。実際のアプリケーションでは、適切なテストネットワークや自身でEthereumノードを立ち上げる必要があることに注意してください。

# 代表的なスマートコントラクト

## ERC20
ERC20とは、イーサリアム（Ethereum）ブロックチェーン上で基盤通貨を含むトークンを発行するための仕様です。 ERC20トークンを発行することで、プロジェクトや企業は自身のブランドに基づく通貨を作成し、ICOなどの目的で使用することができます。


このスマートコントラクトでは、代表的なERC20関数が実装されています。具体的には`transfer`, `approve`, `transferFrom` の3つです。

*   `transfer`：私たちが他の人にトークンを送りたい場合に使用する関数です。
*   `approve`: 一定の数量のトークンを第三者に委任するために使用されます。ここでは新しいオーナーが定義されたaddress `_spender` に我々が議決で指定した `_value` の金額を許可します。
*   `transferFrom`: 前2つの関数を組み合わせたものであり、サードパーティーまたはトークンの所有者自身からの払い出しを許可します。

https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC20

## ERC721
ERC721はNFTに使われているスマートコントラクトです。
NFTは、不可分割なトークン（Non-Fungible Token）の略で、特定のデジタルアセットを表すために使用されます。これらのアセットには、写真、音楽、動画、バーチャルプロパティ、およびゲームアイテムなどが含まれます。 Ethereumブロックチェーンネットワーク上でNFTを作成したい場合、Solidityでスマートコントラクトを実装することが一般的です。以下に、SolidityでNFTスマートコントラクトを実装する例を挙げます。

```solidity
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";

contract MyNFT is ERC721 {
    constructor()
        ERC721("MyNFT", "MNFT")
    {}
    
    struct File {
        string fileType;      
        string fileName; 
    }
    
    mapping(uint256 => File) public files;
    
    function mint(address owner, string memory fileType, string memory fileName) public returns (uint256 tokenId) {
        _tokenIds.increment();
        
        tokenId = _tokenIds.current();
        _mint(owner, tokenId);
        
        files[tokenId] = File(fileType, fileName);
        
        return tokenId;
    }
}
```

このスマートコントラクトは、ERC721標準を使用してNFTを定義します。ファイルの詳細を格納するFileという新しい構造体を定義し、filesというマッピングにNFT IDに応じたファイルを蓄積します。 また、`mint()`関数を使用してトークンを鋳造します（つまり、NFTを作成します）。この関数では、ERC721から継承した`_mint()`関数を使用して、NFTをエンドユーザーに発行し、そのNFTに関連する情報をマッピングに追加します。

https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC721


まとめ
--

これらはSolidityの基本的な概念と用法についての簡単な説明でした。

もっと詳しく知りたい人は公式ドキュメントを見てください

https://docs.soliditylang.org/en/v0.8.19/


実装の依頼や相談は[こちら](https://docs.google.com/forms/d/e/1FAIpQLSewSJGBn0WCJcJ8XOHvdXYXCEgM9foP9-dGdBbXPbU-ygDQjQ/viewform)からお問い合わせください