peatio-jruby 2.6.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/.drone.yml +29 -0
  3. data/.gitignore +16 -0
  4. data/.rspec +3 -0
  5. data/.rubocop.yml +148 -0
  6. data/.simplecov +17 -0
  7. data/.tool-versions +1 -0
  8. data/.travis.yml +18 -0
  9. data/Gemfile +8 -0
  10. data/Gemfile.lock +198 -0
  11. data/README.md +47 -0
  12. data/Rakefile +6 -0
  13. data/bin/console +14 -0
  14. data/bin/peatio +12 -0
  15. data/bin/setup +8 -0
  16. data/lib/peatio.rb +52 -0
  17. data/lib/peatio/adapter_registry.rb +25 -0
  18. data/lib/peatio/auth/error.rb +18 -0
  19. data/lib/peatio/auth/jwt_authenticator.rb +127 -0
  20. data/lib/peatio/block.rb +29 -0
  21. data/lib/peatio/blockchain/abstract.rb +161 -0
  22. data/lib/peatio/blockchain/error.rb +37 -0
  23. data/lib/peatio/blockchain/registry.rb +16 -0
  24. data/lib/peatio/command/base.rb +11 -0
  25. data/lib/peatio/command/db.rb +20 -0
  26. data/lib/peatio/command/inject.rb +13 -0
  27. data/lib/peatio/command/root.rb +14 -0
  28. data/lib/peatio/command/security.rb +29 -0
  29. data/lib/peatio/command/service.rb +40 -0
  30. data/lib/peatio/error.rb +18 -0
  31. data/lib/peatio/executor.rb +64 -0
  32. data/lib/peatio/injectors/peatio_events.rb +240 -0
  33. data/lib/peatio/logger.rb +39 -0
  34. data/lib/peatio/metrics/server.rb +15 -0
  35. data/lib/peatio/mq/client.rb +51 -0
  36. data/lib/peatio/ranger/connection.rb +117 -0
  37. data/lib/peatio/ranger/events.rb +11 -0
  38. data/lib/peatio/ranger/router.rb +234 -0
  39. data/lib/peatio/ranger/web_socket.rb +68 -0
  40. data/lib/peatio/security/key_generator.rb +26 -0
  41. data/lib/peatio/sql/client.rb +19 -0
  42. data/lib/peatio/sql/schema.rb +72 -0
  43. data/lib/peatio/transaction.rb +122 -0
  44. data/lib/peatio/upstream/base.rb +116 -0
  45. data/lib/peatio/upstream/registry.rb +14 -0
  46. data/lib/peatio/version.rb +3 -0
  47. data/lib/peatio/wallet/abstract.rb +189 -0
  48. data/lib/peatio/wallet/error.rb +37 -0
  49. data/lib/peatio/wallet/registry.rb +16 -0
  50. data/peatio.gemspec +59 -0
  51. metadata +480 -0
@@ -0,0 +1,47 @@
1
+ ![Cryptocurrency Exchange Platform - OpenDAX](https://github.com/openware/meta/raw/main/images/github_opendax.png)
2
+
3
+ <h3 align="center">
4
+ <a href="https://www.openware.com/sdk">Guide</a> <span>&vert;</span>
5
+ <a href="https://www.openware.com/sdk/api.html">API Docs</a> <span>&vert;</span>
6
+ <a href="https://www.openware.com/">Consulting</a> <span>&vert;</span>
7
+ <a href="https://t.me/peatio">Community</a>
8
+ </h3>
9
+ <h6 align="center">Peatio is part of <a href="https://github.com/openware/opendax">OpenDAX Trading Platform</a></h6>
10
+
11
+ ---
12
+
13
+ # Peatio
14
+
15
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/peatio`. To experiment with that code, run `bin/console` for an interactive prompt.
16
+
17
+ TODO: Delete this and the text above, and describe your gem
18
+
19
+ ## Installation
20
+
21
+ Add this line to your application's Gemfile:
22
+
23
+ ```ruby
24
+ gem 'peatio'
25
+ ```
26
+
27
+ And then execute:
28
+
29
+ $ bundle
30
+
31
+ Or install it yourself as:
32
+
33
+ $ gem install peatio
34
+
35
+ ## Usage
36
+
37
+ TODO: Write usage instructions here
38
+
39
+ ## Development
40
+
41
+ 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.
42
+
43
+ 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 tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
44
+
45
+ ## Contributing
46
+
47
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/peatio.
@@ -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 "peatio"
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(__FILE__)
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- RUBY -*-
3
+
4
+ PEATIO_CORE = ENV["PEATIO_CORE"] || File.expand_path(File.join(File.dirname(__FILE__), ".."))
5
+ $: << File.join(PEATIO_CORE, "lib")
6
+
7
+ require "clamp"
8
+
9
+ require "peatio"
10
+ require "peatio/command/root"
11
+
12
+ Peatio::Root.run
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "logger"
4
+ require "json"
5
+ require "base64"
6
+ if defined?(JRUBY_VERSION)
7
+ require 'activerecord-jdbc-adapter'
8
+ require 'activerecord-jdbcmysql-adapter'
9
+ else
10
+ require "mysql2"
11
+ end
12
+ require "bunny"
13
+ require "eventmachine"
14
+ require "em-websocket"
15
+ require "socket"
16
+ require "securerandom"
17
+ require "rack"
18
+ require "prometheus/client"
19
+ require "prometheus/client/push"
20
+ require "prometheus/client/data_stores/single_threaded"
21
+ require "prometheus/middleware/exporter"
22
+
23
+ module Peatio
24
+ require_relative "peatio/error"
25
+ require_relative "peatio/logger"
26
+ require_relative "peatio/version"
27
+ require_relative "peatio/sql/client"
28
+ require_relative "peatio/sql/schema"
29
+ require_relative "peatio/mq/client"
30
+ require_relative "peatio/metrics/server"
31
+ require_relative "peatio/ranger/events"
32
+ require_relative "peatio/ranger/router"
33
+ require_relative "peatio/ranger/connection"
34
+ require_relative "peatio/ranger/web_socket"
35
+ require_relative "peatio/injectors/peatio_events"
36
+ require_relative "peatio/security/key_generator"
37
+ require_relative "peatio/auth/jwt_authenticator"
38
+
39
+ require_relative "peatio/blockchain/abstract"
40
+ require_relative "peatio/blockchain/error"
41
+ require_relative "peatio/blockchain/registry"
42
+
43
+ require_relative "peatio/wallet/abstract"
44
+ require_relative "peatio/wallet/error"
45
+ require_relative "peatio/wallet/registry"
46
+
47
+ require_relative "peatio/upstream/base"
48
+ require_relative "peatio/upstream/registry"
49
+
50
+ require_relative "peatio/transaction"
51
+ require_relative "peatio/block"
52
+ end
@@ -0,0 +1,25 @@
1
+ module Peatio
2
+ class AdapterRegistry
3
+ Error = Class.new(StandardError)
4
+ DuplicatedAdapterError = Class.new(Error)
5
+ NotRegisteredAdapterError = Class.new(Error)
6
+
7
+ def []=(name, instance)
8
+ name = name.to_sym
9
+ raise DuplicatedAdapterError, name if adapters.key?(name)
10
+ adapters[name] = instance
11
+ end
12
+
13
+ def [](name)
14
+ adapters.fetch(name.to_sym) { raise NotRegisteredAdapterError, name }
15
+ end
16
+
17
+ def adapters
18
+ @adapters ||= {}
19
+ end
20
+
21
+ def adapters=(h)
22
+ @adapters = h
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,18 @@
1
+ module Peatio::Auth
2
+ # Error repesent all errors that can be returned from Auth module.
3
+ class Error < Peatio::Error
4
+ # @return [String, JWT::*] Reason store underlying reason for given error.
5
+ #
6
+ # @see https://github.com/jwt/ruby-jwt/blob/master/lib/jwt/error.rb List of JWT::* errors.
7
+ attr_reader :reason
8
+
9
+ def initialize(reason = nil)
10
+ @reason = reason
11
+
12
+ super(
13
+ code: 2001,
14
+ text: "Authorization failed".tap { |t| t << ": #{reason}" if reason },
15
+ )
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,127 @@
1
+ require "jwt"
2
+
3
+ require_relative "error"
4
+
5
+ module Peatio::Auth
6
+ # JWTAuthenticator used to authenticate user using JWT.
7
+ #
8
+ # It allows configuration of JWT verification through following ENV
9
+ # variables (all optional):
10
+ # * JWT_ISSUER
11
+ # * JWT_AUDIENCE
12
+ # * JWT_ALGORITHM (default: RS256)
13
+ # * JWT_DEFAULT_LEEWAY
14
+ # * JWT_ISSUED_AT_LEEWAY
15
+ # * JWT_EXPIRATION_LEEWAY
16
+ # * JWT_NOT_BEFORE_LEEWAY
17
+ #
18
+ # @see https://github.com/jwt/ruby-jwt JWT validation parameters.
19
+ #
20
+ # @example Token validation
21
+ # rsa_private = OpenSSL::PKey::RSA.generate(2048)
22
+ # rsa_public = rsa_private.public_key
23
+ #
24
+ # payload = {
25
+ # iat: Time.now.to_i,
26
+ # exp: (Time.now + 60).to_i,
27
+ # sub: "session",
28
+ # iss: "barong",
29
+ # aud: [
30
+ # "peatio",
31
+ # "barong",
32
+ # ],
33
+ # jti: "BEF5617B7B2762DDE61702F5",
34
+ # uid: "TEST123",
35
+ # email: "user@example.com",
36
+ # role: "admin",
37
+ # level: 4,
38
+ # state: "active",
39
+ # }
40
+ #
41
+ # token = JWT.encode(payload, rsa_private, "RS256")
42
+ #
43
+ # auth = Peatio::Auth::JWTAuthenticator.new(rsa_public)
44
+ # auth.authenticate!("Bearer #{token}")
45
+ class JWTAuthenticator
46
+ # Creates new authenticator with given public key.
47
+ #
48
+ # @param public_key [OpenSSL::PKey::PKey] Public key object to verify
49
+ # signature.
50
+ # @param private_key [OpenSSL::PKey::PKey] Optional private key that used
51
+ # only to encode new tokens.
52
+ def initialize(public_key, private_key = nil)
53
+ @public_key = public_key
54
+ @private_key = private_key
55
+
56
+ @verify_options = {
57
+ verify_expiration: true,
58
+ verify_not_before: true,
59
+ iss: ENV["JWT_ISSUER"],
60
+ verify_iss: !ENV["JWT_ISSUER"].nil?,
61
+ verify_iat: true,
62
+ verify_jti: true,
63
+ aud: ENV["JWT_AUDIENCE"].to_s.split(",").reject(&:empty?),
64
+ verify_aud: !ENV["JWT_AUDIENCE"].nil?,
65
+ sub: "session",
66
+ verify_sub: true,
67
+ algorithms: [ENV["JWT_ALGORITHM"] || "RS256"],
68
+ leeway: ENV["JWT_DEFAULT_LEEWAY"].yield_self { |n| n.to_i unless n.nil? },
69
+ iat_leeway: ENV["JWT_ISSUED_AT_LEEWAY"].yield_self { |n| n.to_i unless n.nil? },
70
+ exp_leeway: ENV["JWT_EXPIRATION_LEEWAY"].yield_self { |n| n.to_i unless n.nil? },
71
+ nbf_leeway: ENV["JWT_NOT_BEFORE_LEEWAY"].yield_self { |n| n.to_i unless n.nil? },
72
+ }.compact
73
+
74
+ @encode_options = {
75
+ algorithm: @verify_options[:algorithms].first,
76
+ }.compact
77
+ end
78
+
79
+ # Decodes and verifies JWT.
80
+ # Returns payload from JWT or raises an exception
81
+ #
82
+ # @param token [String] Token string. Must start from <tt>"Bearer "</tt>.
83
+ # @return [Hash] Payload Hash from JWT without any changes.
84
+ #
85
+ # @raise [Peatio::Auth::Error] If token is invalid or can't be verified.
86
+ def authenticate!(token)
87
+ token_type, token_value = token.to_s.split(" ")
88
+
89
+ unless token_type == "Bearer"
90
+ raise(Peatio::Auth::Error, "Token type is not provided or invalid.")
91
+ end
92
+
93
+ decode_and_verify_token(token_value)
94
+ rescue => error
95
+ case error
96
+ when Peatio::Auth::Error
97
+ raise(error)
98
+ else
99
+ raise(Peatio::Auth::Error, error.message)
100
+ end
101
+ end
102
+
103
+ # Encodes given payload and produces JWT.
104
+ #
105
+ # @param payload [String, Hash] Payload to encode.
106
+ # @return [String] JWT token string.
107
+ #
108
+ # @raise [ArgumentError] If no private key was passed to constructor.
109
+ def encode(payload)
110
+ raise(::ArgumentError, "No private key given.") if @private_key.nil?
111
+
112
+ JWT.encode(payload, @private_key, @encode_options[:algorithm])
113
+ end
114
+
115
+ private
116
+
117
+ def decode_and_verify_token(token)
118
+ payload, header = JWT.decode(token, @public_key, true, @verify_options)
119
+
120
+ payload.keys.each { |k| payload[k.to_sym] = payload.delete(k) }
121
+
122
+ payload
123
+ rescue JWT::DecodeError => e
124
+ raise(Peatio::Auth::Error, "Failed to decode and verify JWT: #{e.message}")
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,29 @@
1
+ module Peatio #:nodoc:
2
+
3
+ # This class represents blockchain block which contains transactions.
4
+ #
5
+ # Using instant of this class in return for Peatio::Blockchain#fetch_block!
6
+ # @see Peatio::Blockchain#fetch_block! example implementation
7
+ # (inside peatio source https://github.com/rubykube/peatio)
8
+ #
9
+ # @author
10
+ # Maksym Naichuk <naichuk.maks@gmail.com> (https://github.com/mnaichuk)
11
+ class Block
12
+ include Enumerable
13
+
14
+ delegate :each, to: :@transactions
15
+
16
+ # @!attribute [r] number
17
+ # return [String] block number
18
+ attr_reader :number
19
+
20
+ # @!attribute [r] transactions
21
+ # return [Array<Peatio::Transaction>]
22
+ attr_reader :transactions
23
+
24
+ def initialize(number, transactions)
25
+ @number = number
26
+ @transactions = transactions
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,161 @@
1
+ module Peatio #:nodoc:
2
+ module Blockchain #:nodoc:
3
+
4
+ # @abstract Represents basic blockchain interface.
5
+ #
6
+ # Subclass and override abstract methods to implement
7
+ # a peatio plugable blockchain.
8
+ # Then you need to register your blockchain implementation.
9
+ #
10
+ # @see Bitcoin::Blockchain Bitcoin as example of Abstract imlementation
11
+ # (inside peatio source https://github.com/rubykube/peatio).
12
+ #
13
+ # @example
14
+ #
15
+ # class MyBlockchain < Peatio::Abstract::Blockchain
16
+ # def fetch_block(block_number)
17
+ # # do something
18
+ # end
19
+ # ...
20
+ # end
21
+ #
22
+ # # Register MyBlockchain as peatio plugable blockchain.
23
+ # Peatio::Blockchain.registry[:my_blockchain] = MyBlockchain.new
24
+ #
25
+ # @author
26
+ # Yaroslav Savchuk <savchukyarpolk@gmail.com> (https://github.com/ysv)
27
+ class Abstract
28
+
29
+ # Hash of features supported by blockchain.
30
+ #
31
+ # @abstract
32
+ #
33
+ # @see Abstract::SUPPORTED_FEATURES for list of features supported by peatio.
34
+ #
35
+ # @!attribute [r] features
36
+ # @return [Hash] list of features supported by blockchain.
37
+ attr_reader :features
38
+
39
+ # List of features supported by peatio.
40
+ #
41
+ # @note Features list:
42
+ #
43
+ # case_sensitive - defines if transactions and addresses of current
44
+ # blockchain are case_sensitive.
45
+ #
46
+ # cash_addr_format - defines if blockchain supports Cash Address format
47
+ # for more info see (https://support.exodus.io/article/664-bitcoin-cash-address-format)
48
+ SUPPORTED_FEATURES = %i[case_sensitive cash_addr_format].freeze
49
+
50
+
51
+ # Current blockchain settings for performing API calls and building blocks.
52
+ #
53
+ # @abstract
54
+ #
55
+ # @see Abstract::SUPPORTED_SETTINGS for list of settings required by blockchain.
56
+ #
57
+ # @!attribute [r] settings
58
+ # @return [Hash] current blockchain settings.
59
+ attr_reader :settings
60
+
61
+ # List of configurable settings.
62
+ #
63
+ # @see #configure
64
+ SUPPORTED_SETTINGS = %i[server currencies].freeze
65
+
66
+
67
+ # Abstract constructor.
68
+ #
69
+ # @abstract
70
+ #
71
+ # @example
72
+ # class MyBlockchain < Peatio::Abstract::Blockchain
73
+ #
74
+ # DEFAULT_FEATURES = {case_sensitive: true, cash_addr_format: false}.freeze
75
+ #
76
+ # # You could override default features by passing them to initializer.
77
+ # def initialize(my_custom_features = {})
78
+ # @features = DEFAULT_FEATURES.merge(my_custom_features)
79
+ # end
80
+ # ...
81
+ # end
82
+ #
83
+ # # Register MyBlockchain as peatio plugable blockchain.
84
+ # custom_features = {cash_addr_format: true}
85
+ # Peatio::Blockchain.registry[:my_blockchain] = MyBlockchain.new(custom_features)
86
+ def initialize(*)
87
+ abstract_method
88
+ end
89
+
90
+ # Merges given configuration parameters with defined during initialization
91
+ # and returns the result.
92
+ #
93
+ # @abstract
94
+ #
95
+ # @param [Hash] settings parameters to use.
96
+ #
97
+ # @option settings [String] :server Public blockchain API endpoint.
98
+ # @option settings [Array<Hash>] :currencies List of currency hashes
99
+ # with :id,:base_factor,:options(deprecated) keys.
100
+ # Custom keys could be added by defining them in Currency #options.
101
+ #
102
+ # @return [Hash] merged settings.
103
+ #
104
+ # @note Be careful with your blockchain state after configure.
105
+ # Clean everything what could be related to other blockchain configuration.
106
+ # E.g. client state.
107
+ def configure(settings = {})
108
+ abstract_method
109
+ end
110
+
111
+ # Fetches blockchain block by calling API and builds block object
112
+ # from response payload.
113
+ #
114
+ # @abstract
115
+ #
116
+ # @param block_number [Integer] the block number.
117
+ # @return [Peatio::Block] the block object.
118
+ # @raise [Peatio::Blockchain::ClientError] if error was raised
119
+ # on blockchain API call.
120
+ def fetch_block!(block_number)
121
+ abstract_method
122
+ end
123
+
124
+ # Fetches current blockchain height by calling API and returns it as number.
125
+ #
126
+ # @abstract
127
+ #
128
+ # @return [Integer] the current blockchain height.
129
+ # @raise [Peatio::Blockchain::ClientError] if error was raised
130
+ # on blockchain API call.
131
+ def latest_block_number
132
+ abstract_method
133
+ end
134
+
135
+ # Fetches address balance of specific currency.
136
+ #
137
+ # @note Optional. Don't override this method if your blockchain
138
+ # doesn't provide functionality to get balance by address.
139
+ #
140
+ # @param address [String] the address for requesting balance.
141
+ # @param currency_id [String] which currency balance we need to request.
142
+ # @return [BigDecimal] the current address balance.
143
+ # @raise [Peatio::Blockchain::ClientError,Peatio::Blockchain::UnavailableAddressBalanceError]
144
+ # if error was raised on blockchain API call ClientError is raised.
145
+ # if blockchain API call was successful but we can't detect balance
146
+ # for address Error is raised.
147
+ def load_balance_of_address!(address, currency_id)
148
+ raise Peatio::Blockchain::UnavailableAddressBalanceError
149
+ end
150
+
151
+ private
152
+
153
+ # Method for defining other methods as abstract.
154
+ #
155
+ # @raise [MethodNotImplemented]
156
+ def abstract_method
157
+ method_not_implemented
158
+ end
159
+ end
160
+ end
161
+ end