ethereum.rb 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.rspec +2 -0
  4. data/.ruby-gemset +1 -0
  5. data/.travis.yml +26 -0
  6. data/CODE_OF_CONDUCT.md +13 -0
  7. data/Gemfile +4 -0
  8. data/LICENSE +22 -0
  9. data/LICENSE.txt +21 -0
  10. data/README.md +183 -0
  11. data/Rakefile +11 -0
  12. data/bin/console +14 -0
  13. data/bin/install_parity +29 -0
  14. data/bin/setup +7 -0
  15. data/contracts/AccountingLib.sol +112 -0
  16. data/contracts/AuditorInterface.sol +4 -0
  17. data/contracts/AuditorRegistry.sol +14 -0
  18. data/contracts/CustodianInterface.sol +27 -0
  19. data/contracts/CustodianRegistry.sol +40 -0
  20. data/contracts/DigixConfiguration.sol +68 -0
  21. data/contracts/Directory.sol +67 -0
  22. data/contracts/DoublyLinked.sol +54 -0
  23. data/contracts/GenericInterface.sol +56 -0
  24. data/contracts/GenericRegistry.sol +15 -0
  25. data/contracts/Gold.sol +105 -0
  26. data/contracts/GoldRegistry.sol +82 -0
  27. data/contracts/GoldTokenLedger.sol +3 -0
  28. data/contracts/Interface.sol +27 -0
  29. data/contracts/Minter.sol +3 -0
  30. data/contracts/Recaster.sol +3 -0
  31. data/contracts/Testing.sol +59 -0
  32. data/contracts/VendorInterface.sol +82 -0
  33. data/contracts/VendorRegistry.sol +39 -0
  34. data/contracts/classic/Digixbot.sol +106 -0
  35. data/contracts/classic/DigixbotConfiguration.sol +62 -0
  36. data/contracts/classic/DigixbotEthereum.sol +86 -0
  37. data/contracts/classic/DigixbotUsers.sol +103 -0
  38. data/contracts/classic/Gold.sol +497 -0
  39. data/contracts/classic/GoldRegistry.sol +503 -0
  40. data/contracts/classic/GoldTokenLedger.sol +560 -0
  41. data/contracts/classic/GoldTokenMinter.sol +607 -0
  42. data/contracts/classic/ParticipantRegistry.sol +94 -0
  43. data/contracts/classic/QueueSample.sol +54 -0
  44. data/ethereum.gemspec +35 -0
  45. data/lib/ethereum.rb +24 -0
  46. data/lib/ethereum/client.rb +97 -0
  47. data/lib/ethereum/contract.rb +266 -0
  48. data/lib/ethereum/contract_event.rb +25 -0
  49. data/lib/ethereum/contract_initializer.rb +54 -0
  50. data/lib/ethereum/deployment.rb +49 -0
  51. data/lib/ethereum/formatter.rb +172 -0
  52. data/lib/ethereum/function.rb +20 -0
  53. data/lib/ethereum/function_input.rb +13 -0
  54. data/lib/ethereum/function_output.rb +14 -0
  55. data/lib/ethereum/http_client.rb +38 -0
  56. data/lib/ethereum/initializer.rb +27 -0
  57. data/lib/ethereum/ipc_client.rb +46 -0
  58. data/lib/ethereum/project_initializer.rb +28 -0
  59. data/lib/ethereum/railtie.rb +10 -0
  60. data/lib/ethereum/singleton.rb +39 -0
  61. data/lib/ethereum/solidity.rb +47 -0
  62. data/lib/ethereum/transaction.rb +36 -0
  63. data/lib/ethereum/version.rb +3 -0
  64. data/lib/tasks/ethereum_contract.rake +27 -0
  65. data/lib/tasks/ethereum_node.rake +51 -0
  66. data/lib/tasks/ethereum_test.rake +32 -0
  67. data/lib/tasks/ethereum_transaction.rake +24 -0
  68. metadata +198 -0
@@ -0,0 +1,94 @@
1
+ contract ParticipantRegistry {
2
+
3
+ enum ParticipantTypes { Admin, Vendor, Custodian, Auditor }
4
+ struct ParticipantDatabase {
5
+ mapping (address => bool) auditors;
6
+ mapping (address => bool) vendors;
7
+ mapping (address => bool) custodians;
8
+ mapping (address => bool) registrars;
9
+ }
10
+
11
+ address owner;
12
+ ParticipantDatabase participantdb;
13
+
14
+ event AddParticipant(address indexed participant, uint indexed participanttype);
15
+ event RemoveParticipant(address indexed participant, uint indexed participanttype);
16
+
17
+ modifier ifowner { if (msg.sender == owner) _ }
18
+ modifier ifregistrar { if ((participantdb.registrars[tx.origin]) || (tx.origin == owner)) _ }
19
+ modifier onlyvendor { if (isVendor(tx.origin) == true) _ }
20
+ modifier onlycustodian { if (isCustodian(tx.origin) == true) _ }
21
+ modifier onlyauditor { if (isAuditor(tx.origin) == true) _ }
22
+
23
+ function ParticipantRegistry() {
24
+ owner = msg.sender;
25
+ }
26
+
27
+ function getOwner() returns (address oa) {
28
+ oa = owner;
29
+ }
30
+
31
+ function setOwner(address nown) ifowner {
32
+ owner = nown;
33
+ }
34
+
35
+ function registerAdmin(address regraddr) ifowner {
36
+ participantdb.registrars[regraddr] = true;
37
+ AddParticipant(regraddr, uint(ParticipantTypes.Admin));
38
+ }
39
+
40
+ function unregisterAdmin(address regraddr) ifowner {
41
+ participantdb.registrars[regraddr] = false;
42
+ RemoveParticipant(regraddr, uint(ParticipantTypes.Admin));
43
+ }
44
+
45
+ function registerVendor(address vendoraddress) ifregistrar {
46
+ participantdb.vendors[vendoraddress] = true;
47
+ AddParticipant(vendoraddress, uint(ParticipantTypes.Vendor));
48
+ }
49
+
50
+ function unregisterVendor(address vendoraddress) ifregistrar {
51
+ participantdb.vendors[vendoraddress] = false;
52
+ RemoveParticipant(vendoraddress, uint(ParticipantTypes.Vendor));
53
+ }
54
+
55
+ function registerCustodian(address custodianaddress) ifregistrar {
56
+ participantdb.custodians[custodianaddress] = true;
57
+ AddParticipant(custodianaddress, uint(ParticipantTypes.Custodian));
58
+ }
59
+
60
+ function unregisterCustodian(address custodianaddress) ifregistrar {
61
+ participantdb.custodians[custodianaddress] = false;
62
+ RemoveParticipant(custodianaddress, uint(ParticipantTypes.Custodian));
63
+ }
64
+
65
+ function registerAuditor(address auditoraddress) ifregistrar {
66
+ participantdb.auditors[auditoraddress] = true;
67
+ AddParticipant(auditoraddress, uint(ParticipantTypes.Auditor));
68
+ }
69
+
70
+ function unregisterAuditor(address auditoraddress) ifregistrar {
71
+ participantdb.auditors[auditoraddress] = false;
72
+ RemoveParticipant(auditoraddress, uint(ParticipantTypes.Auditor));
73
+ }
74
+
75
+ function isVendor(address vendoraddress) returns (bool) {
76
+ return participantdb.vendors[vendoraddress];
77
+ }
78
+
79
+ function isCustodian(address custodianaddress) returns (bool) {
80
+ return participantdb.custodians[custodianaddress];
81
+ }
82
+
83
+ function isAuditor(address auditoraddress) returns (bool) {
84
+ return participantdb.auditors[auditoraddress];
85
+ }
86
+
87
+ function isRegistrar(address regraddr) returns (bool) {
88
+ return participantdb.registrars[regraddr];
89
+ }
90
+ }
91
+
92
+
93
+
94
+ //#include [ParticipantRegistry]
@@ -0,0 +1,54 @@
1
+ ////////////////////////////////////////////////////////////
2
+ // This is an example contract hacked together at a meetup.
3
+ // It is by far not complete and only used to show some
4
+ // features of Solidity.
5
+ ////////////////////////////////////////////////////////////
6
+ contract QueueContract
7
+ {
8
+ struct Queue {
9
+ uint[] data;
10
+ uint front;
11
+ uint back;
12
+ }
13
+ /// @dev the number of elements stored in the queue.
14
+ function length(Queue storage q) constant internal returns (uint) {
15
+ return q.back - q.front;
16
+ }
17
+ /// @dev the number of elements this queue can hold
18
+ function capacity(Queue storage q) constant internal returns (uint) {
19
+ return q.data.length - 1;
20
+ }
21
+ /// @dev push a new element to the back of the queue
22
+ function push(Queue storage q, uint data) internal
23
+ {
24
+ if ((q.back + 1) % q.data.length == q.front)
25
+ return; // throw;
26
+ q.data[q.back] = data;
27
+ q.back = (q.back + 1) % q.data.length;
28
+ }
29
+ /// @dev remove and return the element at the front of the queue
30
+ function pop(Queue storage q) internal returns (uint r)
31
+ {
32
+ if (q.back == q.front)
33
+ return; // throw;
34
+ r = q.data[q.front];
35
+ delete q.data[q.front];
36
+ q.front = (q.front + 1) % q.data.length;
37
+ }
38
+ }
39
+
40
+ contract QueueUserMayBeDeliveryDroneCotnrol is QueueContract {
41
+ Queue requests;
42
+ function QueueUserMayBeDeliveryDroneCotnrol() {
43
+ requests.data.length = 200;
44
+ }
45
+ function addRequest(uint d) {
46
+ push(requests, d);
47
+ }
48
+ function popRequest() returns (uint) {
49
+ return pop(requests);
50
+ }
51
+ function queueLength() returns (uint) {
52
+ return length(requests);
53
+ }
54
+ }
@@ -0,0 +1,35 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'ethereum/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "ethereum.rb"
8
+ spec.version = Ethereum::VERSION
9
+ spec.authors = ["Marek Kirejczyk"]
10
+ spec.email = ["marek.kirejczyk@gmail.com"]
11
+
12
+ spec.summary = %q{Ruby Ethereum client using the JSON-RPC interface}
13
+ spec.description = %q{Ethereum.rb is Ruby Ethereum client using the JSON-RPC interface. Provides interface for sending transactions, creating and interacting with contracts as well as usefull toolkit to work with Ethereum node.}
14
+ spec.homepage = "https://github.com/marekkirejczyk/ethereum.rb"
15
+ spec.license = "MIT"
16
+
17
+ if spec.respond_to?(:metadata)
18
+ spec.metadata['allowed_push_host'] = "https://rubygems.org"
19
+ else
20
+ raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
21
+ end
22
+
23
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
24
+ spec.bindir = "exe"
25
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
26
+ spec.require_paths = ["lib", "bin"]
27
+
28
+ spec.add_development_dependency "bundler", "~> 1.13"
29
+ spec.add_development_dependency "rake", "~> 12.0"
30
+ spec.add_development_dependency "rspec"
31
+ spec.add_development_dependency "pry"
32
+
33
+ spec.add_dependency "activesupport", "~> 5.0.1"
34
+ spec.add_dependency "digest-sha3", "~> 1.1.0"
35
+ end
@@ -0,0 +1,24 @@
1
+ require "ethereum/version"
2
+ require 'active_support'
3
+ require 'active_support/core_ext'
4
+ require 'digest/sha3'
5
+
6
+ module Ethereum
7
+ require 'ethereum/client'
8
+ require 'ethereum/ipc_client'
9
+ require 'ethereum/http_client'
10
+ require 'ethereum/singleton'
11
+ require 'ethereum/solidity'
12
+ require 'ethereum/initializer'
13
+ require 'ethereum/contract'
14
+ require 'ethereum/function'
15
+ require 'ethereum/function_input'
16
+ require 'ethereum/function_output'
17
+ require 'ethereum/contract_event'
18
+ require 'ethereum/formatter'
19
+ require 'ethereum/transaction'
20
+ require 'ethereum/deployment'
21
+ require 'ethereum/project_initializer'
22
+ require 'ethereum/contract_initializer'
23
+ require 'ethereum/railtie' if defined?(Rails)
24
+ end
@@ -0,0 +1,97 @@
1
+ module Ethereum
2
+ class Client
3
+ # https://github.com/ethereum/wiki/wiki/JSON-RPC
4
+ RPC_COMMANDS = %w(web3_clientVersion web3_sha3 net_version net_peerCount net_listening eth_protocolVersion eth_syncing eth_coinbase eth_mining eth_hashrate eth_gasPrice eth_accounts eth_blockNumber eth_getBalance eth_getStorageAt eth_getTransactionCount eth_getBlockTransactionCountByHash eth_getBlockTransactionCountByNumber eth_getUncleCountByBlockHash eth_getUncleCountByBlockNumber eth_getCode eth_sign eth_sendTransaction eth_sendRawTransaction eth_call eth_estimateGas eth_getBlockByHash eth_getBlockByNumber eth_getTransactionByHash eth_getTransactionByBlockHashAndIndex eth_getTransactionByBlockNumberAndIndex eth_getTransactionReceipt eth_getUncleByBlockHashAndIndex eth_getUncleByBlockNumberAndIndex eth_getCompilers eth_compileLLL eth_compileSolidity eth_compileSerpent eth_newFilter eth_newBlockFilter eth_newPendingTransactionFilter eth_uninstallFilter eth_getFilterChanges eth_getFilterLogs eth_getLogs eth_getWork eth_submitWork eth_submitHashrate db_putString db_getString db_putHex db_getHex shh_post shh_version shh_newIdentity shh_hasIdentity shh_newGroup shh_addToGroup shh_newFilter shh_uninstallFilter shh_getFilterChanges shh_getMessages)
5
+ # https://github.com/ethereum/go-ethereum/wiki/Management-APIs
6
+ RPC_MANAGEMENT_COMMANDS = %w(admin_addPeer admin_datadir admin_nodeInfo admin_peers admin_setSolc admin_startRPC admin_startWS admin_stopRPC admin_stopWS debug_backtraceAt debug_blockProfile debug_cpuProfile debug_dumpBlock debug_gcStats debug_getBlockRlp debug_goTrace debug_memStats debug_seedHash debug_setHead debug_setBlockProfileRate debug_stacks debug_startCPUProfile debug_startGoTrace debug_stopCPUProfile debug_stopGoTrace debug_traceBlock debug_traceBlockByNumber debug_traceBlockByHash debug_traceBlockFromFile debug_traceTransaction debug_verbosity debug_vmodule debug_writeBlockProfile debug_writeMemProfile miner_hashrate miner_makeDAG miner_setExtra miner_setGasPrice miner_start miner_startAutoDAG miner_stop miner_stopAutoDAG personal_importRawKey personal_listAccounts personal_lockAccount personal_newAccount personal_unlockAccount personal_sendTransaction txpool_content txpool_inspect txpool_status)
7
+
8
+ attr_accessor :command, :id, :log, :logger, :default_account
9
+
10
+ def initialize(log = false)
11
+ @id = 0
12
+ @log = log
13
+ @batch = nil
14
+
15
+ if @log == true
16
+ @logger = Logger.new("/tmp/ethereum_ruby_http.log")
17
+ end
18
+ end
19
+
20
+ def self.create(host_or_ipcpath, log = false)
21
+ return IpcClient.new(host_or_ipcpath, log) if host_or_ipcpath.end_with? '.ipc'
22
+ return HttpClient.new(host_or_ipcpath, log) if host_or_ipcpath.start_with? 'http'
23
+ raise ArgumentError.new('Unable to detect client type')
24
+ end
25
+
26
+ def batch
27
+ @batch = []
28
+
29
+ yield
30
+ result = send_batch(@batch)
31
+
32
+ @batch = nil
33
+ reset_id
34
+
35
+ return result
36
+ end
37
+
38
+ def get_id
39
+ @id += 1
40
+ return @id
41
+ end
42
+
43
+ def reset_id
44
+ @id = 0
45
+ end
46
+
47
+ def default_account
48
+ @default_account || eth_accounts["result"][0]
49
+ end
50
+
51
+ def int_to_hex(n)
52
+ return "0x#{n.to_s(16)}"
53
+ end
54
+
55
+ # https://github.com/ethereum/wiki/wiki/JSON-RPC#output-hex-values
56
+ def encode_params(params)
57
+ return params.map do |p|
58
+ if p.is_a?(Integer)
59
+ int_to_hex(p)
60
+ else
61
+ p
62
+ end
63
+ end
64
+ end
65
+
66
+ (RPC_COMMANDS + RPC_MANAGEMENT_COMMANDS).each do |rpc_command|
67
+ method_name = rpc_command.underscore
68
+ define_method method_name do |*args|
69
+ command = rpc_command
70
+ if ["eth_getBalance", "eth_call"].include?(command)
71
+ args << "latest"
72
+ end
73
+ payload = {jsonrpc: "2.0", method: command, params: encode_params(args), id: get_id}
74
+
75
+ if @log == true
76
+ @logger.info("Sending #{payload.to_json}")
77
+ end
78
+
79
+ if @batch
80
+ @batch << payload
81
+ return true
82
+ else
83
+ read = send_single(payload.to_json)
84
+ output = JSON.parse(read)
85
+ if @log == true
86
+ @logger.info("Received #{output.to_json}")
87
+ end
88
+ reset_id
89
+ return output
90
+ end
91
+ end
92
+ end
93
+
94
+ end
95
+
96
+ end
97
+
@@ -0,0 +1,266 @@
1
+ module Ethereum
2
+ class Contract
3
+
4
+ DEFAULT_GAS_PRICE = 60000000000
5
+
6
+ DEFAULT_GAS = 3000000
7
+
8
+ attr_accessor :code, :name, :functions, :abi, :constructor_inputs, :events, :class_object
9
+
10
+ def initialize(name, code, abi)
11
+ @name = name
12
+ @code = code
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
23
+ end
24
+
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
38
+ end
39
+
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
+
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
132
+
133
+ define_method :gas_price do
134
+ instance_variable_get("@gas_price") || DEFAULT_GAS_PRICE
135
+ end
136
+
137
+ define_method :set_gas do |gas|
138
+ instance_variable_set("@gas", gas)
139
+ end
140
+
141
+ define_method :gas do
142
+ instance_variable_get("@gas") || DEFAULT_GAS
143
+ end
144
+
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
187
+
188
+ end
189
+
190
+ functions.each do |fun|
191
+
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
202
+
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
219
+
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
229
+
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
243
+
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
250
+
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
255
+
256
+ end
257
+ end
258
+ if Object.const_defined?(class_name)
259
+ Object.send(:remove_const, class_name)
260
+ end
261
+ Object.const_set(class_name, class_methods)
262
+ @class_object = class_methods
263
+ end
264
+
265
+ end
266
+ end