ethereum.rb 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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