bitshares 0.1.0.pre

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []