Skip to content

FlowClient is a Ruby gRPC client for Flow (onflow.org)

License

Notifications You must be signed in to change notification settings

Evan-Dapplica/flow_client

 
 

Repository files navigation

Gem Version RSpec Tests

FlowClient

FlowClient is a Ruby gRPC client for Flow (onflow.org)

Features

Blocks:

  • retrieve a block by ID
  • retrieve a block by height
  • retrieve the latest block

Collections:

  • retrieve a collection by ID

Events:

  • retrieve events by name in the block height range

Scripts:

  • submit a script and parse the response
  • submit a script with arguments
  • create a script that returns complex structure and parse the response

Accounts:

  • retrieve an account by address
  • create a new account
  • deploy a new contract to the account
  • remove a contract from the account
  • update an existing contract on the account

Transactions:

  • retrieve a transaction by ID
  • sign a transaction with same payer, proposer and authorizer
  • sign a transaction with different payer and proposer
  • sign a transaction with different authorizers using sign method multiple times
  • submit a signed transaction
  • sign a transaction with arguments and submit it

Installation

Add this line to your application's Gemfile:

gem 'flow_client'

And then execute:

$ bundle install

Or install it yourself as:

$ gem install flow_client

Usage

# Connect to the Flow testnet
client = FlowClient::Client.new("access.devnet.nodes.onflow.org:9000")
res = client.ping

Blocks

Retrieve a block by ID

latest_block = client.get_latest_block
res = client.get_block_by_id(latest_block.block.id.unpack1("H*"))

Retrieve a block by height

latest_block = client.get_latest_block
res = client.get_block_by_height(latest_block.block.height)

Retrieve the latest block

latest_block = client.get_latest_block

Collections

Retrieve a collection by ID

latest_block = client.get_latest_block
cid = latest_block.block.collection_guarantees.first.collection_id.unpack1("H*")
res = client.get_collection_by_id(cid)

Events

# get_events(type, start_height, end_height)
res = client.get_events("A.0b2a3299cc857e29.TopShot.Deposit", 12913388, 12913389)

Scripts

# execute_script(cadence_string, args_array)
args = [{ type: "Address", value: "0xAlice" }.to_json]
# Execute a Cadence script
res = client.execute_script(script, args)

Accounts

Create account

# get_account(account_address)
res = client.get_account("0xAlice")

Get account

# get_account(account_address)
res = client.get_account("0xAlice")

Add contract

contract_code = "..."
signer = FlowClient::LocalSigner.new(service_account_private_key)
payer = FlowClient::Account.new(address: service_account_address)
client.add_contract("ContractName", contract_code, payer, signer)

Update contract

contract_code = "..."
signer = FlowClient::LocalSigner.new(service_account_private_key)
payer = FlowClient::Account.new(address: service_account_address)
client.update_contract("ContractName", contract_code, payer, signer)

Remove contract

signer = FlowClient::LocalSigner.new(service_account_private_key)
payer = FlowClient::Account.new(address: service_account_address)
client.remove_contract("ContractName", payer, signer)

Transactions

Get transaction result

# Get a transaction result
# get_transaction_result(transaction_id)
client.get_transaction_result(res.id.unpack("H*"))

Single signer, proposer and authorizer

service_account_address = "f8d6e0586b0a20c7"
service_account_key = client.get_account(service_account_address).keys.first

arguments = [{ type: "String", value: "Hello world!" }.to_json]

transaction = FlowClient::Transaction.new
transaction.script = script
transaction.reference_block_id = reference_block_id
transaction.gas_limit = 100
transaction.proposer_address = service_account_address
transaction.proposer_key_index = service_account_key.index
transaction.arguments = arguments
transaction.proposer_key_sequence_number = service_account_key.sequence_number
transaction.payer_address = service_account_address
transaction.authorizer_addresses = [service_account_address]

# Only the envelope needs to be signed in this special case
signer = FlowClient::LocalSigner.new(service_account_private_key)
transaction.add_envelope_signature(service_account_address, 0, signer)

tx = client.send_transaction(transaction)
client.wait_for_transaction(tx.id.unpack1("H*")) do |result|
  puts result.inspect
end

Sign a transaction with different payer and proposer

service_account_address = "f8d6e0586b0a20c7"
service_account_key = client.get_account(service_account_address).keys.first

service_account = client.get_account(service_account_address)
payer_signer = FlowClient::LocalSigner.new(service_account_private_key)

# Create a new account that will be executing the transaction
authorizer_priv_key, authorizer_pub_key = FlowClient::Crypto.generate_key_pair
new_account = client.create_account(authorizer_pub_key, service_account, payer_signer)
authorizer_signer = FlowClient::LocalSigner.new(
  authorizer_priv_key
)

arguments = [{ type: "String", value: "Hello world!" }.to_json]

transaction = FlowClient::Transaction.new
transaction.script = script
transaction.reference_block_id = reference_block_id
transaction.gas_limit = 100
transaction.proposer_address = service_account_address
transaction.proposer_key_index = service_account_key.index
transaction.arguments = arguments
transaction.proposer_key_sequence_number = service_account_key.sequence_number
transaction.payer_address = service_account_address
transaction.authorizer_addresses = [service_account_address]

# The authorizer signs the payload
transaction.add_payload_signature(new_account.address, new_account.keys.first.index, authorizer_signer)

# The payer signs the envelope
transaction.add_envelope_signature(service_account_address, service_account.keys.first.index, payer_signer)

tx = client.send_transaction(transaction)
client.wait_for_transaction(tx.id.unpack1("H*")) do |result|
  puts result.inspect
end

Sign a transaction with different authorizers using sign method multiple times

service_account_address = "f8d6e0586b0a20c7"
service_account_key = client.get_account(service_account_address).keys.first

arguments = [{ type: "String", value: "Hello world!" }.to_json]

priv_key_one, pub_key_one = FlowClient::Crypto.generate_key_pair
priv_key_two, pub_key_two = FlowClient::Crypto.generate_key_pair

payer_signer = FlowClient::LocalSigner.new(service_account_private_key)
payer_account = FlowClient::Account.new(address: service_account_address)
new_account = client.create_account(pub_key_one, payer_account, payer_signer)

auth_signer_one = FlowClient::LocalSigner.new(priv_key_one)
auth_signer_two = FlowClient::LocalSigner.new(priv_key_two)
client.add_account_key(new_account.address, pub_key_two, new_account, auth_signer_one, 1000.0)

new_account = client.get_account(new_account.address)

@transaction = FlowClient::Transaction.new
@transaction.script = script
@transaction.reference_block_id = client.get_latest_block.block.id.unpack1("H*")
@transaction.gas_limit = gas_limit
@transaction.proposer_address = new_account.address
@transaction.proposer_key_index = new_account.keys[0].index
@transaction.arguments = arguments
@transaction.proposer_key_sequence_number = new_account.keys[0].sequence_number
@transaction.payer_address = new_account.address
@transaction.authorizer_addresses = [new_account.address]
@transaction.add_envelope_signature(new_account.address, new_account.keys[0].index, auth_signer_one)
@transaction.add_envelope_signature(new_account.address, new_account.keys[1].index, auth_signer_two)
tx_res = client.send_transaction(@transaction)
client.wait_for_transaction(tx_res.id.unpack1("H*")) do |response|
  expect(response.status_code).to eq(0)
end

Tests

Running the tests require the emulator to be started.

docker-compose up
bundle exec rspec

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and the created tag, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/glucode/flow_client. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.

License

The gem is available as open source under the terms of the MIT License.

Code of Conduct

Everyone interacting in the FlowClient project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.

About

FlowClient is a Ruby gRPC client for Flow (onflow.org)

Resources

License

Code of conduct

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Ruby 99.7%
  • Shell 0.3%