ethereum.rb 1.6.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 847343b8aaa240f07a46b58d0423fdc1ac3e368b
4
- data.tar.gz: 8610cf63893eaf0686cd5230156bc6e29c020d1f
3
+ metadata.gz: c4bfce795e5c0ba5c86e8731f2f7c04504b53000
4
+ data.tar.gz: 52feb089966aabb77b7a1002d5a8aff8433049dd
5
5
  SHA512:
6
- metadata.gz: a0b703025e50dacbf4448209709563e4075ff4176d6d01129925f975b9e9f3b68c1dcf1e6febe21bee10ef885814844273a593ac39533ce4561f0baad63e480e
7
- data.tar.gz: 149a4faa03278bbed430632dba56ed4ef8d1b5ca84440244af1caadfe2cae17ecfc3f51f4fd8a69894eebee6f10c983946dfdeddd60d67d9d32fd4ab8cc52fcf
6
+ metadata.gz: 40ff1fe3ac72b9f4676eb5350c1ada0e31ebcf9778eeab3b5d80036f5d4a8c0cc854d3988f4a11d044788ffadee6482ca5d0bf2e7c31e600521de045f9d93902
7
+ data.tar.gz: 69eb7f4a2a31e04a883d0b266211fd13e411790afc9105e884494464e508db60fd4363e9f970aef9afb26b153501e1f35c89e4bf8dc456951c5f2da569d31b6b
@@ -2,6 +2,12 @@ dist: trusty
2
2
  language: ruby
3
3
  rvm:
4
4
  - 2.3.1
5
+ env:
6
+ - PARITY="1.4.8"
7
+ - PARITY="1.5.0"
8
+ matrix:
9
+ allow_failures:
10
+ - env: PARITY="1.5.0"
5
11
  cache:
6
12
  bundler: true
7
13
  directories:
@@ -10,15 +16,15 @@ before_install:
10
16
  - sudo bin/install_parity
11
17
  - gem install bundler -v 1.11.2
12
18
  before_script:
13
- - parity --chain ~/.parity/ropsten.json --warp --password ~/.parity/pass --unlock 21e72c12878136d9349c77c1645deef121ee8926 --author 21e72c12878136d9349c77c1645deef121ee8926 daemon ~/.parity.pid --log-file ~/.parity.log
19
+ - parity --chain ~/.parity/ropsten.json --warp --password ~/.parity/pass --unlock 3089630d06fD90Ef48a0c43f000971587c1F3247 --author 3089630d06fD90Ef48a0c43f000971587c1F3247 daemon ~/.parity.pid --log-file ~/.parity.log
20
+ - cat ~/.parity.log
14
21
  - sleep 5
15
22
  - parity --chain ~/.parity/ropsten.json account list
16
23
  - cat ~/.parity.log
17
24
  - bundle exec rake ethereum:node:waitforsync
18
25
  - bundle exec rake ethereum:test:setup
19
26
  script:
20
- - bundle exec rspec --tag ~slow
21
- - bundle exec rspec --tag slow
27
+ - bundle exec rspec --tag ~blockchain && bundle exec rspec --tag blockchain
22
28
  before_cache:
23
29
  - killall parity
24
30
  - sleep 3
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
- # Ethereum.rb
1
+ # Ethereum Ruby library - Ethereum.rb
2
2
 
3
- [![Build Status](https://travis-ci.org/marekkirejczyk/ethereum.rb.svg?branch=master)](https://travis-ci.org/marekkirejczyk/ethereum.rb) [![security](https://hakiri.io/github/NullVoxPopuli/MetaHash/master.svg)](https://hakiri.io/github/NullVoxPopuli/MetaHash/master) [![Dependency Status](https://gemnasium.com/marekkirejczyk/ethereum.rb.svg)](https://gemnasium.com/marekkirejczyk/ethereum.rb)
3
+ [![Build Status](https://travis-ci.org/marekkirejczyk/ethereum.rb.svg?branch=master)](https://travis-ci.org/marekkirejczyk/ethereum.rb) [![security](https://hakiri.io/github/NullVoxPopuli/MetaHash/master.svg)](https://hakiri.io/github/NullVoxPopuli/MetaHash/master) [![Dependency Status](https://gemnasium.com/marekkirejczyk/ethereum.rb.svg)](https://gemnasium.com/marekkirejczyk/ethereum.rb) [![Code Climate](https://codeclimate.com/github/marekkirejczyk/ethereum.rb/badges/gpa.svg)](https://codeclimate.com/github/marekkirejczyk/ethereum.rb)
4
4
 
5
- A simple library for Ethereum.
5
+ A ruby gem for interacting with Ethereum.
6
6
 
7
7
  ## Highlights
8
8
 
@@ -36,7 +36,7 @@ To be able to compile [solidity](https://github.com/ethereum/solidity) contracts
36
36
  Add this line to your application's Gemfile:
37
37
 
38
38
  ```ruby
39
- gem 'ethereum'
39
+ gem 'ethereum.rb'
40
40
  ```
41
41
 
42
42
  And then execute:
@@ -45,7 +45,7 @@ And then execute:
45
45
 
46
46
  Or install it yourself as:
47
47
 
48
- $ gem install ethereum
48
+ $ gem install ethereum.eb
49
49
 
50
50
  ## Basic Usage
51
51
 
@@ -72,44 +72,47 @@ By default logging is on and logs are saved in "/tmp/ethereum_ruby_http.log".
72
72
  You can create contract from solidity source and deploy it to the blockchain.
73
73
 
74
74
  ```ruby
75
- contract = Ethereum::Contract.from_file("mycontract.sol", client)
76
- contract_instance = contract.deploy_and_wait
75
+ contract = Ethereum::Contract.create(file: "mycontract.sol", client: client)
76
+ address = contract.deploy_and_wait
77
77
  ```
78
78
 
79
79
  Deployment may take up to couple minutes.
80
- Or with more complex syntax (might be useful if you want to complie multiple contracts at once):
80
+ If you want to complie multiple contracts at once, you can create new instances using newly declared clasess:
81
81
 
82
82
  ```ruby
83
- init = Ethereum::Initializer.new("mycontract.sol", client)
84
- init.build_all
83
+ Ethereum::Contract.create(file: "mycontract.sol", client: client)
85
84
  contract = MyContract.new
86
- contract_instance = contract.deploy_and_wait(60)
85
+ contract = contract.deploy_and_wait
87
86
  ```
88
87
 
89
- Note that contract variable holds the reference to contract code, while contract_instance holds refernce to contract deployed to the blockchain. You can call contract functions on contract_instance as described in sections "Transacting and Calling Solidity Functions".
90
-
91
88
  All names used to name contract in solidity source will transalte to name of classes in ruby (camelized).
92
89
  If class of given name exist it will be undefined first to avoid name collision.
93
90
 
94
91
  ### Get contract from blockchain
95
92
 
96
93
  The other way to obtain contract instance is get one form the blockchain. To do so you need a contract name, contract address and ABI definition.
94
+ `client` parameter is optional.
97
95
 
98
96
  ```ruby
99
- contract_instance = Ethereum::Contract.from_blockchain("MyContract", "0x01a4d1A62F01ED966646acBfA8BB0b59960D06dd ", abi, client)
100
-
97
+ contract = Ethereum::Contract.create(name: "MyContract", address: "0x01a4d1A62F01ED966646acBfA8BB0b59960D06dd ", abi: abi, client: client)
101
98
  ```
102
99
 
103
100
  Note that you need to specify contract name, that will be used to define new class in ruby, as it is not a part of ABI definition.
104
101
 
102
+ If you want to create new contract, that is not yet deployed from ABI definition you need to supply binary code too:
103
+
104
+ ```ruby
105
+ contract = Ethereum::Contract.create(name: "MyContract", address: "0x01a4d1A62F01ED966646acBfA8BB0b59960D06dd ", abi: abi, code: "...")
106
+ ```
107
+
105
108
  ### Transacting and Calling Solidity Functions
106
109
 
107
- Solidity functions are exposed using the following conventions:
110
+ Functions defined in a contract are exposed using the following conventions:
108
111
 
109
112
  ```
110
- transact_[function_name](params)
111
- transact_and_wait_[function_name](params)
112
- call_[function_name](params)
113
+ contract.transact.[function_name](params)
114
+ contract.transact_and_wait.[function_name](params)
115
+ contract.call.[function_name](params)
113
116
  ```
114
117
 
115
118
  **Example Contract in Solidity**
@@ -127,27 +130,23 @@ contract SimpleNameRegistry {
127
130
  }
128
131
  ```
129
132
 
130
- ```ruby
131
- simple_name_registry_instance.transact_and_wait_register("0x5b6cb65d40b0e27fab87a2180abcab22174a2d45", "minter.contract.dgx")
132
- simple_name_registry_instance.transact_register("0x385acafdb80b71ae001f1dbd0d65e62ec2fff055", "anthony@eufemio.dgx")
133
- simple_name_registry_instance.call_get_some_value("0x385acafdb80b71ae001f1dbd0d65e62ec2fff055")
134
- simple_name_registry_instance.call_my_mapping("0x385acafdb80b71ae001f1dbd0d65e62ec2fff055")
135
- ```
136
-
137
- ### Run contracts using a different address
133
+ And here is how to access it's methods:
138
134
 
139
135
  ```ruby
140
- simple_name_registry_instance.as("0x0c0d99d3608a2d1d38bb1b28025e970d3910b1e1")
136
+ contract.transact_and_wait.register("0x5b6cb65d40b0e27fab87a2180abcab22174a2d45", "minter.contract.dgx")
137
+ contract.transact.register("0x385acafdb80b71ae001f1dbd0d65e62ec2fff055", "anthony@eufemio.dgx")
138
+ contract.call.get_some_value("0x385acafdb80b71ae001f1dbd0d65e62ec2fff055")
141
139
  ```
142
140
 
143
- ### Point contract instance to a previously deployed contract
141
+ Note that as `register` method will change contract state, so you need to use `transact` family of methods (or `transact_and_wait` for synchronous version) to call it.
142
+
143
+ For method like `getSomeValue`, that does not affect state of the contract (and don't need to propagate change to blockchain therefore) you can use call method. It will retrive value from local copy of the blockchain.
144
144
 
145
- ```ruby
146
- simple_name_registry_instance.at("0x734533083b5fc0cd14b7cb8c8eb6ed0c9bd184d3")
147
- ```
148
145
 
149
146
  ## Utils rake tasks
150
147
 
148
+ There is plenty of useful rake tasks for interacting with blockchain:
149
+
151
150
  ```ruby
152
151
  rake ethereum:contract:compile[path] # Compile a contract / Compile and deploy contract
153
152
  rake ethereum:node:mine # Mine ethereum testing environment for ethereum node
@@ -160,7 +159,7 @@ rake ethereum:transaction:send[address,amount] # Send [amount of] ether to an a
160
159
  ```
161
160
 
162
161
  ## Debbuging
163
- Logs from communication with node are available under following path:
162
+ Logs from communication between ruby app and node are available under following path:
164
163
  ```
165
164
  /tmp/ethereum_ruby_http.log
166
165
  ```
@@ -171,13 +170,13 @@ After checking out the repo, run `bin/setup` to install dependencies.
171
170
  Make sure `rake ethereum:test:setup` passes before running tests.
172
171
  Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
173
172
 
173
+ You need ethereum node up and running for tests to pass and it needs to be working on testnet (Ropsten).
174
+
174
175
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
175
176
 
176
- ## Ethereum ruby
177
+ ## Acknowledgements and license
177
178
 
178
179
  This library has been forked from [ethereum-ruby](https://github.com/DigixGlobal/ethereum-ruby) by DigixGlobal Pte Ltd (https://dgx.io).
179
180
 
180
- ## License
181
-
182
181
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
183
182
 
@@ -1,29 +1,21 @@
1
1
  #!/bin/bash
2
2
 
3
- install_parity () {
4
- sudo add-apt-repository ppa:ethereum/ethereum -y
5
- sudo apt-get update
6
- sudo apt-get install solc
7
- wget http://d1h4xl4cr1h0mo.cloudfront.net/v1.4.8/x86_64-unknown-linux-gnu/parity_1.4.8_amd64.deb
8
- sudo dpkg -i parity_1.4.8_amd64.deb
9
- }
10
-
11
-
12
-
13
3
  echo "Installing parity..."
4
+ sudo add-apt-repository ppa:ethereum/ethereum -y
5
+ sudo apt-get update
6
+ sudo apt-get install solc
7
+ sudo apt-get -y install libssl-dev
8
+ echo "Solc version"
9
+ solc --version
10
+ wget http://d1h4xl4cr1h0mo.cloudfront.net/v$PARITY\/x86_64-unknown-linux-gnu/parity_$PARITY\_amd64.deb
11
+ sudo dpkg -i parity_$PARITY\_amd64.deb
14
12
 
15
- if [ `which parity` ]; then
16
- echo "Parity cached, skipping"
17
- install_parity
18
- else
19
- echo "Settuping parity..."
20
- install_parity
21
- mkdir -p ~/.parity
22
- wget https://raw.githubusercontent.com/ethcore/parity/master/ethcore/res/ethereum/ropsten.json --output-document ~/.parity/ropsten.json
23
- echo $pass > ~/.parity/pass
24
- mkdir -p ~/.parity/keys
25
- echo $wallet > ~/.parity/keys/10890ad6-5171-4945-be95-984d83394120
26
- chown -R travis:travis ~/.parity
27
- fi
13
+ echo "Setuping parity..."
14
+ mkdir -p ~/.parity
15
+ wget https://raw.githubusercontent.com/ethcore/parity/master/ethcore/res/ethereum/ropsten.json --output-document ~/.parity/ropsten.json
16
+ echo $pass > ~/.parity/pass
17
+ mkdir -p ~/.parity/keys
18
+ echo $wallet > ~/.parity/keys/UTC--2017-01-08T21-02-29.039669388Z--3089630d06fd90ef48a0c43f000971587c1f3247
19
+ chown -R travis:travis ~/.parity
28
20
 
29
21
  ls -la ~/.parity
@@ -4,6 +4,7 @@ require 'active_support/core_ext'
4
4
  require 'digest/sha3'
5
5
 
6
6
  module Ethereum
7
+ require 'ethereum/abi'
7
8
  require 'ethereum/client'
8
9
  require 'ethereum/ipc_client'
9
10
  require 'ethereum/http_client'
@@ -15,6 +16,8 @@ module Ethereum
15
16
  require 'ethereum/function_input'
16
17
  require 'ethereum/function_output'
17
18
  require 'ethereum/contract_event'
19
+ require 'ethereum/encoder'
20
+ require 'ethereum/decoder'
18
21
  require 'ethereum/formatter'
19
22
  require 'ethereum/transaction'
20
23
  require 'ethereum/deployment'
@@ -0,0 +1,18 @@
1
+ module Ethereum
2
+ class Abi
3
+
4
+ def self.parse_abi(abi)
5
+ constructor_inputs = abi.detect {|x| x["type"] == "constructor"}["inputs"] rescue nil
6
+ functions = abi.select {|x| x["type"] == "function" }.map { |fun| Ethereum::Function.new(fun) }
7
+ events = abi.select {|x| x["type"] == "event" }.map { |evt| Ethereum::ContractEvent.new(evt) }
8
+ [constructor_inputs, functions, events]
9
+ end
10
+
11
+ def self.parse_type(type)
12
+ raise NotImplementedError if type.ends_with?("]")
13
+ match = /(\D+)(\d.+)?/.match(type)
14
+ [match[1], match[2]]
15
+ end
16
+
17
+ end
18
+ end
@@ -1,266 +1,211 @@
1
1
  module Ethereum
2
2
  class Contract
3
3
 
4
- DEFAULT_GAS_PRICE = 60000000000
4
+ attr_reader :address
5
+ attr_accessor :code, :name, :abi, :class_object, :sender, :deployment, :client
6
+ attr_accessor :events, :functions, :constructor_inputs
7
+ attr_accessor :call_raw_proxy, :call_proxy, :transact_proxy, :transact_and_wait_proxy
8
+ attr_accessor :new_filter_proxy, :get_filter_logs_proxy, :get_filter_change_proxy
5
9
 
6
- DEFAULT_GAS = 3000000
7
-
8
- attr_accessor :code, :name, :functions, :abi, :constructor_inputs, :events, :class_object
9
-
10
- def initialize(name, code, abi)
10
+ def initialize(name, code, abi, client = Ethereum::Singleton.instance)
11
11
  @name = name
12
12
  @code = code
13
13
  @abi = abi
14
- @functions = []
15
- @events = []
16
- @constructor_inputs = @abi.detect {|x| x["type"] == "constructor"}["inputs"] rescue nil
17
- @abi.select {|x| x["type"] == "function" }.each do |abifun|
18
- @functions << Ethereum::Function.new(abifun)
19
- end
20
- @abi.select {|x| x["type"] == "event" }.each do |abievt|
21
- @events << Ethereum::ContractEvent.new(abievt)
22
- end
14
+ @constructor_inputs, @functions, @events = Ethereum::Abi.parse_abi(abi)
15
+ @formatter = Ethereum::Formatter.new
16
+ @client = client
17
+ @sender = client.default_account
18
+ @encoder = Encoder.new
19
+ @decoder = Decoder.new
23
20
  end
24
21
 
25
- def self.from_file(path, client = Ethereum::Singleton.instance)
26
- @init = Ethereum::Initializer.new(path, client)
27
- contracts = @init.build_all
28
- raise "No contracts complied" if contracts.empty?
29
- contracts.first.class_object.new
30
- end
31
-
32
- def self.from_blockchain(name, address, abi, client = Ethereum::Singleton.instance)
33
- contract = Ethereum::Contract.new(name, nil, abi)
34
- contract.build(client)
35
- contract_instance = contract.class_object.new
36
- contract_instance.at address
37
- contract_instance
22
+ def self.create(file: nil, client: Ethereum::Singleton.instance, code: nil, abi: nil, address: nil, name: nil)
23
+ contract = nil
24
+ if file.present?
25
+ contracts = Ethereum::Initializer.new(file, client).build_all
26
+ raise "No contracts complied" if contracts.empty?
27
+ contract = contracts.first.class_object.new
28
+ else
29
+ abi = JSON.parse(abi) if abi.is_a? String
30
+ contract = Ethereum::Contract.new(name, code, abi, client)
31
+ contract.build
32
+ contract = contract.class_object.new
33
+ end
34
+ contract.address = address
35
+ contract
38
36
  end
39
37
 
40
- def build(connection)
41
- class_name = @name.camelize
42
- functions = @functions
43
- constructor_inputs = @constructor_inputs
44
- binary = @code
45
- events = @events
46
- abi = @abi
47
-
48
- class_methods = Class.new do
49
-
50
- define_method "connection".to_sym do
51
- connection
52
- end
53
-
54
- define_method :deploy do |*params|
55
- formatter = Ethereum::Formatter.new
56
- deploy_code = binary
57
- deploy_arguments = ""
58
- if constructor_inputs.present?
59
- raise "Missing constructor parameter" and return if params.length != constructor_inputs.length
60
- constructor_inputs.each_index do |i|
61
- args = [constructor_inputs[i]["type"], params[i]]
62
- deploy_arguments << formatter.to_payload(args)
63
- end
64
- end
65
- deploy_payload = deploy_code + deploy_arguments
66
- deploytx = connection.eth_send_transaction({from: self.sender, data: "0x" + deploy_payload})["result"]
67
- raise "Failed to deploy, did you unlock #{self.sender} account? Transaction hash: #{deploytx}" if deploytx.nil? || deploytx == "0x0000000000000000000000000000000000000000000000000000000000000000"
68
- instance_variable_set("@deployment", Ethereum::Deployment.new(deploytx, connection))
69
- end
70
-
71
- define_method :estimate do |*params|
72
- formatter = Ethereum::Formatter.new
73
- deploy_code = binary
74
- deploy_arguments = ""
75
- if constructor_inputs.present?
76
- raise "Missing constructor parameter" and return if params.length != constructor_inputs.length
77
- constructor_inputs.each_index do |i|
78
- args = [constructor_inputs[i]["type"], params[i]]
79
- deploy_arguments << formatter.to_payload(args)
80
- end
81
- end
82
- deploy_payload = deploy_code + deploy_arguments
83
- deploytx = connection.eth_estimate_gas({from: self.sender, data: "0x" + deploy_payload})["result"]
84
- end
85
-
86
- define_method :events do
87
- return events
88
- end
89
-
90
- define_method :abi do
91
- return abi
92
- end
93
-
94
- define_method :deployment do
95
- instance_variable_get("@deployment")
96
- end
97
-
98
- define_method :deploy_and_wait do |time = 200.seconds, *params, **args, &block|
99
- self.deploy(*params)
100
- self.deployment.wait_for_deployment(time, **args, &block)
101
- instance_variable_set("@address", self.deployment.contract_address)
102
- self.events.each do |event|
103
- event.set_address(self.deployment.contract_address)
104
- event.set_client(connection)
105
- end
106
- self.deployment.contract_address
107
- end
108
-
109
- define_method :at do |addr|
110
- instance_variable_set("@address", addr)
111
- self.events.each do |event|
112
- event.set_address(addr)
113
- event.set_client(connection)
114
- end
115
- end
116
38
 
117
- define_method :address do
118
- instance_variable_get("@address")
119
- end
120
-
121
- define_method :as do |addr|
122
- instance_variable_set("@sender", addr)
123
- end
124
-
125
- define_method :sender do
126
- instance_variable_get("@sender") || connection.default_account
127
- end
128
-
129
- define_method :set_gas_price do |gp|
130
- instance_variable_set("@gas_price", gp)
131
- end
39
+ def address=(addr)
40
+ @address = addr
41
+ @events.each do |event|
42
+ event.set_address(addr)
43
+ event.set_client(@client)
44
+ end
45
+ end
132
46
 
133
- define_method :gas_price do
134
- instance_variable_get("@gas_price") || DEFAULT_GAS_PRICE
135
- end
47
+ def deploy(*params)
48
+ if @constructor_inputs.present?
49
+ raise "Missing constructor parameter" and return if params.length != @constructor_inputs.length
50
+ end
51
+ deploy_arguments = @formatter.construtor_params_to_payload(@constructor_inputs, params)
52
+ payload = "0x" + @code + deploy_arguments
53
+ tx = @client.eth_send_transaction({from: sender, data: payload})["result"]
54
+ raise "Failed to deploy, did you unlock #{sender} account? Transaction hash: #{deploytx}" if tx.nil? || tx == "0x0000000000000000000000000000000000000000000000000000000000000000"
55
+ @deployment = Ethereum::Deployment.new(tx, @client)
56
+ end
136
57
 
137
- define_method :set_gas do |gas|
138
- instance_variable_set("@gas", gas)
139
- end
58
+ def deploy_and_wait(*params, **args, &block)
59
+ deploy(*params)
60
+ @deployment.wait_for_deployment(**args, &block)
61
+ self.events.each do |event|
62
+ event.set_address(@address)
63
+ event.set_client(@client)
64
+ end
65
+ @address = @deployment.contract_address
66
+ end
140
67
 
141
- define_method :gas do
142
- instance_variable_get("@gas") || DEFAULT_GAS
68
+ def estimate(*params)
69
+ deploy_arguments = ""
70
+ if @constructor_inputs.present?
71
+ raise "Wrong number of arguments in a constructor" and return if params.length != @constructor_inputs.length
72
+ @constructor_inputs.each_index do |i|
73
+ args = [@constructor_inputs[i]["type"], params[i]]
74
+ deploy_arguments << @formatter.to_payload(args)
143
75
  end
76
+ end
77
+ deploy_payload = @code + deploy_arguments
78
+ result = @client.eth_estimate_gas({from: @sender, data: "0x" + deploy_payload})
79
+ @decoder.decode_int(result["result"])
80
+ end
144
81
 
145
- events.each do |evt|
146
- define_method "nf_#{evt.name.underscore}".to_sym do |params = {}|
147
- params[:to_block] ||= "latest"
148
- params[:from_block] ||= "0x0"
149
- params[:address] ||= instance_variable_get("@address")
150
- params[:topics] = evt.signature
151
- payload = {topics: [params[:topics]], fromBlock: params[:from_block], toBlock: params[:to_block], address: params[:address]}
152
- filter_id = connection.new_filter(payload)
153
- return filter_id["result"]
154
- end
155
-
156
- define_method "gfl_#{evt.name.underscore}".to_sym do |filter_id|
157
- formatter = Ethereum::Formatter.new
158
- logs = connection.get_filter_logs(filter_id)
159
- collection = []
160
- logs["result"].each do |result|
161
- inputs = evt.input_types
162
- outputs = inputs.zip(result["topics"][1..-1])
163
- data = {blockNumber: result["blockNumber"].hex, transactionHash: result["transactionHash"], blockHash: result["blockHash"], transactionIndex: result["transactionIndex"].hex, topics: []}
164
- outputs.each do |output|
165
- data[:topics] << formatter.from_payload(output)
166
- end
167
- collection << data
168
- end
169
- return collection
170
- end
171
-
172
- define_method "gfc_#{evt.name.underscore}".to_sym do |filter_id|
173
- formatter = Ethereum::Formatter.new
174
- logs = connection.get_filter_changes(filter_id)
175
- collection = []
176
- logs["result"].each do |result|
177
- inputs = evt.input_types
178
- outputs = inputs.zip(result["topics"][1..-1])
179
- data = {blockNumber: result["blockNumber"].hex, transactionHash: result["transactionHash"], blockHash: result["blockHash"], transactionIndex: result["transactionIndex"].hex, topics: []}
180
- outputs.each do |output|
181
- data[:topics] << formatter.from_payload(output)
182
- end
183
- collection << data
184
- end
185
- return collection
186
- end
82
+ def call_raw(fun, *args)
83
+ arg_types = fun.inputs.collect(&:type)
84
+ return {result: :error, message: "missing parameters for #{fun.function_string}" } if arg_types.length != args.length
85
+ payload = [fun.signature]
86
+ arg_types.zip(args).each do |arg|
87
+ payload << @formatter.to_payload(arg)
88
+ end
89
+ raw_result = @client.eth_call({to: @address, from: @sender, data: "0x" + payload.join()})
90
+ raw_result = raw_result["result"]
91
+ output = @decoder.decode_arguments(fun.outputs, raw_result)
92
+ return {data: "0x" + payload.join(), raw: raw_result, formatted: output}
93
+ end
187
94
 
188
- end
95
+ def call(fun, *args)
96
+ output = call_raw(fun, *args)[:formatted]
97
+ if output.length == 1
98
+ return output[0]
99
+ else
100
+ return output
101
+ end
102
+ end
189
103
 
190
- functions.each do |fun|
104
+ def transact(fun, *args)
105
+ arg_types = fun.inputs.collect(&:type)
106
+ return {result: :error, message: "missing parameters for #{fun.function_string}" } if arg_types.length != args.length
107
+ payload = []
108
+ payload << fun.signature
109
+ arg_types.zip(args).each do |arg|
110
+ payload << @formatter.to_payload(arg)
111
+ end
112
+ txid = @client.eth_send_transaction({to: @address, from: @sender, data: "0x" + payload.join()})["result"]
113
+ return Ethereum::Transaction.new(txid, @client, payload.join(), args)
114
+ end
191
115
 
192
- fun_count = functions.select {|x| x.name == fun.name }.count
193
- derived_function_name = (fun_count == 1) ? "#{fun.name.underscore}" : "#{fun.name.underscore}__#{fun.inputs.collect {|x| x.type}.join("__")}"
194
- call_function_name = "call_#{derived_function_name}".to_sym
195
- call_function_name_alias = "c_#{derived_function_name}".to_sym
196
- call_raw_function_name = "call_raw_#{derived_function_name}".to_sym
197
- call_raw_function_name_alias = "cr_#{derived_function_name}".to_sym
198
- transact_function_name = "transact_#{derived_function_name}".to_sym
199
- transact_function_name_alias = "t_#{derived_function_name}".to_sym
200
- transact_and_wait_function_name = "transact_and_wait_#{derived_function_name}".to_sym
201
- transact_and_wait_function_name_alias = "tw_#{derived_function_name}".to_sym
116
+ def transact_and_wait(fun, *args)
117
+ tx = transact(fun, *args)
118
+ tx.wait_for_miner
119
+ return tx
120
+ end
202
121
 
203
- define_method call_raw_function_name do |*args|
204
- formatter = Ethereum::Formatter.new
205
- arg_types = fun.inputs.collect(&:type)
206
- connection = self.connection
207
- return {result: :error, message: "missing parameters for #{fun.function_string}" } if arg_types.length != args.length
208
- payload = []
209
- payload << fun.signature
210
- arg_types.zip(args).each do |arg|
211
- payload << formatter.to_payload(arg)
212
- end
213
- raw_result = connection.eth_call({to: self.address, from: self.sender, data: "0x" + payload.join()})
214
- raw_result = raw_result["result"]
215
- formatted_result = fun.outputs.collect {|x| x.type }.zip(raw_result.gsub(/^0x/,'').scan(/.{64}/))
216
- output = formatted_result.collect {|x| formatter.from_payload(x) }
217
- return {data: "0x" + payload.join(), raw: raw_result, formatted: output}
218
- end
122
+ def create_filter(evt, **params)
123
+ params[:to_block] ||= "latest"
124
+ params[:from_block] ||= "0x0"
125
+ params[:address] ||= @address
126
+ params[:topics] = @encoder.ensure_prefix(evt.signature)
127
+ payload = {topics: [params[:topics]], fromBlock: params[:from_block], toBlock: params[:to_block], address: @encoder.ensure_prefix(params[:address])}
128
+ filter_id = @client.eth_new_filter(payload)
129
+ return @decoder.decode_int(filter_id["result"])
130
+ end
219
131
 
220
- define_method call_function_name do |*args|
221
- data = self.send(call_raw_function_name, *args)
222
- output = data[:formatted]
223
- if output.length == 1
224
- return output[0]
225
- else
226
- return output
227
- end
228
- end
132
+ def parse_filter_data(evt, logs)
133
+ formatter = Ethereum::Formatter.new
134
+ collection = []
135
+ logs["result"].each do |result|
136
+ inputs = evt.input_types
137
+ outputs = inputs.zip(result["topics"][1..-1])
138
+ data = {blockNumber: result["blockNumber"].hex, transactionHash: result["transactionHash"], blockHash: result["blockHash"], transactionIndex: result["transactionIndex"].hex, topics: []}
139
+ outputs.each do |output|
140
+ data[:topics] << formatter.from_payload(output)
141
+ end
142
+ collection << data
143
+ end
144
+ return collection
145
+ end
229
146
 
230
- define_method transact_function_name do |*args|
231
- formatter = Ethereum::Formatter.new
232
- arg_types = fun.inputs.collect(&:type)
233
- connection = self.connection
234
- return {result: :error, message: "missing parameters for #{fun.function_string}" } if arg_types.length != args.length
235
- payload = []
236
- payload << fun.signature
237
- arg_types.zip(args).each do |arg|
238
- payload << formatter.to_payload(arg)
239
- end
240
- txid = connection.eth_send_transaction({to: self.address, from: self.sender, data: "0x" + payload.join()})["result"]
241
- return Ethereum::Transaction.new(txid, self.connection, payload.join(), args)
242
- end
147
+ def get_filter_logs(evt, filter_id)
148
+ parse_filter_data evt, @client.eth_get_filter_logs(filter_id)
149
+ end
243
150
 
244
- define_method transact_and_wait_function_name do |*args|
245
- function_name = "transact_#{derived_function_name}".to_sym
246
- tx = self.send(function_name, *args)
247
- tx.wait_for_miner
248
- return tx
249
- end
151
+ def get_filter_changes(evt, filter_id)
152
+ parse_filter_data evt, @client.eth_get_filter_changes(filter_id)
153
+ end
250
154
 
251
- alias_method call_function_name_alias, call_function_name
252
- alias_method call_raw_function_name_alias, call_raw_function_name
253
- alias_method transact_function_name_alias, transact_function_name
254
- alias_method transact_and_wait_function_name_alias, transact_and_wait_function_name
155
+ def function_name(fun)
156
+ count = functions.select {|x| x.name == fun.name }.count
157
+ name = (count == 1) ? "#{fun.name.underscore}" : "#{fun.name.underscore}__#{fun.inputs.collect {|x| x.type}.join("__")}"
158
+ name.to_sym
159
+ end
255
160
 
161
+ def build
162
+ class_name = @name.camelize
163
+ parent = self
164
+ create_function_proxies
165
+ create_event_proxies
166
+ class_methods = Class.new do
167
+ extend Forwardable
168
+ def_delegators :parent, :abi, :deployment, :events
169
+ def_delegators :parent, :estimate, :deploy, :deploy_and_wait
170
+ def_delegators :parent, :address, :address=, :sender, :sender=
171
+ def_delegator :parent, :call_raw_proxy, :call_raw
172
+ def_delegator :parent, :call_proxy, :call
173
+ def_delegator :parent, :transact_proxy, :transact
174
+ def_delegator :parent, :transact_and_wait_proxy, :transact_and_wait
175
+ def_delegator :parent, :new_filter_proxy, :new_filter
176
+ def_delegator :parent, :get_filter_logs_proxy, :get_filter_logs
177
+ def_delegator :parent, :get_filter_change_proxy, :get_filter_changes
178
+ define_method :parent do
179
+ parent
256
180
  end
257
181
  end
258
- if Object.const_defined?(class_name)
259
- Object.send(:remove_const, class_name)
260
- end
182
+ Object.send(:remove_const, class_name) if Object.const_defined?(class_name)
261
183
  Object.const_set(class_name, class_methods)
262
184
  @class_object = class_methods
263
185
  end
264
186
 
187
+ private
188
+ def create_function_proxies
189
+ parent = self
190
+ call_raw_proxy, call_proxy, transact_proxy, transact_and_wait_proxy = Class.new, Class.new, Class.new, Class.new
191
+ @functions.each do |fun|
192
+ call_raw_proxy.send(:define_method, parent.function_name(fun)) { |*args| parent.call_raw(fun, *args) }
193
+ call_proxy.send(:define_method, parent.function_name(fun)) { |*args| parent.call(fun, *args) }
194
+ transact_proxy.send(:define_method, parent.function_name(fun)) { |*args| parent.transact(fun, *args) }
195
+ transact_and_wait_proxy.send(:define_method, parent.function_name(fun)) { |*args| parent.transact_and_wait(fun, *args) }
196
+ end
197
+ @call_raw_proxy, @call_proxy, @transact_proxy, @transact_and_wait_proxy = call_raw_proxy.new, call_proxy.new, transact_proxy.new, transact_and_wait_proxy.new
198
+ end
199
+
200
+ def create_event_proxies
201
+ parent = self
202
+ new_filter_proxy, get_filter_logs_proxy, get_filter_change_proxy = Class.new, Class.new, Class.new
203
+ events.each do |evt|
204
+ new_filter_proxy.send(:define_method, evt.name.underscore) { |*args| parent.create_filter(evt, *args) }
205
+ get_filter_logs_proxy.send(:define_method, evt.name.underscore) { |*args| parent.get_filter_logs(evt, *args) }
206
+ get_filter_change_proxy.send(:define_method, evt.name.underscore) { |*args| parent.get_filter_changes(evt, *args) }
207
+ end
208
+ @new_filter_proxy, @get_filter_logs_proxy, @get_filter_change_proxy = new_filter_proxy.new, get_filter_logs_proxy.new, get_filter_change_proxy.new
209
+ end
265
210
  end
266
211
  end
@@ -8,8 +8,7 @@ module Ethereum
8
8
  @input_types = data["inputs"].collect {|x| x["type"]}
9
9
  @inputs = data["inputs"].collect {|x| x["name"]}
10
10
  @event_string = "#{@name}(#{@input_types.join(",")})"
11
- @signature = SHA3::Digest::SHA256.hexdigest(@event_string)
12
- # @signature = Digest::SHA3.hexdigest @event_string, 256
11
+ @signature = Digest::SHA3.hexdigest(@event_string, 256)
13
12
  end
14
13
 
15
14
  def set_address(address)
@@ -40,7 +40,7 @@ module Ethereum
40
40
  end
41
41
 
42
42
  def build(connection)
43
- @contract = Ethereum::Contract.new(@name, @binary, @abi)
43
+ @contract = Ethereum::Contract.new(@name, @binary, @abi, client)
44
44
  @contract.build(connection)
45
45
  end
46
46
 
@@ -0,0 +1,58 @@
1
+ module Ethereum
2
+ class Decoder
3
+
4
+ def decode(type, value, start = 0)
5
+ value = value.gsub(/^0x/,'')
6
+ core, subtype = Abi::parse_type(type)
7
+ method_name = "decode_#{core}".to_sym
8
+ if "bytes" == core and subtype.nil?
9
+ decode_dynamic_bytes(value, start)
10
+ elsif "string" == core
11
+ self.send(method_name, value, start)
12
+ else
13
+ self.send(method_name, value[start..start+63])
14
+ end
15
+ end
16
+
17
+ def decode_uint(value)
18
+ value.hex
19
+ end
20
+
21
+ def decode_int(value)
22
+ raise ArgumentError if value.nil?
23
+ (value[0..1] == "ff") ? (value.hex - (2 ** 256)) : value.hex
24
+ end
25
+
26
+ def decode_bool(value)
27
+ return true if value == "0000000000000000000000000000000000000000000000000000000000000001"
28
+ return false if value == "0000000000000000000000000000000000000000000000000000000000000000"
29
+ raise ArgumentError
30
+ end
31
+
32
+ def decode_address(value)
33
+ raise ArgumentError if value.size != 40
34
+ value
35
+ end
36
+
37
+ def decode_bytes(value)
38
+ value.scan(/.{2}/).collect {|x| x.hex}.pack('C*').strip
39
+ end
40
+
41
+ def decode_dynamic_bytes(value, start = 0)
42
+ location = decode_uint(value[start..(start+63)]) * 2
43
+ size = decode_uint(value[location..location+63]) * 2
44
+ value[location+64..location+63+size].scan(/.{2}/).collect {|x| x.hex}.pack('C*')
45
+ end
46
+
47
+ def decode_string(value, start = 0)
48
+ decode_dynamic_bytes(value, start).force_encoding('utf-8')
49
+ end
50
+
51
+ def decode_arguments(arguments, data)
52
+ data = data.gsub(/^0x/,'')
53
+ types = arguments.map { |o| o.type }
54
+ types.each.with_index.map { |t , i| decode(t, data, i*64) }
55
+ end
56
+
57
+ end
58
+ end
@@ -35,9 +35,9 @@ module Ethereum
35
35
  @valid_deployment ||= check_deployed
36
36
  end
37
37
 
38
- def wait_for_deployment(timeout = DEFAULT_TIMEOUT, step: DEFAULT_STEP, &block)
38
+ def wait_for_deployment(timeout: DEFAULT_TIMEOUT, step: DEFAULT_STEP)
39
39
  start_time = Time.now
40
- while true
40
+ loop do
41
41
  raise "Transaction #{@id} timed out." if ((Time.now - start_time) > timeout)
42
42
  sleep step
43
43
  yield if block_given?
@@ -0,0 +1,71 @@
1
+ module Ethereum
2
+
3
+ class Encoder
4
+
5
+ def encode(type, value)
6
+ core, subtype = Abi::parse_type(type)
7
+ if core == "bytes" and subtype.nil?
8
+ encode_dynamic_bytes(value)
9
+ else
10
+ method_name = "encode_#{core}".to_sym
11
+ self.send(method_name, value)
12
+ end
13
+ end
14
+
15
+ def encode_int(value)
16
+ to_twos_complement(value).to_s(16).rjust(64, '0')
17
+ end
18
+
19
+ def encode_uint(value)
20
+ raise ArgumentError if value < 0
21
+ encode_int(value)
22
+ end
23
+
24
+ def encode_bool(value)
25
+ (value ? "1" : "0").rjust(64, '0')
26
+ end
27
+
28
+ def encode_fixed(_value)
29
+ raise NotImplementedError
30
+ end
31
+
32
+ def encode_ufixed(_value)
33
+ raise NotImplementedError
34
+ end
35
+
36
+ def encode_bytes(value)
37
+ value.each_char.map {|x| x.ord.to_s(16)}.join("").ljust(64, '0')
38
+ end
39
+
40
+ def encode_dynamic_bytes(value)
41
+ location = encode_uint(32)
42
+ size = encode_uint(value.size)
43
+ content = encode_bytes(value)
44
+ location + size + content
45
+ end
46
+
47
+ def encode_string(value)
48
+ location = encode_uint(32)
49
+ size = encode_uint(value.bytes.size)
50
+ content = value.bytes.map {|x| x.to_s(16)}.join("").ljust(64, '0')
51
+ location + size + content
52
+ end
53
+
54
+ def encode_address(value)
55
+ value = value.gsub(/^0x/,'')
56
+ raise ArgumentError if value.size != 40
57
+ value
58
+ end
59
+
60
+ def ensure_prefix(value)
61
+ value.start_with?("0x") ? value : ("0x" + value)
62
+ end
63
+
64
+ private
65
+ def to_twos_complement(number)
66
+ (number & ((1 << 256) - 1))
67
+ end
68
+
69
+ end
70
+
71
+ end
@@ -103,6 +103,10 @@ module Ethereum
103
103
  (hexstring.gsub(/^0x/,'')[0..1] == "ff") ? (hexstring.hex - (2 ** 256)) : hexstring.hex
104
104
  end
105
105
 
106
+ def bool_to_payload(bool)
107
+ int_to_payload(bool ? 1 : 0)
108
+ end
109
+
106
110
  def address_to_payload(address)
107
111
  from_address(address)
108
112
  end
@@ -112,7 +116,7 @@ module Ethereum
112
116
  end
113
117
 
114
118
  def int_to_payload(int)
115
- self.to_twos_complement(uint).rjust(64, '0')
119
+ self.to_twos_complement(int).rjust(64, '0')
116
120
  end
117
121
 
118
122
  def bytes_to_payload(bytes)
@@ -123,6 +127,10 @@ module Ethereum
123
127
  self.bytes_to_payload(bytes)
124
128
  end
125
129
 
130
+ def construtor_params_to_payload(abi, params)
131
+ abi.map.with_index { |var, i| to_payload([var["type"], params[i]]) }.join
132
+ end
133
+
126
134
  def get_base_type(typename)
127
135
  typename.gsub(/\d+/,'')
128
136
  end
@@ -12,8 +12,24 @@ module Ethereum
12
12
  @outputs = data["outputs"].collect do |output|
13
13
  Ethereum::FunctionOutput.new(output)
14
14
  end
15
- @function_string = "#{@name}(#{@inputs.collect {|x| x.type }.join(",")})"
16
- @signature = Digest::SHA3.hexdigest(@function_string, 256)[0..7]
15
+ @function_string = self.class.calc_signature(@name, @inputs)
16
+ @signature = self.class.calc_id(@function_string)
17
+ end
18
+
19
+ def self.to_canonical_type(type)
20
+ type
21
+ .gsub(/(int)(\z|\D)/, '\1256\2')
22
+ .gsub(/(uint)(\z|\D)/, '\1256\2')
23
+ .gsub(/(fixed)(\z|\D)/, '\1128x128\2')
24
+ .gsub(/(ufixed)(\z|\D)/, '\1128x128\2')
25
+ end
26
+
27
+ def self.calc_signature(name, inputs)
28
+ "#{name}(#{inputs.collect {|x| self.to_canonical_type(x.type) }.join(",")})"
29
+ end
30
+
31
+ def self.calc_id(signature)
32
+ Digest::SHA3.hexdigest(signature, 256)[0..7]
17
33
  end
18
34
 
19
35
  end
@@ -30,7 +30,7 @@ module Ethereum
30
30
  return response.body
31
31
  end
32
32
 
33
- def send_batch(batch)
33
+ def send_batch(_batch)
34
34
  raise NotImplementedError
35
35
  end
36
36
  end
@@ -13,13 +13,13 @@ module Ethereum
13
13
  abi = JSON.parse(sol_output[contract]["abi"] )
14
14
  name = contract
15
15
  code = sol_output[contract]["bin"]
16
- @contracts << Contract.new(name, code, abi)
16
+ @contracts << Contract.new(name, code, abi, @client)
17
17
  end
18
18
  end
19
19
 
20
20
  def build_all
21
21
  @contracts.each do |contract|
22
- contract.build(@client)
22
+ contract.build
23
23
  end
24
24
  end
25
25
 
@@ -27,7 +27,6 @@ module Ethereum
27
27
  return read
28
28
  end
29
29
 
30
- # TODO: Not sure if multithread safe
31
30
  # Note: Guarantees the results are in the same order as defined in batch call.
32
31
  # client.batch do
33
32
  # client.eth_block_number
@@ -8,7 +8,7 @@ class Ethereum::Singleton
8
8
  @instance ||= configure_instance(create_instance)
9
9
  end
10
10
 
11
- def setup(&block)
11
+ def setup
12
12
  yield(self)
13
13
  end
14
14
 
@@ -39,7 +39,7 @@ module Ethereum
39
39
 
40
40
  def execute_solc(dir, filename)
41
41
  cmd = "#{@bin_path} #{@args} '#{dir}' '#{filename}'"
42
- stdout, stderr, status = Open3.capture3(cmd)
42
+ _, stderr, status = Open3.capture3(cmd)
43
43
  raise SystemCallError, "Unanable to run solc compliers" if status.exitstatus == 127
44
44
  raise CompilationError, stderr unless status.exitstatus == 0
45
45
  end
@@ -1,3 +1,3 @@
1
1
  module Ethereum
2
- VERSION = "1.6.0"
2
+ VERSION = "2.0.0"
3
3
  end
@@ -4,20 +4,20 @@ namespace :ethereum do
4
4
  namespace :contract do
5
5
 
6
6
  desc "Compile a contract"
7
- task :compile, [:path] do |t, args|
7
+ task :compile, [:path] do |_, args|
8
8
  contract = Ethereum::Solidity.new.compile(args[:path])
9
9
  puts "Contract abi:"
10
- puts contract["Works"]["abi"]
10
+ puts contract.map { |k, v| "#{k}: #{v["abi"]}" }.join("\n\n")
11
11
  puts
12
12
  puts "Contract binary code:"
13
- puts contract["Works"]["bin"]
13
+ puts contract.map { |k, v| "#{k}: #{v["bin"]}" }.join("\n\n")
14
14
  puts
15
15
  end
16
16
 
17
17
  desc "Compile and deploy contract"
18
- task :deploy, [:path] do |t, args|
18
+ task :deploy, [:path] do |_, args|
19
19
  puts "Deploing contract #{args[:path]}"
20
- @works = Ethereum::Contract.from_file(args[:path])
20
+ @works = Ethereum::Contract.create(file: args[:path])
21
21
  @works.deploy_and_wait { puts "." }
22
22
  address = @works.deployment.contract_address
23
23
  puts "Contract deployed under address: #{address}"
@@ -5,8 +5,8 @@ namespace :ethereum do
5
5
 
6
6
  desc "Run testnet node "
7
7
  task :test do
8
- stdout, stdeerr, status = Open3.capture3("parity --chain ~/.parity/ropsten.json account list")
9
- account = stdeerr.split(/[\[,\]]/)[1]
8
+ _, out, _ = Open3.capture3("parity --chain ~/.parity/ropsten.json account list")
9
+ account = out.split(/[\[,\]]/)[1]
10
10
  cmd = "parity --chain ~/.parity/ropsten.json --password ~/.parity/pass --unlock #{account} --author #{account}"
11
11
  puts cmd
12
12
  system cmd
@@ -14,8 +14,8 @@ namespace :ethereum do
14
14
 
15
15
  desc "Run morden (production) node"
16
16
  task :run do
17
- stdout, stdeerr, status = Open3.capture3("parity account list")
18
- account = stdeerr.split(/[\[,\]]/)[1]
17
+ _, out, _ = Open3.capture3("parity account list")
18
+ account = out.split(/[\[,\]]/)[1]
19
19
  system "parity --password ~/.parity/pass --unlock #{account} --author #{account} --no-jsonrpc"
20
20
  end
21
21
 
@@ -30,7 +30,7 @@ namespace :ethereum do
30
30
  task :waitforsync do
31
31
  formatter = Ethereum::Formatter.new
32
32
  begin
33
- while (1) do
33
+ loop do
34
34
  result = Ethereum::Singleton.instance.eth_syncing["result"]
35
35
  unless result
36
36
  puts "Synced"
@@ -5,13 +5,13 @@ namespace :ethereum do
5
5
  namespace :transaction do
6
6
 
7
7
  desc "Get info about transaction"
8
- task :byhash, [:id] do |t, args|
8
+ task :byhash, [:id] do |_, args|
9
9
  @client = Ethereum::Singleton.instance
10
10
  pp @client.eth_get_transaction_by_hash(args[:id])
11
11
  end
12
12
 
13
13
  desc "Send"
14
- task :send, [:address, :amount] do |t, args|
14
+ task :send, [:address, :amount] do |_, args|
15
15
  @client = Ethereum::Singleton.instance
16
16
  @formatter = Ethereum::Formatter.new
17
17
  address = @formatter.to_address(args[:address])
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ethereum.rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marek Kirejczyk
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-01-18 00:00:00.000000000 Z
11
+ date: 2017-01-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -147,11 +147,14 @@ files:
147
147
  - contracts/classic/QueueSample.sol
148
148
  - ethereum.gemspec
149
149
  - lib/ethereum.rb
150
+ - lib/ethereum/abi.rb
150
151
  - lib/ethereum/client.rb
151
152
  - lib/ethereum/contract.rb
152
153
  - lib/ethereum/contract_event.rb
153
154
  - lib/ethereum/contract_initializer.rb
155
+ - lib/ethereum/decoder.rb
154
156
  - lib/ethereum/deployment.rb
157
+ - lib/ethereum/encoder.rb
155
158
  - lib/ethereum/formatter.rb
156
159
  - lib/ethereum/function.rb
157
160
  - lib/ethereum/function_input.rb
@@ -191,7 +194,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
191
194
  version: '0'
192
195
  requirements: []
193
196
  rubyforge_project:
194
- rubygems_version: 2.5.2
197
+ rubygems_version: 2.5.1
195
198
  signing_key:
196
199
  specification_version: 4
197
200
  summary: Ruby Ethereum client using the JSON-RPC interface