⛓️

Rubyを使ってEthereumネットワークに接続してスマートコントラクトをデプロイし、実行する

2023/01/03に公開

はじめに

本業は投資家をやりつつ、日本のNFTを盛り上げてます
https://twitter.com/i/events/1439793574602625028

前提

そういや、Ethereumネットワークに接続して
Rubyでスマートコントラクトを実行する例の記事ってないよな? と思い書くことにしました
(あっても ethereum.rb を使用した例しかない)

ethereum.rb より、 eth.rb 使おうぜ って公式も言ってるので
eth.rb 使います

https://ethereum.org/en/developers/docs/programming-languages/ruby/

と、言っても

It is not only a rewrite of the eth gem but also a partial merge of the ethereum gem by Marek Kirejczyk and Yuta Kurotaki.
https://github.com/EthWorks/ethereum.rb (MIT)

なので、そんなに変わらないですが

インストール周りも含め書いてみました

Gethのインストール

Golang製Ethereumクライアント
https://github.com/ethereum/go-ethereum

brew tap ethereum/ethereum
brew install ethereum

プライベートネットワークの作成

ディレクトリ作成

mkdir -p dev/eth/privatenet

genesis.json作成

vim genesis.json
{
  "config": {
    "chainId": 1234,
    "homesteadBlock": 0,
    "eip150Block": 0,
    "eip155Block": 0,
    "eip158Block": 0,
    "byzantiumBlock": 0,
    "constantinopleBlock": 0,
    "petersburgBlock": 0,
    "istanbulBlock": 0,
    "berlinBlock": 0,
    "londonBlock": 0
  },
  "alloc": {},
  "coinbase": "0x0000000000000000000000000000000000000000",
  "difficulty": "0x200",
  "extraData": "",
  "gasLimit": "0xffffffff",
  "nonce": "0x0000000000000042",
  "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "timestamp": "0x00"
}

chainId

ディレクトリ

/dev/eth
└── privatenet
    ├── genesis.json

ここからの注意点

datadir などの指定に関わるので、全てカレントディレクトリに注意しながら実行する

Geth init

geth --datadir eth/privatenet init eth/privatenet/genesis.json

Gethをフォアグラウンドで起動

geth --networkid 4649 --nodiscover --maxpeers 0 --datadir eth/privatenet console

アカウント作成

personal.newAccount("password_1")
> eth.getBalance(eth.coinbase)
0

マイニングの開始

> miner.start(1)
null
> eth.mining
true
> eth.blockNumber
0
> eth.getBalance(eth.coinbase)
18000000000000000000
> eth.blockNumber
15
> miner.stop()
null

gemのインストール

https://github.com/q9f/eth.rb

gem install eth

Can't exec "aclocal": No such file or directory が出た場合は

brew instal automake

Solidityのインストール

brew install solidity

RPCオプションを設定してGethを起動

geth --networkid 4649 --nodiscover --maxpeers 0 --datadir eth/privatenet --http --http.api "eth, net, web3, personal" --http.addr "localhost" --http.port "8545" --http.corsdomain "*" console

コントラクト作成

vim address_storage.sol
pragma solidity ^0.8;

contract AddressStorage {

  address myAddress;
  
  function storeMyAddress(address addr) public {
    myAddress = addr;
  }

  function retrieveMyAddress() public view returns (address){
    return myAddress;
  }
}

eth.rb の疎通を確認

require 'eth'
client = Eth::Client.create 'http://127.0.0.1:8545'
address = Eth::Address.new('0xc3e90b387f026bf7b293f8faf7e87c57399fef0f')
balance = client.eth_get_balance(address)['result'].to_i(16)
=> 36000000000000000000
> eth.getBalance(eth.coinbase)
36000000000000000000

コントラクトをデプロイ

client = Eth::Client.create 'http://127.0.0.1:8545'   
contract = Eth::Contract.from_file(file: 'eth/privatenet/address_storage.sol')
client.deploy_and_wait(contract)

コントラクトのメソッドを実行

client.transact_and_wait(contract, 'storeMyAddress', '0xc427556a14de0d2ed4e1cfd10b30ab75c1360ecd')
=> "0x58c583806999f94961b4fa24ddbdd48b99e1dbc59b8ea5bd241969f0400a8990"
irb(main):053:0> client.call(contract, 'retrieveMyAddress')
=> "0xc427556a14de0d2ed4e1cfd10b30ab75c1360ecd"

Discussion