Class: FlowClient::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/flow_client/client.rb

Overview

Flow client

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(node_address) ⇒ Client

Returns a new instance of Client.


19
20
21
22
# File 'lib/flow_client/client.rb', line 19

def initialize(node_address)
  @stub = Access::AccessAPI::Stub.new(node_address, :this_channel_is_insecure)
  @address_aliases = {}
end

Instance Attribute Details

#address_aliasesObject

Returns the value of attribute address_aliases.


17
18
19
# File 'lib/flow_client/client.rb', line 17

def address_aliases
  @address_aliases
end

Instance Method Details

#add_account_key(public_key_hex, payer_account, signer, weight) ⇒ Object

Adds a public key to an account


108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/flow_client/client.rb', line 108

def (public_key_hex, , signer, weight)
  script = File.read(File.join("lib", "cadence", "templates", "add-account-key.cdc"))

  arguments = [
    CadenceType.String(public_key_hex),
    CadenceType.UFix64(weight)
  ]

  transaction = FlowClient::Transaction.new
  transaction.script = script
  transaction.reference_block_id = get_latest_block.id
  transaction.proposer_address = .address
  transaction.proposer_key_index = 0
  transaction.arguments = arguments
  transaction.proposer_key_sequence_number = (.address).keys.first.sequence_number
  transaction.payer_address = .address
  transaction.authorizer_addresses = [.address]
  transaction.add_envelope_signature(.address, 0, signer)
  res = send_transaction(transaction)

  wait_for_transaction(res.id) do |response|
    raise CadenceRuntimeError, response.error_message if response.status_code != 0
  end
end

#add_contract(name, code, payer_account, signer) ⇒ Object

Adds a contract to an account


134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/flow_client/client.rb', line 134

def add_contract(name, code, , signer)
  script = File.read(File.join("lib", "cadence", "templates", "add-contract.cdc"))
  code_hex = code.unpack1("H*")

  arguments = [
    CadenceType.String(name),
    CadenceType.String(code_hex)
  ]

  transaction = FlowClient::Transaction.new
  transaction.script = script
  transaction.reference_block_id = get_latest_block.id
  transaction.proposer_address = .address
  transaction.proposer_key_index = 0
  transaction.arguments = arguments
  transaction.proposer_key_sequence_number = (.address).keys.first.sequence_number
  transaction.payer_address = .address
  transaction.authorizer_addresses = [.address]
  transaction.add_envelope_signature(.address, 0, signer)
  res = send_transaction(transaction)

  wait_for_transaction(res.id) do |response|
    raise CadenceRuntimeError, response.error_message if response.status_code != 0
  end
end

#create_account(new_account_public_keys, contracts, payer_account, signer) ⇒ FlowClient::Account

Creates a new account

Returns:


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
96
97
98
99
100
101
102
103
104
105
# File 'lib/flow_client/client.rb', line 68

def (, contracts, , signer)
  script = File.read(File.join("lib", "cadence", "templates", "create-account.cdc"))

  arguments = [
    CadenceType.Array(
      .to_a.map { |key| CadenceType.String(key) }
    ),
    CadenceType.Dictionary(
      contracts.to_a.map { |name, code| CadenceType.DictionaryValue(
        CadenceType.String(name), CadenceType.String(code.unpack1("H*"))
      ) }
    ),
  ]

  transaction = FlowClient::Transaction.new
  transaction.script = script
  transaction.reference_block_id = get_latest_block.id
  transaction.proposer_address = .address
  transaction.proposer_key_index = 0
  transaction.arguments = arguments
  transaction.proposer_key_sequence_number = (.address).keys.first.sequence_number
  transaction.payer_address = .address
  transaction.authorizer_addresses = [.address]
  transaction.add_envelope_signature(.address, 0, signer)
  res = send_transaction(transaction)

   = nil
  wait_for_transaction(res.id) do |response|
    raise CadenceRuntimeError, response.error_message if response.status_code != 0

    event_payload = response.events.select { |e| e.type == "flow.AccountCreated" }.first.payload
    payload_json = JSON.parse(event_payload)
     = payload_json["value"]["fields"][0]["value"]["value"]
     = ()
  end

  
end

#execute_script(script, args = []) ⇒ Object

Executes a script on the blockchain


215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/flow_client/client.rb', line 215

def execute_script(script, args = [])
  processed_args = []
  args.to_a.each do |arg|
    processed_arg = arg.class == OpenStruct ? Utils.openstruct_to_json(arg) : arg
    processed_args << processed_arg
  end

  req = Access::ExecuteScriptAtLatestBlockRequest.new(
    script: FlowClient::Utils.substitute_address_aliases(script, @address_aliases),
    arguments: processed_args
  )

  res = @stub.execute_script_at_latest_block(req)
  parse_json(res.value)
end

#get_account(address) ⇒ FlowClient::Account

Returns an account for the address specified at the latest block.

Parameters:

  • the (String)

    address string value

Returns:


37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/flow_client/client.rb', line 37

def (address)
  req = Access::GetAccountAtLatestBlockRequest.new(address: to_bytes(address))

  begin
    res = @stub.(req)
  rescue GRPC::BadStatus => e
    raise ClientError, e.details
  else
     = FlowClient::Account.new(
      address: res..address.unpack1("H*"),
      balance: res..balance/100000000.0
    )

    res..keys.each do |key|
      .keys << FlowClient::AccountKey.new(
        public_key: key.public_key.unpack1("H*"),
        index: key.index,
        sequence_number: key.sequence_number,
        revoked: key.revoked,
        weight: key.weight
      )
    end

    .contracts = res..contracts
    
  end
end

#get_block_by_height(height) ⇒ FlowClient::Block

Returns the latest with height

Parameters:

  • block (Integer)

    height

Returns:


260
261
262
263
264
265
266
# File 'lib/flow_client/client.rb', line 260

def get_block_by_height(height)
  req = Access::GetBlockByHeightRequest.new(
    height: height
  )
  res = @stub.get_block_by_height(req)
  Block.parse_grpc_block_response(res)
end

#get_block_by_id(id) ⇒ FlowClient::Block

Returns the block with id

Returns:


247
248
249
250
251
252
253
# File 'lib/flow_client/client.rb', line 247

def get_block_by_id(id)
  req = Access::GetBlockByIDRequest.new(
    id: to_bytes(id)
  )
  res = @stub.get_block_by_id(req)
  Block.parse_grpc_block_response(res)
end

#get_collection_by_id(id) ⇒ FlowClient::Collection

Returns the collection with id

Parameters:

  • collection (String)

    id

Returns:


275
276
277
278
279
280
281
# File 'lib/flow_client/client.rb', line 275

def get_collection_by_id(id)
  req = Access::GetCollectionByIDRequest.new(
    id: to_bytes(id)
  )
  res = @stub.get_collection_by_id(req)
  Collection.parse_grpc_type(res)
end

#get_events(type, start_height, end_height) ⇒ FlowClient::EventsResult

Returns events of the given type between the start and end block heights

Parameters:

  • event (String)

    name

  • start (Integer)

    block height

  • end (Integer)

    block height

Returns:


292
293
294
295
296
297
298
299
300
301
302
303
304
305
# File 'lib/flow_client/client.rb', line 292

def get_events(type, start_height, end_height)
  req = Access::GetEventsForHeightRangeRequest.new(
    type: type,
    start_height: start_height,
    end_height: end_height
  )
  begin
    res = @stub.get_events_for_height_range(req)
  rescue GRPC::BadStatus => e
    raise ClientError, e.details
  else
    res.results.map { |event| EventsResult.parse_grpc_type(event) }
  end
end

#get_latest_block(is_sealed: true) ⇒ FlowClient::Block

Returns the latest block

Returns:


236
237
238
239
240
241
242
# File 'lib/flow_client/client.rb', line 236

def get_latest_block(is_sealed: true)
  req = Access::GetLatestBlockRequest.new(
    is_sealed: is_sealed
  )
  res = @stub.get_latest_block(req)
  Block.parse_grpc_block_response(res)
end

#get_transaction(transaction_id) ⇒ FlowClient::Transaction

Returns the transaction with transaction_id

Returns:


330
331
332
333
334
335
336
337
338
339
340
341
342
# File 'lib/flow_client/client.rb', line 330

def get_transaction(transaction_id)
  req = Access::GetTransactionRequest.new(
    id: to_bytes(transaction_id)
  )

  begin
    res = @stub.get_transaction(req)
  rescue GRPC::BadStatus => e
    raise ClientError, e.details
  else
    Transaction.parse_grpc_type(res.transaction)
  end
end

#get_transaction_result(transaction_id) ⇒ FlowClient::TransactionResult

Returns a transaction result

Returns:


347
348
349
350
351
352
353
354
355
356
357
358
359
# File 'lib/flow_client/client.rb', line 347

def get_transaction_result(transaction_id)
  req = Access::GetTransactionRequest.new(
    id: to_bytes(transaction_id)
  )

  begin
    res = @stub.get_transaction_result(req)
  rescue GRPC::BadStatus => e
    raise ClientError, e.details
  else
    TransactionResult.parse_grpc_type(res)
  end
end

#pingObject


24
25
26
27
# File 'lib/flow_client/client.rb', line 24

def ping
  req = Access::PingRequest.new
  @stub.ping(req)
end

#remove_contract(name, payer_account, signer) ⇒ Object

Removes a contract from an account


161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/flow_client/client.rb', line 161

def remove_contract(name, , signer)
  script = File.read(File.join("lib", "cadence", "templates", "remove-contract.cdc"))

  arguments = [
    CadenceType.String(name),
  ]

  transaction = FlowClient::Transaction.new
  transaction.script = script
  transaction.reference_block_id = get_latest_block.id
  transaction.proposer_address = .address
  transaction.proposer_key_index = 0
  transaction.arguments = arguments
  transaction.proposer_key_sequence_number = (.address).keys.first.sequence_number
  transaction.payer_address = .address
  transaction.authorizer_addresses = [.address]
  transaction.add_envelope_signature(.address, 0, signer)
  res = send_transaction(transaction)

  wait_for_transaction(res.id) do |response|
    raise CadenceRuntimeError, response.error_message if response.status_code != 0
  end
end

#send_transaction(transaction) ⇒ FlowClient::TransactionResponse

Sends a transaction to the blockchain

Returns:


312
313
314
315
316
317
318
319
320
321
322
323
324
325
# File 'lib/flow_client/client.rb', line 312

def send_transaction(transaction)
  transaction.address_aliases = @address_aliases
  req = Access::SendTransactionRequest.new(
    transaction: transaction.to_protobuf_message
  )

  begin
    res = @stub.send_transaction(req)
  rescue GRPC::BadStatus => e
    raise ClientError, e.details
  else
    TransactionResponse.parse_grpc_type(res)
  end
end

#update_contract(name, code, payer_account, signer) ⇒ Object

Updates a contract on an account


186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'lib/flow_client/client.rb', line 186

def update_contract(name, code, , signer)
  script = File.read(File.join("lib", "cadence", "templates", "update-contract.cdc"))
  code_hex = code.unpack1("H*")

  arguments = [
    CadenceType.String(name),
    CadenceType.String(code_hex)
  ]

  transaction = FlowClient::Transaction.new
  transaction.script = script
  transaction.reference_block_id = get_latest_block.id
  transaction.proposer_address = .address
  transaction.proposer_key_index = 0
  transaction.arguments = arguments
  transaction.proposer_key_sequence_number = (.address).keys.first.sequence_number
  transaction.payer_address = .address
  transaction.authorizer_addresses = [.address]
  transaction.add_envelope_signature(.address, 0, signer)
  res = send_transaction(transaction)

  wait_for_transaction(res.id) do |response|
    raise CadenceRuntimeError, response.error_message if response.status_code != 0
  end
end

#wait_for_transaction(transaction_id) {|response| ... } ⇒ Object

Polls the blockchain for the transaction result until it is sealed or expired

Yields:

  • (response)

363
364
365
366
367
368
369
370
371
# File 'lib/flow_client/client.rb', line 363

def wait_for_transaction(transaction_id)
  response = get_transaction_result(transaction_id)
  while ![:SEALED, :EXPIRED].include? response.status
    sleep(0.5)
    response = get_transaction_result(transaction_id)
  end

  yield(response)
end