class EthereumEx::Contract
Attributes
abi[RW]
code[RW]
constructor_inputs[RW]
events[RW]
functions[RW]
name[RW]
Public Class Methods
new(name, code, abi)
click to toggle source
# File lib/ethereumex/contract.rb, line 6 def initialize(name, code, abi) @name = name @code = code @abi = abi @functions = [] @events = [] @constructor_inputs = @abi.detect {|x| x["type"] == "constructor"}["inputs"] rescue nil @abi.select {|x| x["type"] == "function" }.each do |abifun| @functions << EthereumEx::Function.new(abifun) end @abi.select {|x| x["type"] == "event" }.each do |abievt| @events << EthereumEx::ContractEvent.new(abievt) end end
Public Instance Methods
build(connection)
click to toggle source
# File lib/ethereumex/contract.rb, line 21 def build(connection) class_name = @name functions = @functions constructor_inputs = @constructor_inputs binary = @code events = @events class_methods = Class.new do define_method "connection".to_sym do connection end define_method :deploy do |*params| formatter = EthereumEx::Formatter.new deploy_code = binary deploy_arguments = "" if constructor_inputs.present? raise "Missing constructor parameter" and return if params.length != constructor_inputs.length constructor_inputs.each_index do |i| args = [constructor_inputs[i]["type"], params[i]] deploy_arguments << formatter.to_payload(args) end end deploy_payload = deploy_code + deploy_arguments deploytx = connection.send_transaction({from: self.sender, gas: self.gas, gasPrice: self.gas_price, data: "0x" + deploy_payload})["result"] instance_variable_set("@deployment", EthereumEx::Deployment.new(deploytx, connection)) end define_method :events do return events end define_method :deployment do instance_variable_get("@deployment") end define_method :deploy_and_wait do |time = 60.seconds, *params| self.deploy(*params) self.deployment.wait_for_deployment(time) instance_variable_set("@address", self.deployment.contract_address) self.events.each do |event| event.set_address(self.deployment.contract_address) event.set_client(connection) end end define_method :at do |addr| instance_variable_set("@address", addr) self.events.each do |event| event.set_address(addr) event.set_client(connection) end end define_method :address do instance_variable_get("@address") end define_method :as do |addr| instance_variable_set("@sender", addr) end define_method :sender do instance_variable_get("@sender") || connection.coinbase["result"] end define_method :set_gas_price do |gp| instance_variable_set("@gas_price", gp) end define_method :gas_price do instance_variable_get("@gas_price") || 60000000000 end define_method :set_gas do |gas| instance_variable_set("@gas", gas) end define_method :gas do instance_variable_get("@gas") || 3000000 end events.each do |evt| define_method "nf_#{evt.name.underscore}".to_sym do |params = {}| params[:to_block] ||= "latest" params[:from_block] ||= "0x0" params[:address] ||= instance_variable_get("@address") params[:topics] = evt.signature payload = {topics: [params[:topics]], fromBlock: params[:from_block], toBlock: params[:to_block], address: params[:address]} filter_id = connection.new_filter(payload) return filter_id["result"] end define_method "gfl_#{evt.name.underscore}".to_sym do |filter_id| formatter = Ethereum::Formatter.new logs = connection.get_filter_logs(filter_id) collection = [] logs["result"].each do |result| inputs = evt.input_types outputs = inputs.zip(result["topics"][1..-1]) data = {blockNumber: result["blockNumber"].hex, transactionHash: result["transactionHash"], blockHash: result["blockHash"], transactionIndex: result["transactionIndex"].hex, topics: []} outputs.each do |output| data[:topics] << formatter.from_payload(output) end collection << data end return collection end define_method "gfc_#{evt.name.underscore}".to_sym do |filter_id| formatter = Ethereum::Formatter.new logs = connection.get_filter_changes(filter_id) collection = [] logs["result"].each do |result| inputs = evt.input_types outputs = inputs.zip(result["topics"][1..-1]) data = {blockNumber: result["blockNumber"].hex, transactionHash: result["transactionHash"], blockHash: result["blockHash"], transactionIndex: result["transactionIndex"].hex, topics: []} outputs.each do |output| data[:topics] << formatter.from_payload(output) end collection << data end return collection end end functions.each do |fun| fun_count = functions.select {|x| x.name == fun.name }.count derived_function_name = (fun_count == 1) ? "#{fun.name.underscore}" : "#{fun.name.underscore}__#{fun.inputs.collect {|x| x.type}.join("__")}" call_function_name = "call_#{derived_function_name}".to_sym call_function_name_alias = "c_#{derived_function_name}".to_sym call_raw_function_name = "call_raw_#{derived_function_name}".to_sym call_raw_function_name_alias = "cr_#{derived_function_name}".to_sym transact_function_name = "transact_#{derived_function_name}".to_sym transact_function_name_alias = "t_#{derived_function_name}".to_sym transact_and_wait_function_name = "transact_and_wait_#{derived_function_name}".to_sym transact_and_wait_function_name_alias = "tw_#{derived_function_name}".to_sym define_method call_raw_function_name do |*args| formatter = Ethereum::Formatter.new arg_types = fun.inputs.collect(&:type) connection = self.connection return {result: :error, message: "missing parameters for #{fun.function_string}" } if arg_types.length != args.length payload = [] payload << fun.signature arg_types.zip(args).each do |arg| payload << formatter.to_payload(arg) end raw_result = connection.call({to: self.address, from: self.sender, data: payload.join()})["result"] formatted_result = fun.outputs.collect {|x| x.type }.zip(raw_result.gsub(/^0x/,'').scan(/.{64}/)) output = formatted_result.collect {|x| formatter.from_payload(x) } return {data: "0x" + payload.join(), raw: raw_result, formatted: output} end define_method call_function_name do |*args| data = self.send(call_raw_function_name, *args) output = data[:formatted] if output.length == 1 return output[0] else return output end end define_method transact_function_name do |*args| formatter = Ethereum::Formatter.new arg_types = fun.inputs.collect(&:type) connection = self.connection return {result: :error, message: "missing parameters for #{fun.function_string}" } if arg_types.length != args.length payload = [] payload << fun.signature arg_types.zip(args).each do |arg| payload << formatter.to_payload(arg) end txid = connection.send_transaction({to: self.address, from: self.sender, data: "0x" + payload.join(), gas: self.gas, gasPrice: self.gas_price})["result"] return Ethereum::Transaction.new(txid, self.connection, payload.join(), args) end define_method transact_and_wait_function_name do |*args| function_name = "transact_#{derived_function_name}".to_sym tx = self.send(function_name, *args) tx.wait_for_miner return tx end alias_method call_function_name_alias, call_function_name alias_method call_raw_function_name_alias, call_raw_function_name alias_method transact_function_name_alias, transact_function_name alias_method transact_and_wait_function_name_alias, transact_and_wait_function_name end end if Object.const_defined?(class_name) Object.send(:remove_const, class_name) end Object.const_set(class_name, class_methods) end