bitshares 0.1.0.pre

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b9b32c0ea5eb6d1c9fff1dd36374f01b15122882
4
+ data.tar.gz: da5e2e39c271e30232052c9b193524637990bb01
5
+ SHA512:
6
+ metadata.gz: e969d690cba21ce4d2cdbebc0e935c5a7189c9ffeb067eaac8b025a211b17ceeff2c1f9d636aac4ebab2a988d0caac5573e952123ea2f02ca5a81bec96837638
7
+ data.tar.gz: 420309ee77866f3ef0be97dedb6ed4546f6eac8c93aa5d58f04d727620cf5fcf3428ae7ab83dbfc538969618738be913c6eedc2575cd5e181ee2b1a626435550
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.2
4
+ before_install: gem install bundler -v 1.10.2
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Bruce Steedman
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,155 @@
1
+ # Bitshares Ruby Gem
2
+
3
+ This Gem provides a Ruby API for the BitShares command line client by exposing the RPC commands of the [Bitshares client v0.x](https://github.com/bitshares/bitshares) as methods of it's Client class.
4
+
5
+ The binary client; "bitshares_client" must be installed, configured and running. The Gem detects the port the HTTP JSON RPC server is running on and expects the RPC endpoint to be `localhost` for security reasons - see [Configuration file settings](http://wiki.bitshares.org/index.php/BitShares/API).
6
+
7
+ ## Requirements
8
+
9
+ _Important:_ The interface uses the command line binary, not the GUI app.
10
+ Tested with v0.9.2 client on Mac OS X (10.9.5) and Ubuntu 14.04. Should work on any *NIX platform - sorry not Windows.
11
+
12
+ ## Installation
13
+
14
+ Add this line to your application's Gemfile:
15
+
16
+ ```ruby
17
+ gem 'bitshares-ruby'
18
+ ```
19
+
20
+ And then execute:
21
+
22
+ $ bundle
23
+
24
+ Or install it yourself as:
25
+
26
+ $ gem install bitshares-ruby
27
+
28
+ ## Authentication
29
+
30
+ RPC server login credentials (registered account name and password) must be stored in the following environment variables:-
31
+
32
+ `$BITSHARES_ACCOUNT`
33
+
34
+ `$BITSHARES_PASSWORD`
35
+
36
+ ## Configuration
37
+
38
+ The Gem allows multiple wallet names and passwords to be stored so that actions requiring these data may be automated.
39
+ To use this functionality - i.e. with the Wallet class (see below) wallet names and passwords must be configured in either of the following ways:
40
+
41
+ **Via a hash**
42
+ ```Ruby
43
+ Bitshares.configure(:wallet => {:name => 'wallet1', :password => 'password1'})
44
+ Bitshares.configure(:wallet => {:name => 'wallet2', :password => 'password2'})
45
+ ...
46
+ ```
47
+
48
+ **From a Yaml configuration file**
49
+ ```Ruby
50
+ Bitshares.configure_with(<path to Yaml file>) # 'wallets' and 'passwords' keys and array values must be used, as above
51
+ ```
52
+
53
+ ```Ruby
54
+ Bitshares.config # returns the configuration hash
55
+ ```
56
+
57
+ ## Usage
58
+
59
+ ### Quick start
60
+
61
+ ```ruby
62
+ require 'bitshares'
63
+
64
+ client = Bitshares::Client.init # The object BitShares RPC client calls are routed to.
65
+ ```
66
+ Any valid client command can then be issued via a method call with relevant parameters - e.g.
67
+
68
+ ```ruby
69
+ client.get_info
70
+ client.wallet_open 'default'
71
+ client.blockchain_list_delegates
72
+ client_wallet_market_submit_bid(account, amount, quote, price, base)
73
+ ...
74
+ ```
75
+
76
+ Data is returned as a hash
77
+
78
+ ### Detailed usage
79
+
80
+ **Blockchain**
81
+
82
+ The blockchain is implemented as a class purely for convenience when calling 'blockchain_' methods:
83
+ ```Ruby
84
+ chain = Bitshares::Blockchain
85
+ count = chain.get_block_count # equivalent to `client.blockchain_get_block_count`
86
+ ```
87
+
88
+ **Wallet**
89
+
90
+ ```Ruby
91
+ wallet = Bitshares::Wallet.new 'wallet1' # opens a wallet available on this client.
92
+ ```
93
+ Note that the following command opens the named wallet, but does not return an instance of Wallet class - use Wallet.new
94
+ ```Ruby
95
+ wallet.open 'wallet1'
96
+ ```
97
+
98
+ Thereafter 'wallet_' commands may be issued like this:
99
+ ```Ruby
100
+ wallet.get_info # gets info on this wallet, equivalent to client.wallet_get_info
101
+ wallet.transfer(amount, asset, from, recipient) # equivalent to - you get the picture..
102
+ ```
103
+ A wallet is unlocked and closed in a similar fashion:
104
+ ```Ruby
105
+ wallet.unlock
106
+ wallet.close
107
+ ```
108
+
109
+ Predicates are provided for convenience:
110
+ ```Ruby
111
+ wallet.open?
112
+ wallet.unlocked?
113
+ ```
114
+
115
+ **Account**
116
+
117
+ Once you have a wallet instance you can do this:
118
+ ```Ruby
119
+ account = wallet.account 'account_name'
120
+ ```
121
+ Thereafter 'wallet_account_' commands may be issued like this:
122
+ ```Ruby
123
+ account.balance
124
+ account.register(account_name, pay_from)
125
+ ```
126
+
127
+ **Market**
128
+
129
+ The market class represents the trading (order book and history) for a given an asset-pair - e.g. CNY/BTS. It is instantiated like this:
130
+ ```Ruby
131
+ market = Bitshares::Market.new(CNY, BTS)
132
+ ```
133
+ Any 'blockchain_market_' client method may then be used without specifying the quote and base assets again e.g:
134
+ ```Ruby
135
+ market.list_bids
136
+ market.order_history
137
+ ```
138
+
139
+ ## Testing and specification
140
+
141
+ `rake spec`
142
+
143
+ _Important:_ There is currently no sandbox, so the test suite runs on your live client. If this concerns you - and it should :scream: - feel free to browse the code. In particular, the following client 'fixtures' are required for the full test suite to run and pass:
144
+
145
+ An empty wallet 'test1', with password 'password1'
146
+
147
+ ## Contributing
148
+
149
+ Bug reports and pull requests are welcome on GitHub at https://github.com/MatzFan/bitshares-ruby.
150
+
151
+
152
+ ## License
153
+
154
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
155
+
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'bitshares-ruby'
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require 'irb'
14
+ IRB.start
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'bitshares/version'
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = 'bitshares'
8
+ s.version = Bitshares::VERSION
9
+ s.authors = ['Bruce Steedman']
10
+ s.email = ['bruce.steedman@gmail.com']
11
+
12
+ s.summary = %q{Ruby API for BitShares client}
13
+ s.description = %q{Exposes the BitShares client commands via RPC interface}
14
+ s.license = "MIT"
15
+
16
+ s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(spec)/}) }
17
+ s.bindir = 'exe'
18
+ s.executables = s.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
+ s.require_paths = ['lib']
20
+
21
+ s.add_development_dependency 'bundler', '~> 1.10'
22
+ s.add_development_dependency 'rake', '~> 10.0'
23
+ s.add_development_dependency 'rspec', '~> 3.0'
24
+ end
@@ -0,0 +1,41 @@
1
+ require 'bitshares/version'
2
+
3
+ require 'json'
4
+ require 'uri'
5
+ require 'net/http'
6
+ require 'yaml'
7
+
8
+ require 'bitshares/client'
9
+ require 'bitshares/blockchain'
10
+ require 'bitshares/wallet'
11
+ require 'bitshares/account'
12
+ require 'bitshares/market'
13
+
14
+ # stackoverflow.com/questions/6233124/where-to-place-access-config-file-in-gem
15
+ module Bitshares
16
+ @config = {:wallets => {nil => nil}} # name/password key/value pairs
17
+
18
+ @valid_keys = @config.keys
19
+
20
+ def self.configure(opts = {})
21
+ opts.each {|k,v| @config[k.to_sym] = v if @valid_keys.include? k.to_sym}
22
+ end
23
+
24
+ def self.configure_with(path_to_yaml_file)
25
+ begin
26
+ config = YAML::load(IO.read(path_to_yaml_file))
27
+ rescue Errno::ENOENT
28
+ puts "YAML configuration file couldn\'t be found. Using defaults"
29
+ return
30
+ rescue Psych::SyntaxError
31
+ puts 'YAML configuration file contains invalid syntax. Using defaults'
32
+ return
33
+ end
34
+
35
+ configure(config)
36
+ end
37
+
38
+ def self.config
39
+ @config
40
+ end
41
+ end
@@ -0,0 +1,18 @@
1
+ module Bitshares
2
+
3
+ class Account
4
+
5
+ attr_reader :wallet, :name
6
+
7
+ def initialize(wallet, name)
8
+ @wallet = wallet
9
+ @name = name
10
+ end
11
+
12
+ def method_missing(name, *args)
13
+ Bitshares::Client::rpc.request('wallet_account_' + name.to_s, args)
14
+ end
15
+
16
+ end
17
+
18
+ end
@@ -0,0 +1,11 @@
1
+ module Bitshares
2
+
3
+ class Blockchain
4
+
5
+ def self.method_missing(name, *args)
6
+ Bitshares::Client::rpc.request('blockchain_' + name.to_s, args)
7
+ end
8
+
9
+ end
10
+
11
+ end
@@ -0,0 +1,65 @@
1
+ module Bitshares
2
+
3
+ class Client
4
+
5
+ def self.init
6
+ @user = ENV['BITSHARES_ACCOUNT']
7
+ @password = ENV['BITSHARES_PASSWORD']
8
+ @@rpc_instance = Bitshares::Client::Rpc.new(@user, @password)
9
+ return self
10
+ end
11
+
12
+ def self.rpc
13
+ @@rpc_instance
14
+ end
15
+
16
+ def self.method_missing(method, *args)
17
+ @@rpc_instance.request(method, args)
18
+ end
19
+
20
+ class Rpc
21
+
22
+ class Err < RuntimeError; end
23
+
24
+ def initialize(user, password)
25
+ bitshares_running?
26
+ @uri = URI("http://localhost:#{rpc_http_port}/rpc")
27
+ @req = Net::HTTP::Post.new(@uri)
28
+ @req.content_type = 'application/json'
29
+ @req.basic_auth user, password
30
+ end
31
+
32
+ def request(m, args = [])
33
+ resp = nil
34
+ Net::HTTP.start(@uri.hostname, @uri.port) do |http|
35
+ @req.body = { method: m, params: args, jsonrpc: '2.0', id: 0 }.to_json
36
+ resp = http.request(@req)
37
+ end
38
+ raise Err, 'Bad credentials' if resp.class == Net::HTTPUnauthorized
39
+ result = JSON.parse(resp.body)
40
+ e = result['error']
41
+ raise Err, JSON.pretty_generate(e), "#{m} #{args.join(' ') if args}" if e
42
+ return result['result']
43
+ end
44
+
45
+ private
46
+
47
+ def bitshares_running?
48
+ raise Err, 'Server not running!' unless rpc_ports.count == 2
49
+ end
50
+
51
+ def rpc_http_port
52
+ rpc_ports.each do |port| # only http RPC port raises a non-empty response
53
+ return port unless `curl -s -I -L http://localhost:#{port}`.empty?
54
+ end
55
+ end
56
+
57
+ def rpc_ports # returns bitshares HTTP JSON RPC and JSON RPC server ports
58
+ `lsof -iTCP@localhost | grep bitshares`.scan(/:(\d+) \(LISTEN\)/).flatten
59
+ end
60
+
61
+ end
62
+
63
+ end
64
+
65
+ end
@@ -0,0 +1,102 @@
1
+ module Bitshares
2
+
3
+ class Market
4
+
5
+ class AssetError < RuntimeError; end
6
+
7
+ CHAIN = Bitshares::Blockchain
8
+ SELL_ORDER_TYPES = %w(ask_order cover_order)
9
+ BUY_ORDER_TYPES = %w(bid_order)
10
+
11
+ attr_reader :quote, :base
12
+
13
+ def initialize(quote_symbol, base_symbol)
14
+ @quote_hash = get_asset quote_symbol.upcase
15
+ @base_hash = get_asset base_symbol.upcase
16
+ @multiplier = multiplier
17
+ @quote = @quote_hash['symbol']
18
+ @base = @base_hash['symbol']
19
+ @order_book = order_book
20
+ end
21
+
22
+ def center_price
23
+ market_status['center_price']['ratio'].to_f
24
+ end
25
+
26
+ def last_fill
27
+ return -1 if order_hist.empty?
28
+ order_hist.first['bid_index']['order_price']['ratio'].to_f * multiplier
29
+ end
30
+
31
+ def mid_price
32
+ return nil if highest_bid.nil? || lowest_ask.nil?
33
+ (highest_bid + lowest_ask) / 2
34
+ end
35
+
36
+ def lowest_ask
37
+ return if asks.empty?
38
+ price asks.first
39
+ end
40
+
41
+ def highest_bid
42
+ return if bids.empty?
43
+ price bids.first
44
+ end
45
+
46
+ private
47
+
48
+ def get_asset(s)
49
+ CHAIN.get_asset(s) || (raise AssetError, "No such asset: #{s}")
50
+ end
51
+
52
+ def market_status
53
+ CHAIN.market_status(@quote, @base)
54
+ end
55
+
56
+ def order_book
57
+ CHAIN.market_order_book(@quote, @base)
58
+ end
59
+
60
+ def order_hist
61
+ CHAIN.market_order_history(@quote, @base)
62
+ end
63
+
64
+ def multiplier
65
+ @base_hash['precision'].to_f / @quote_hash['precision']
66
+ end
67
+
68
+ def check_new_order_type(order_list, order_types)
69
+ new_ = order_list.reject { |p| order_types.any? { |t| p['type'] == t } }
70
+ raise AssetError, "New order type: #{new_.first}" unless new_.empty?
71
+ order_list
72
+ end
73
+
74
+ def buy_orders
75
+ bids = @order_book.first
76
+ check_new_order_type(bids, BUY_ORDER_TYPES)
77
+ end
78
+
79
+ def bids
80
+ buy_orders.select { |p| p['type'] == 'bid_order' }
81
+ end
82
+
83
+ def sell_orders # includes 'ask_type' and 'cover_type'
84
+ asks = @order_book.last
85
+ check_new_order_type(asks, SELL_ORDER_TYPES)
86
+ end
87
+
88
+ def asks
89
+ sell_orders.select { |p| p['type'] == 'ask_order' }
90
+ end
91
+
92
+ def covers
93
+ sell_orders.select { |p| p['type'] == 'cover_order' }
94
+ end
95
+
96
+ def price(order) # CARE: preserve float precision with * NOT /
97
+ order['market_index']['order_price']['ratio'].to_f * @multiplier
98
+ end
99
+
100
+ end
101
+
102
+ end
@@ -0,0 +1,3 @@
1
+ module Bitshares
2
+ VERSION = '0.1.0.pre'
3
+ end
@@ -0,0 +1,54 @@
1
+ module Bitshares
2
+
3
+ class Wallet
4
+
5
+ attr_reader :name, :account
6
+
7
+ def initialize(name)
8
+ @name = name
9
+ @account = nil
10
+ @password = Bitshares.config[:wallets][@name.to_sym]
11
+ end
12
+
13
+ def account(name)
14
+ @account = Bitshares::Account.new(self, name)
15
+ end
16
+
17
+ def open
18
+ Bitshares::Client::rpc.request('wallet_open', [@name])
19
+ end
20
+
21
+ def lock
22
+ open # must be opened first
23
+ Bitshares::Client::rpc.request 'wallet_lock'
24
+ end
25
+
26
+ def unlock(timeout = 1776)
27
+ open # must be opened first
28
+ Bitshares::Client::rpc.request('wallet_unlock', [timeout, @password])
29
+ end
30
+
31
+ def open?
32
+ self.get_info['open']
33
+ end
34
+
35
+ def closed?
36
+ !open?
37
+ end
38
+
39
+ def unlocked?
40
+ open
41
+ get_info['unlocked']
42
+ end
43
+
44
+ def locked?
45
+ !unlocked?
46
+ end
47
+
48
+ def method_missing(name, *args)
49
+ Bitshares::Client::rpc.request('wallet_' + name.to_s, args)
50
+ end
51
+
52
+ end
53
+
54
+ end
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bitshares
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0.pre
5
+ platform: ruby
6
+ authors:
7
+ - Bruce Steedman
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2015-08-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.10'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.10'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ description: Exposes the BitShares client commands via RPC interface
56
+ email:
57
+ - bruce.steedman@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - ".rspec"
64
+ - ".travis.yml"
65
+ - Gemfile
66
+ - LICENSE.txt
67
+ - README.md
68
+ - Rakefile
69
+ - bin/console
70
+ - bin/setup
71
+ - bitshares-ruby.gemspec
72
+ - lib/bitshares-ruby.rb
73
+ - lib/bitshares/account.rb
74
+ - lib/bitshares/blockchain.rb
75
+ - lib/bitshares/client.rb
76
+ - lib/bitshares/market.rb
77
+ - lib/bitshares/version.rb
78
+ - lib/bitshares/wallet.rb
79
+ homepage:
80
+ licenses:
81
+ - MIT
82
+ metadata: {}
83
+ post_install_message:
84
+ rdoc_options: []
85
+ require_paths:
86
+ - lib
87
+ required_ruby_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ required_rubygems_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">"
95
+ - !ruby/object:Gem::Version
96
+ version: 1.3.1
97
+ requirements: []
98
+ rubyforge_project:
99
+ rubygems_version: 2.4.8
100
+ signing_key:
101
+ specification_version: 4
102
+ summary: Ruby API for BitShares client
103
+ test_files: []