Class: Platon::Contract
- Inherits:
-
Object
- Object
- Platon::Contract
- Defined in:
- lib/platon/contract.rb
Instance Attribute Summary collapse
-
#abi ⇒ Object
Returns the value of attribute abi.
-
#address ⇒ Object
Returns the value of attribute address.
-
#call_proxy ⇒ Object
Returns the value of attribute call_proxy.
-
#call_raw_proxy ⇒ Object
Returns the value of attribute call_raw_proxy.
-
#class_object ⇒ Object
Returns the value of attribute class_object.
-
#client ⇒ Object
Returns the value of attribute client.
-
#code ⇒ Object
Returns the value of attribute code.
-
#constructor_inputs ⇒ Object
Returns the value of attribute constructor_inputs.
-
#deployment ⇒ Object
Returns the value of attribute deployment.
-
#events ⇒ Object
Returns the value of attribute events.
-
#functions ⇒ Object
Returns the value of attribute functions.
-
#gas_limit ⇒ Object
Returns the value of attribute gas_limit.
-
#gas_price ⇒ Object
Returns the value of attribute gas_price.
-
#get_filter_change_proxy ⇒ Object
Returns the value of attribute get_filter_change_proxy.
-
#get_filter_logs_proxy ⇒ Object
Returns the value of attribute get_filter_logs_proxy.
-
#key ⇒ Object
Returns the value of attribute key.
-
#name ⇒ Object
Returns the value of attribute name.
-
#new_filter_proxy ⇒ Object
Returns the value of attribute new_filter_proxy.
-
#nonce ⇒ Object
Returns the value of attribute nonce.
-
#sender ⇒ Object
Returns the value of attribute sender.
-
#transact_and_wait_proxy ⇒ Object
Returns the value of attribute transact_and_wait_proxy.
-
#transact_proxy ⇒ Object
Returns the value of attribute transact_proxy.
Class Method Summary collapse
-
.create(file: nil, client: Platon::Singleton.instance, code: nil, abi: nil, address: nil, name: nil, contract_index: nil, truffle: nil) ⇒ Platon::Contract
Creates a contract wrapper.
-
.find_truffle_artifacts(name, paths = []) ⇒ Hash?
Looks up and loads a Truffle artifacts file.
-
.truffle_paths ⇒ Array<String>
Get the list of paths where to look up Truffle artifacts files.
-
.truffle_paths=(paths) ⇒ Object
Set the list of paths where to look up Truffle artifacts files.
Instance Method Summary collapse
- #build ⇒ Object
- #call(fun, *args) ⇒ Object
- #call_args(fun, args) ⇒ Object
- #call_payload(fun, args) ⇒ Object
- #call_raw(fun, *args) ⇒ Object
- #create_filter(evt, **params) ⇒ Object
- #deploy(*params) ⇒ Object
- #deploy_and_wait(*params, **args, &block) ⇒ Object
- #deploy_args(params) ⇒ Object
- #deploy_payload(params) ⇒ Object
- #estimate(*params) ⇒ Object
- #function_name(fun) ⇒ Object
- #get_filter_changes(evt, filter_id) ⇒ Object
- #get_filter_logs(evt, filter_id) ⇒ Object
-
#initialize(name, code, abi, client = Platon::Singleton.instance) ⇒ Contract
constructor
A new instance of Contract.
- #parse_filter_data(evt, logs) ⇒ Object
- #send_raw_transaction(payload, to = nil) ⇒ Object
- #send_transaction(tx_args) ⇒ Object
- #transact(fun, *args) ⇒ Object
- #transact_and_wait(fun, *args) ⇒ Object
Constructor Details
#initialize(name, code, abi, client = Platon::Singleton.instance) ⇒ Contract
Returns a new instance of Contract.
14 15 16 17 18 19 20 21 22 23 24 25 26 |
# File 'lib/platon/contract.rb', line 14 def initialize(name, code, abi, client = Platon::Singleton.instance) @name = name @code = code @abi = abi @constructor_inputs, @functions, @events = Platon::Abi.parse_abi(abi) @formatter = Platon::Formatter.new @client = client @sender = client.default_account @encoder = Encoder.new @decoder = Decoder.new @gas_limit = @client.gas_limit @gas_price = @client.gas_price end |
Instance Attribute Details
#abi ⇒ Object
Returns the value of attribute abi.
9 10 11 |
# File 'lib/platon/contract.rb', line 9 def abi @abi end |
#address ⇒ Object
Returns the value of attribute address.
6 7 8 |
# File 'lib/platon/contract.rb', line 6 def address @address end |
#call_proxy ⇒ Object
Returns the value of attribute call_proxy.
11 12 13 |
# File 'lib/platon/contract.rb', line 11 def call_proxy @call_proxy end |
#call_raw_proxy ⇒ Object
Returns the value of attribute call_raw_proxy.
11 12 13 |
# File 'lib/platon/contract.rb', line 11 def call_raw_proxy @call_raw_proxy end |
#class_object ⇒ Object
Returns the value of attribute class_object.
9 10 11 |
# File 'lib/platon/contract.rb', line 9 def class_object @class_object end |
#client ⇒ Object
Returns the value of attribute client.
9 10 11 |
# File 'lib/platon/contract.rb', line 9 def client @client end |
#code ⇒ Object
Returns the value of attribute code.
9 10 11 |
# File 'lib/platon/contract.rb', line 9 def code @code end |
#constructor_inputs ⇒ Object
Returns the value of attribute constructor_inputs.
10 11 12 |
# File 'lib/platon/contract.rb', line 10 def constructor_inputs @constructor_inputs end |
#deployment ⇒ Object
Returns the value of attribute deployment.
9 10 11 |
# File 'lib/platon/contract.rb', line 9 def deployment @deployment end |
#events ⇒ Object
Returns the value of attribute events.
10 11 12 |
# File 'lib/platon/contract.rb', line 10 def events @events end |
#functions ⇒ Object
Returns the value of attribute functions.
10 11 12 |
# File 'lib/platon/contract.rb', line 10 def functions @functions end |
#gas_limit ⇒ Object
Returns the value of attribute gas_limit.
8 9 10 |
# File 'lib/platon/contract.rb', line 8 def gas_limit @gas_limit end |
#gas_price ⇒ Object
Returns the value of attribute gas_price.
8 9 10 |
# File 'lib/platon/contract.rb', line 8 def gas_price @gas_price end |
#get_filter_change_proxy ⇒ Object
Returns the value of attribute get_filter_change_proxy.
12 13 14 |
# File 'lib/platon/contract.rb', line 12 def get_filter_change_proxy @get_filter_change_proxy end |
#get_filter_logs_proxy ⇒ Object
Returns the value of attribute get_filter_logs_proxy.
12 13 14 |
# File 'lib/platon/contract.rb', line 12 def get_filter_logs_proxy @get_filter_logs_proxy end |
#key ⇒ Object
Returns the value of attribute key.
7 8 9 |
# File 'lib/platon/contract.rb', line 7 def key @key end |
#name ⇒ Object
Returns the value of attribute name.
9 10 11 |
# File 'lib/platon/contract.rb', line 9 def name @name end |
#new_filter_proxy ⇒ Object
Returns the value of attribute new_filter_proxy.
12 13 14 |
# File 'lib/platon/contract.rb', line 12 def new_filter_proxy @new_filter_proxy end |
#nonce ⇒ Object
Returns the value of attribute nonce.
8 9 10 |
# File 'lib/platon/contract.rb', line 8 def nonce @nonce end |
#sender ⇒ Object
Returns the value of attribute sender.
9 10 11 |
# File 'lib/platon/contract.rb', line 9 def sender @sender end |
#transact_and_wait_proxy ⇒ Object
Returns the value of attribute transact_and_wait_proxy.
11 12 13 |
# File 'lib/platon/contract.rb', line 11 def transact_and_wait_proxy @transact_and_wait_proxy end |
#transact_proxy ⇒ Object
Returns the value of attribute transact_proxy.
11 12 13 |
# File 'lib/platon/contract.rb', line 11 def transact_proxy @transact_proxy end |
Class Method Details
.create(file: nil, client: Platon::Singleton.instance, code: nil, abi: nil, address: nil, name: nil, contract_index: nil, truffle: nil) ⇒ Platon::Contract
Creates a contract wrapper. This method attempts to instantiate a contract object from a Solidity source file, from a Truffle artifacts file, or from explicit API and bytecode.
-
If :file is present, the method compiles it and looks up the contract factory at :contract_index (0 if not provided). :abi and :code are ignored.
-
If :truffle is present, the method looks up the Truffle artifacts data for :name and uses those data to build a contract instance.
-
Otherwise, the method uses :name, :code, and :abi to build the contract instance.
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/platon/contract.rb', line 55 def self.create(file: nil, client: Platon::Singleton.instance, code: nil, abi: nil, address: nil, name: nil, contract_index: nil, truffle: nil) contract = nil if file.present? contracts = Platon::Initializer.new(file, client).build_all raise "No contracts compiled" if contracts.empty? if contract_index contract = contracts[contract_index].class_object.new else contract = contracts.first.class_object.new end else if truffle.present? && truffle.is_a?(Hash) artifacts = find_truffle_artifacts(name, (truffle[:paths].is_a?(Array)) ? truffle[:paths] : []) if artifacts abi = artifacts['abi'] # The truffle artifacts store bytecodes with a 0x tag, which we need to remove # this may need to be 'deployedBytecode' code_key = artifacts['bytecode'].present? ? 'bytecode' : 'unlinked_binary' code = (artifacts[code_key].start_with?('0x')) ? artifacts[code_key][2, artifacts[code_key].length] : artifacts[code_key] unless address address = if client network_id = client.net_version (artifacts['networks'][network_id]) ? artifacts['networks'][network_id]['address'] : nil else nil end end else abi = nil code = nil end else abi = abi.is_a?(String) ? JSON.parse(abi) : abi.map(&:deep_stringify_keys) end contract = Platon::Contract.new(name, code, abi, client) contract.build contract = contract.class_object.new end contract.address = address contract end |
.find_truffle_artifacts(name, paths = []) ⇒ Hash?
Looks up and loads a Truffle artifacts file. This method iterates over the ‘truffle_path` elements, looking for an artifact file in the `build/contracts` subdirectory.
305 306 307 308 309 310 311 312 313 314 |
# File 'lib/platon/contract.rb', line 305 def self.find_truffle_artifacts(name, paths = []) subpath = File.join('build', 'contracts', "#{name}.json") found = paths.concat(truffle_paths).find { |p| File.file?(File.join(p, subpath)) } if (found) JSON.parse(IO.read(File.join(found, subpath))) else nil end end |
.truffle_paths ⇒ Array<String>
Get the list of paths where to look up Truffle artifacts files.
280 281 282 283 |
# File 'lib/platon/contract.rb', line 280 def self.truffle_paths() @truffle_paths = [] unless @truffle_paths @truffle_paths end |
.truffle_paths=(paths) ⇒ Object
Set the list of paths where to look up Truffle artifacts files.
290 291 292 |
# File 'lib/platon/contract.rb', line 290 def self.truffle_paths=(paths) @truffle_paths = (paths.is_a?(Array)) ? paths : [] end |
Instance Method Details
#build ⇒ Object
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 |
# File 'lib/platon/contract.rb', line 247 def build class_name = @name.camelize parent = self create_function_proxies create_event_proxies class_methods = Class.new do extend Forwardable def_delegators :parent, :deploy_payload, :deploy_args, :call_payload, :call_args def_delegators :parent, :signed_deploy, :key, :key= def_delegators :parent, :gas_limit, :gas_price, :gas_limit=, :gas_price=, :nonce, :nonce= def_delegators :parent, :abi, :deployment, :events def_delegators :parent, :estimate, :deploy, :deploy_and_wait def_delegators :parent, :address, :address=, :sender, :sender= def_delegator :parent, :call_raw_proxy, :call_raw def_delegator :parent, :call_proxy, :call def_delegator :parent, :transact_proxy, :transact def_delegator :parent, :transact_and_wait_proxy, :transact_and_wait def_delegator :parent, :new_filter_proxy, :new_filter def_delegator :parent, :get_filter_logs_proxy, :get_filter_logs def_delegator :parent, :get_filter_change_proxy, :get_filter_changes define_method :parent do parent end end Platon::Contract.send(:remove_const, class_name) if Platon::Contract.const_defined?(class_name, false) Platon::Contract.const_set(class_name, class_methods) @class_object = class_methods end |
#call(fun, *args) ⇒ Object
184 185 186 187 188 189 190 191 |
# File 'lib/platon/contract.rb', line 184 def call(fun, *args) output = call_raw(fun, *args)[:formatted] if output.length == 1 return output[0] else return output end end |
#call_args(fun, args) ⇒ Object
172 173 174 175 176 |
# File 'lib/platon/contract.rb', line 172 def call_args(fun, args) # add_gas_options_args({to: @address, from: @sender, data: call_payload(fun, args)}) {to: @address, from: @sender, data: call_payload(fun, args)} ## TODO[from js SDK] :missing "from" should give error on deploy and send, call ? end |
#call_payload(fun, args) ⇒ Object
168 169 170 |
# File 'lib/platon/contract.rb', line 168 def call_payload(fun, args) "0x" + fun.signature + (@encoder.encode_arguments(fun.inputs, args).presence || "0"*64) end |
#call_raw(fun, *args) ⇒ Object
178 179 180 181 182 |
# File 'lib/platon/contract.rb', line 178 def call_raw(fun, *args) raw_result = @client.platon_call(call_args(fun, args),"latest") output = @decoder.decode_arguments(fun.outputs, raw_result) return {data: call_payload(fun, args), raw: raw_result, formatted: output} end |
#create_filter(evt, **params) ⇒ Object
208 209 210 211 212 213 214 215 216 |
# File 'lib/platon/contract.rb', line 208 def create_filter(evt, **params) params[:to_block] ||= "latest" params[:from_block] ||= "0x0" params[:address] ||= @address params[:topics] = @encoder.ensure_prefix(evt.signature) payload = {topics: [params[:topics]], fromBlock: params[:from_block], toBlock: params[:to_block], address: @encoder.ensure_prefix(params[:address])} filter_id = @client.platon_new_filter(payload) return @decoder.decode_int(filter_id) end |
#deploy(*params) ⇒ Object
142 143 144 145 146 147 148 149 150 151 |
# File 'lib/platon/contract.rb', line 142 def deploy(*params) if key tx = send_raw_transaction(deploy_payload(params)) else tx = send_transaction(deploy_args(params)) end tx_failed = tx.nil? || tx == "0x0000000000000000000000000000000000000000000000000000000000000000" raise IOError, "Failed to deploy, did you unlock #{sender} account? Transaction hash: #{tx}" if tx_failed @deployment = Platon::Deployment.new(tx, @client) end |
#deploy_and_wait(*params, **args, &block) ⇒ Object
153 154 155 156 157 158 159 160 161 |
# File 'lib/platon/contract.rb', line 153 def deploy_and_wait(*params, **args, &block) deploy(*params) @deployment.wait_for_deployment(**args, &block) self.events.each do |event| event.set_address(@address) event.set_client(@client) end @address = @deployment.contract_address end |
#deploy_args(params) ⇒ Object
113 114 115 |
# File 'lib/platon/contract.rb', line 113 def deploy_args(params) ({from: sender, data: deploy_payload(params)}) end |
#deploy_payload(params) ⇒ Object
105 106 107 108 109 110 111 |
# File 'lib/platon/contract.rb', line 105 def deploy_payload(params) if @constructor_inputs.present? raise ArgumentError, "Wrong number of arguments in a constructor" and return if params.length != @constructor_inputs.length end deploy_arguments = @encoder.encode_arguments(@constructor_inputs, params) "0x" + @code + deploy_arguments end |
#estimate(*params) ⇒ Object
163 164 165 166 |
# File 'lib/platon/contract.rb', line 163 def estimate(*params) result = @client.platon_estimate_gas(deploy_args(params)) @decoder.decode_int(result.to_s(16)) ## TODO end |
#function_name(fun) ⇒ Object
241 242 243 244 245 |
# File 'lib/platon/contract.rb', line 241 def function_name(fun) count = functions.select {|x| x.name == fun.name }.count name = (count == 1) ? "#{fun.name.underscore}" : "#{fun.name.underscore}__#{fun.inputs.collect {|x| x.type}.join("__")}" name.to_sym end |
#get_filter_changes(evt, filter_id) ⇒ Object
237 238 239 |
# File 'lib/platon/contract.rb', line 237 def get_filter_changes(evt, filter_id) parse_filter_data evt, @client.platon_get_filter_changes(filter_id) end |
#get_filter_logs(evt, filter_id) ⇒ Object
233 234 235 |
# File 'lib/platon/contract.rb', line 233 def get_filter_logs(evt, filter_id) parse_filter_data evt, @client.platon_get_filter_logs(filter_id) end |
#parse_filter_data(evt, logs) ⇒ Object
218 219 220 221 222 223 224 225 226 227 228 229 230 231 |
# File 'lib/platon/contract.rb', line 218 def parse_filter_data(evt, logs) formatter = Platon::Formatter.new collection = [] logs.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 |
#send_raw_transaction(payload, to = nil) ⇒ Object
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
# File 'lib/platon/contract.rb', line 121 def send_raw_transaction(payload, to = nil) # Platon.configure { |c| c.chain_id = @client.net_version.to_i } @nonce = @client.get_nonce(key.bech32_address(hrp:@client.hrp)) args = { from: key.address, value: 0, data: payload, nonce: @nonce, gas_limit: gas_limit, gas_price: gas_price, chain_id: @client.chain_id } args[:to] = Utils.decode_bech32_address(to) if to puts args tx = Platon::Tx.new(args) tx.sign key @client.platon_send_raw_transaction(tx.hex) end |
#send_transaction(tx_args) ⇒ Object
117 118 119 |
# File 'lib/platon/contract.rb', line 117 def send_transaction(tx_args) @client.platon_send_transaction(tx_args) end |
#transact(fun, *args) ⇒ Object
193 194 195 196 197 198 199 200 |
# File 'lib/platon/contract.rb', line 193 def transact(fun, *args) if key tx = send_raw_transaction(call_payload(fun, args), address) else tx = send_transaction(call_args(fun, args)) end return Platon::Transaction.new(tx, @client, call_payload(fun, args), args) end |
#transact_and_wait(fun, *args) ⇒ Object
202 203 204 205 206 |
# File 'lib/platon/contract.rb', line 202 def transact_and_wait(fun, *args) tx = transact(fun, *args) tx.wait_for_miner return tx end |