innox 2.7.6

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.
Files changed (53) hide show
  1. checksums.yaml +7 -0
  2. data/.drone.yml +29 -0
  3. data/.gitattributes +2 -0
  4. data/.gitignore +16 -0
  5. data/.rspec +3 -0
  6. data/.rubocop.yml +148 -0
  7. data/.simplecov +17 -0
  8. data/.travis.yml +18 -0
  9. data/Gemfile +8 -0
  10. data/Gemfile.lock +190 -0
  11. data/README.md +25 -0
  12. data/Rakefile +6 -0
  13. data/bin/console +14 -0
  14. data/bin/innox +12 -0
  15. data/bin/setup +8 -0
  16. data/checksums.yaml +7 -0
  17. data/innox.gemspec +52 -0
  18. data/lib/innox/adapter_registry.rb +25 -0
  19. data/lib/innox/auth/error.rb +18 -0
  20. data/lib/innox/auth/jwt_authenticator.rb +127 -0
  21. data/lib/innox/block.rb +27 -0
  22. data/lib/innox/blockchain/abstract.rb +159 -0
  23. data/lib/innox/blockchain/error.rb +37 -0
  24. data/lib/innox/blockchain/registry.rb +16 -0
  25. data/lib/innox/command/base.rb +11 -0
  26. data/lib/innox/command/db.rb +20 -0
  27. data/lib/innox/command/inject.rb +13 -0
  28. data/lib/innox/command/root.rb +14 -0
  29. data/lib/innox/command/security.rb +29 -0
  30. data/lib/innox/command/service.rb +40 -0
  31. data/lib/innox/error.rb +18 -0
  32. data/lib/innox/executor.rb +64 -0
  33. data/lib/innox/injectors/innox_events.rb +240 -0
  34. data/lib/innox/logger.rb +39 -0
  35. data/lib/innox/metrics/server.rb +15 -0
  36. data/lib/innox/mq/client.rb +51 -0
  37. data/lib/innox/ranger/connection.rb +117 -0
  38. data/lib/innox/ranger/events.rb +11 -0
  39. data/lib/innox/ranger/router.rb +234 -0
  40. data/lib/innox/ranger/web_socket.rb +68 -0
  41. data/lib/innox/security/key_generator.rb +26 -0
  42. data/lib/innox/sql/client.rb +19 -0
  43. data/lib/innox/sql/schema.rb +72 -0
  44. data/lib/innox/transaction.rb +136 -0
  45. data/lib/innox/upstream/base.rb +116 -0
  46. data/lib/innox/upstream/registry.rb +14 -0
  47. data/lib/innox/version.rb +3 -0
  48. data/lib/innox/wallet/abstract.rb +188 -0
  49. data/lib/innox/wallet/error.rb +37 -0
  50. data/lib/innox/wallet/registry.rb +16 -0
  51. data/lib/innox.rb +47 -0
  52. data/metadata +463 -0
  53. metadata +465 -0
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Innox::Ranger
4
+ def self.run(jwt_public_key, exchange_name, opts={})
5
+ host = opts[:ranger_host] || ENV["RANGER_HOST"] || "0.0.0.0"
6
+ port = opts[:ranger_port] || ENV["RANGER_PORT"] || "8081"
7
+
8
+ authenticator = Innox::Auth::JWTAuthenticator.new(jwt_public_key)
9
+
10
+ logger = Innox::Logger.logger
11
+ logger.info "Starting the server on port #{port}"
12
+
13
+ client = Innox::MQ::Client.new
14
+ router = Innox::Ranger::Router.new(opts[:registry])
15
+ client.subscribe(exchange_name, &router.method(:on_message))
16
+
17
+ if opts[:display_stats]
18
+ EM.add_periodic_timer(opts[:stats_period]) do
19
+ Innox::Logger.logger.info { router.stats }
20
+ Innox::Logger.logger.debug { router.debug }
21
+ end
22
+ end
23
+
24
+ EM::WebSocket.start(host: host, port: port, secure: false) do |socket|
25
+ connection = Innox::Ranger::Connection.new(router, socket, logger)
26
+ socket.onopen do |hs|
27
+ connection.handshake(authenticator, hs)
28
+ router.on_connection_open(connection)
29
+ end
30
+
31
+ socket.onmessage do |msg|
32
+ connection.handle(msg)
33
+ end
34
+
35
+ socket.onping do |value|
36
+ logger.debug { "Received ping: #{value}" }
37
+ end
38
+
39
+ socket.onclose do
40
+ logger.debug { "Websocket connection closed" }
41
+ router.on_connection_close(connection)
42
+ end
43
+
44
+ socket.onerror do |e|
45
+ logger.error { "WebSocket Error: #{e.message}\n" + e.backtrace.join("\n") }
46
+ end
47
+ end
48
+ end
49
+
50
+ def self.run!(jwt_public_key, exchange_name, opts={})
51
+ metrics_host = opts[:metrics_host] || ENV["METRICS_HOST"] || "0.0.0.0"
52
+ metrics_port = opts[:metrics_port] || ENV["METRICS_PORT"] || "8082"
53
+
54
+ EM.run do
55
+ run(jwt_public_key, exchange_name, opts)
56
+
57
+ if opts[:registry]
58
+ thin = Rack::Handler.get("thin")
59
+ thin.run(Innox::Metrics::Server.app(opts[:registry]), Host: metrics_host, Port: metrics_port)
60
+ end
61
+
62
+ trap("INT") do
63
+ puts "\nSIGINT received, stopping ranger..."
64
+ EM.stop
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,26 @@
1
+ require 'fileutils'
2
+
3
+ module Innox::Security
4
+ class KeyGenerator
5
+
6
+ attr_reader :public, :private
7
+
8
+ def initialize
9
+ OpenSSL::PKey::RSA.generate(2048).tap do |pkey|
10
+ @public = pkey.public_key.to_pem
11
+ @private = pkey.to_pem
12
+ end
13
+ end
14
+
15
+ def save(folder)
16
+ FileUtils.mkdir_p(folder) unless File.exists?(folder)
17
+
18
+ write(File.join(folder, 'rsa-key'), @private)
19
+ write(File.join(folder, 'rsa-key.pub'), @public)
20
+ end
21
+
22
+ def write(filename, text)
23
+ File.open(filename, 'w') { |file| file.write(text) }
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,19 @@
1
+ module Innox::Sql
2
+ class Client
3
+ attr_accessor :client, :config
4
+
5
+ def initialize
6
+ @config = {
7
+ host: ENV["DATABASE_HOST"] || "localhost",
8
+ username: ENV["DATABASE_USER"] || "root",
9
+ password: ENV["DATABASE_PASS"] || "",
10
+ port: ENV["DATABASE_PORT"] || "3306",
11
+ database: ENV["DATABASE_NAME"] || "innox_development",
12
+ }
13
+ end
14
+
15
+ def connect
16
+ @client = Mysql2::Client.new(config)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,72 @@
1
+ module Innox::Sql
2
+ class Schema
3
+ attr_accessor :client
4
+
5
+ def initialize(sql_client)
6
+ @client = sql_client
7
+ end
8
+
9
+ def create_database(name)
10
+ client.query("CREATE DATABASE IF NOT EXISTS `#{ name }`;")
11
+ end
12
+
13
+ def create_tables(options = {})
14
+ statements = []
15
+ statements << "DROP TABLE IF EXISTS `operations`;" if options[:drop_if_exists]
16
+ statements << <<-EOF
17
+ CREATE TABLE IF NOT EXISTS `operations` (
18
+ id INT UNSIGNED NOT NULL AUTO_INCREMENT,
19
+ code TINYINT UNSIGNED NOT NULL,
20
+ account_id INT UNSIGNED NOT NULL,
21
+ reference INT UNSIGNED NOT NULL,
22
+ debit DECIMAL(32, 16) NOT NULL,
23
+ credit DECIMAL(32, 16) NOT NULL,
24
+ created_at DATETIME NOT NULL,
25
+ updated_at DATETIME NOT NULL,
26
+ PRIMARY KEY (id),
27
+ INDEX `balance_key` (account_id, debit, credit)
28
+ ) ENGINE = InnoDB;
29
+ EOF
30
+
31
+ statements << "DROP TABLE IF EXISTS `orders`;" if options[:drop_if_exists]
32
+ statements << <<EOF
33
+ CREATE TABLE IF NOT EXISTS`orders` (
34
+ `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
35
+ `uid` INT(11) UNSIGNED NOT NULL,
36
+ `bid` VARCHAR(5) NOT NULL,
37
+ `ask` VARCHAR(5) NOT NULL,
38
+ `market` VARCHAR(10) NOT NULL,
39
+ `price` DECIMAL(32,16) DEFAULT NULL,
40
+ `volume` DECIMAL(32,16) NOT NULL,
41
+ `fee` DECIMAL(32,16) NOT NULL DEFAULT '0.0000000000000000',
42
+ `type` TINYINT UNSIGNED NOT NULL,
43
+ `state` TINYINT UNSIGNED NOT NULL,
44
+ `created_at` DATETIME NOT NULL,
45
+ `updated_at` DATETIME NOT NULL,
46
+ PRIMARY KEY (`id`)
47
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
48
+ EOF
49
+
50
+ statements << "DROP TABLE IF EXISTS `trades`;" if options[:drop_if_exists]
51
+ statements << <<EOF
52
+ CREATE TABLE IF NOT EXISTS `trades` (
53
+ `id` int(11) NOT NULL AUTO_INCREMENT,
54
+ `market` varchar(10) NOT NULL,
55
+ `volume` decimal(32,16) NOT NULL,
56
+ `price` decimal(32,16) NOT NULL,
57
+ `ask_id` int(11) NOT NULL,
58
+ `bid_id` int(11) NOT NULL,
59
+ `ask_uid` int(11) NOT NULL,
60
+ `bid_uid` int(11) NOT NULL,
61
+ `created_at` datetime NOT NULL,
62
+ `updated_at` datetime NOT NULL,
63
+ PRIMARY KEY (`id`)
64
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
65
+ EOF
66
+ statements.each do |statement|
67
+ puts statement
68
+ client.query(statement)
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,136 @@
1
+ require 'active_support/concern'
2
+ require 'active_support/core_ext/string/inquiry'
3
+ require 'active_support/core_ext/object/blank'
4
+ require 'active_model'
5
+
6
+ module Innox #:nodoc:
7
+
8
+ # This class represents blockchain transaction.
9
+ #
10
+ # Using the instant of this class the innox application will send/recieve
11
+ # income/outcome transactions from a innox pluggable blockchain.
12
+ #
13
+ # @example
14
+ #
15
+ # Innox::Transaction.new(
16
+ # {
17
+ # hash: '0x5d0ef9697a2f3ea561c9fbefb48e380a4cf3d26ad2be253177c472fdd0e8b486',
18
+ # txout: 1,
19
+ # to_address: '0x9af4f143cd5ecfba0fcdd863c5ef52d5ccb4f3e5',
20
+ # amount: 0.01,
21
+ # fee: 0.0004,
22
+ # block_number: 7732274,
23
+ # currency_id: 'eth',
24
+ # fee_currency_id: 'eth',
25
+ # status: 'success'
26
+ # }
27
+ # )
28
+ #
29
+
30
+ class Transaction
31
+ include ActiveModel::Model
32
+
33
+ # List of statuses supported by innox.
34
+ #
35
+ # @note Statuses list:
36
+ #
37
+ # pending - the transaction is unconfirmed in the blockchain or
38
+ # wasn't created yet.
39
+ #
40
+ # success - the transaction is a successfull,
41
+ # the transaction amount has been successfully transferred
42
+ #
43
+ # failed - the transaction is failed in the blockchain.
44
+ #
45
+ # rejected - the transaction is rejected by user.
46
+
47
+ STATUSES = %w[success pending failed rejected].freeze
48
+
49
+ DEFAULT_STATUS = 'pending'.freeze
50
+
51
+ # @!attribute [rw] hash
52
+ # return [String] transaction hash
53
+ attr_accessor :hash
54
+
55
+ # @!attribute [rw] txout
56
+ # return [Integer] transaction number in send-to-many request
57
+ attr_accessor :txout
58
+
59
+ # @!attribute [rw] from_address
60
+ # return [Array<String>] transaction source addresses
61
+ attr_accessor :from_addresses
62
+
63
+ # @!attribute [rw] to_address
64
+ # return [String] transaction recepient address
65
+ attr_accessor :to_address
66
+
67
+ # @!attribute [rw] amount
68
+ # return [Decimal] amount of the transaction
69
+ attr_accessor :amount
70
+
71
+ # @!attribute [rw] fee
72
+ # return [Decimal] fee of the transaction
73
+ attr_accessor :fee
74
+
75
+ # @!attribute [rw] block_number
76
+ # return [Integer] transaction block number
77
+ attr_accessor :block_number
78
+
79
+ # @!attribute [rw] currency_id
80
+ # return [String] transaction currency id
81
+ attr_accessor :currency_id
82
+
83
+ # @!attribute [rw] fee_currency_id
84
+ # return [String] transaction fee currency id
85
+ attr_accessor :fee_currency_id
86
+
87
+ # @!attribute [rw] options
88
+ # return [JSON] transaction options
89
+ attr_accessor :options
90
+
91
+ validates :to_address,
92
+ :amount,
93
+ :currency_id,
94
+ :status,
95
+ presence: true
96
+
97
+ validates :hash,
98
+ :block_number,
99
+ presence: { if: -> (t){ t.status.failed? || t.status.success? } }
100
+
101
+ validates :txout,
102
+ presence: { if: -> (t){ t.status.success? } }
103
+
104
+ validates :block_number,
105
+ numericality: { greater_than_or_equal_to: 0, only_integer: true }
106
+
107
+ validates :amount,
108
+ numericality: { greater_than_or_equal_to: 0 }
109
+
110
+ validates :fee,
111
+ numericality: { greater_than_or_equal_to: 0 }, allow_blank: true
112
+
113
+ validates :status, inclusion: { in: STATUSES }
114
+
115
+ def initialize(attributes={})
116
+ super
117
+ @status = @status.present? ? @status.to_s : DEFAULT_STATUS
118
+ end
119
+
120
+ # Status for specific transaction.
121
+ #
122
+ # @!method status
123
+ #
124
+ # @example
125
+ #
126
+ # status.failed? # true if transaction status 'failed'
127
+ # status.success? # true if transaction status 'success'
128
+ def status
129
+ @status&.inquiry
130
+ end
131
+
132
+ def status=(s)
133
+ @status = s.to_s
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Innox
4
+ module Upstream
5
+ class Base
6
+ DEFAULT_DELAY = 1
7
+ WEBSOCKET_CONNECTION_RETRY_DELAY = 2
8
+
9
+ attr_accessor :logger
10
+
11
+ def initialize(config)
12
+ @host = config["rest"]
13
+ @adapter = config[:faraday_adapter] || :em_synchrony
14
+ @config = config
15
+ @ws_status = false
16
+ @market = config['source']
17
+ @target = config['target']
18
+ @public_trades_cb = []
19
+ @logger = Innox::Logger.logger
20
+ @innox_mq = config['amqp']
21
+ mount
22
+ end
23
+
24
+ def mount
25
+ @public_trades_cb << method(:on_trade)
26
+ end
27
+
28
+ def ws_connect
29
+ logger.info { "Websocket connecting to #{@ws_url}" }
30
+ raise "websocket url missing for account #{id}" unless @ws_url
31
+
32
+ @ws = Faye::WebSocket::Client.new(@ws_url)
33
+
34
+ @ws.on(:open) do |_e|
35
+ subscribe_trades(@target, @ws)
36
+ subscribe_orderbook(@target, @ws)
37
+ logger.info { "Websocket connected" }
38
+ end
39
+
40
+ @ws.on(:message) do |msg|
41
+ ws_read_message(msg)
42
+ end
43
+
44
+ @ws.on(:close) do |e|
45
+ @ws = nil
46
+ @ws_status = false
47
+ logger.error "Websocket disconnected: #{e.code} Reason: #{e.reason}"
48
+ Fiber.new do
49
+ EM::Synchrony.sleep(WEBSOCKET_CONNECTION_RETRY_DELAY)
50
+ ws_connect
51
+ end.resume
52
+ end
53
+ end
54
+
55
+ def ws_connect_public
56
+ ws_connect
57
+ end
58
+
59
+ def subscribe_trades(_market, _ws)
60
+ method_not_implemented
61
+ end
62
+
63
+ def subscribe_orderbook(_market, _ws)
64
+ method_not_implemented
65
+ end
66
+
67
+ def ws_read_public_message(msg)
68
+ logger.info { "received public message: #{msg}" }
69
+ end
70
+
71
+ def ws_read_message(msg)
72
+ logger.debug {"received websocket message: #{msg.data}" }
73
+
74
+ object = JSON.parse(msg.data)
75
+ ws_read_public_message(object)
76
+ end
77
+
78
+ def on_trade(trade)
79
+ logger.info { "Publishing trade event: #{trade.inspect}" }
80
+ @innox_mq.enqueue_event("public", @market, "trades", {trades: [trade]})
81
+ @innox_mq.publish :trade, trade_json(trade), {
82
+ headers: {
83
+ type: :upstream,
84
+ market: @market,
85
+ }
86
+ }
87
+ end
88
+
89
+ def trade_json(trade)
90
+ trade.deep_symbolize_keys!
91
+ {
92
+ id: trade[:tid],
93
+ price: trade[:price],
94
+ amount: trade[:amount],
95
+ market_id: @market,
96
+ created_at: Time.at(trade[:date]).utc.iso8601,
97
+ taker_type: trade[:taker_type]
98
+ }
99
+ end
100
+
101
+ def notify_public_trade(trade)
102
+ @public_trades_cb.each {|cb| cb&.call(trade) }
103
+ end
104
+
105
+ def to_s
106
+ "Exchange::#{self.class} config: #{@opts}"
107
+ end
108
+
109
+ def build_error(response)
110
+ JSON.parse(response.body)
111
+ rescue StandardError => e
112
+ "Code: #{response.env.status} Message: #{response.env.reason_phrase}"
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Innox
4
+ module Upstream
5
+ class << self
6
+ def registry
7
+ @registry ||= Registry.new
8
+ end
9
+
10
+ class Registry < Innox::AdapterRegistry
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,3 @@
1
+ module Innox
2
+ VERSION = "2.7.6"
3
+ end
@@ -0,0 +1,188 @@
1
+ module Innox
2
+ module Wallet
3
+ # @abstract Represents basic wallet interface.
4
+ #
5
+ # Subclass and override abstract methods to implement
6
+ # a innox plugable wallet.
7
+ # Than you need to register your wallet implementation.
8
+ #
9
+ # @see Bitcoin::Wallet Bitcoin as example of Abstract imlementation.
10
+ #
11
+ # @example
12
+ #
13
+ # class MyWallet < Innox::Abstract::Wallet
14
+ # def create_address(options = {})
15
+ # # do something
16
+ # end
17
+ # ...
18
+ # end
19
+ #
20
+ # # Register MyWallet as innox plugable wallet.
21
+ # Innox::Wallet.registry[:my_wallet] = MyWallet.new
22
+ #
23
+
24
+ class Abstract
25
+ # Current wallet settings for performing API calls.
26
+ #
27
+ # @abstract
28
+ #
29
+ # @!attribute [r] settings
30
+ # @return [Hash] current wallet settings.
31
+ attr_reader :settings
32
+
33
+ # List of configurable settings.
34
+ #
35
+ # @see #configure
36
+ SUPPORTED_SETTINGS = %i[wallet currency].freeze
37
+
38
+ # Hash of features supported by wallet.
39
+ #
40
+ # @abstract
41
+ #
42
+ # @see Abstract::SUPPORTED_FEATURES for list of features supported by innox.
43
+ #
44
+ # @!attribute [r] features
45
+ # @return [Hash] list of features supported by wallet.
46
+ attr_reader :features
47
+
48
+ # List of features supported by innox.
49
+ #
50
+ # @note Features list:
51
+ #
52
+ # skip_deposit_collection - defines if deposit will be collected to
53
+ # hot, warm, cold wallets.
54
+ SUPPORTED_FEATURES = %i[skip_deposit_collection].freeze
55
+
56
+ # Abstract constructor.
57
+ #
58
+ # @abstract
59
+ #
60
+ # @example
61
+ # class MyWallet< Innox::Abstract::Wallet
62
+ #
63
+ # # You could customize your wallet by passing features.
64
+ # def initialize(my_custom_features = {})
65
+ # @features = my_custom_features
66
+ # end
67
+ # ...
68
+ # end
69
+ #
70
+ # # Register MyWallet as innox plugable wallet.
71
+ # custom_features = {cash_addr_format: true}
72
+ # Innox::Wallet.registry[:my_wallet] = MyWallet.new(custom_features)
73
+ def initialize(*)
74
+ abstract_method
75
+ end
76
+
77
+ # Merges given configuration parameters with defined during initialization
78
+ # and returns the result.
79
+ #
80
+ # @abstract
81
+ #
82
+ # @param [Hash] settings configurations to use.
83
+ # @option settings [Hash] :wallet Wallet settings for performing API calls.
84
+ # With :address required key other settings could be customized
85
+ # using Wallet#settings.
86
+ # @option settings [Array<Hash>] :currencies List of currency hashes
87
+ # with :id,:base_factor,:options(deprecated) keys.
88
+ # Custom keys could be added by defining them in Currency #options.
89
+ #
90
+ # @return [Hash] merged settings.
91
+ #
92
+ # @note Be careful with your wallet state after configure.
93
+ # Clean everything what could be related to other wallet configuration.
94
+ # E.g. client state.
95
+ def configure(settings = {})
96
+ abstract_method
97
+ end
98
+
99
+ # Performs API call for address creation and returns it.
100
+ #
101
+ # @abstract
102
+ #
103
+ # @param [Hash] options
104
+ # @options options [String] :uid User UID which requested address creation.
105
+ #
106
+ # @return [Hash] newly created blockchain address.
107
+ #
108
+ # @raise [Innox::Blockchain::ClientError] if error was raised
109
+ # on wallet API call.
110
+ #
111
+ # @example
112
+ # { address: :fake_address,
113
+ # secret: :changeme,
114
+ # details: { uid: account.member.uid } }
115
+ def create_address!(options = {})
116
+ abstract_method
117
+ end
118
+
119
+ # Performs API call for creating transaction and returns updated transaction.
120
+ #
121
+ # @abstract
122
+ #
123
+ # @param [Innox::Transaction] transaction transaction with defined
124
+ # to_address, amount & currency_id.
125
+ #
126
+ # @param [Hash] options
127
+ # @options options [String] :subtract_fee Defines if you need to subtract
128
+ # fee from amount defined in transaction.
129
+ # It means that you need to deduct fee from amount declared in
130
+ # transaction and send only remaining amount.
131
+ # If transaction amount is 1.0 and estimated fee
132
+ # for sending transaction is 0.01 you need to send 0.09
133
+ # so 1.0 (0.9 + 0.1) will be subtracted from wallet balance
134
+ #
135
+ # @options options [String] custon options for wallet client.
136
+ #
137
+ # @return [Innox::Transaction] transaction with updated hash.
138
+ #
139
+ # @raise [Innox::Blockchain::ClientError] if error was raised
140
+ # on wallet API call.
141
+ def create_transaction!(transaction, options = {})
142
+ abstract_method
143
+ end
144
+
145
+ # Fetches address balance of specific currency.
146
+ #
147
+ # @note Optional. Don't override this method if your blockchain
148
+ # doesn't provide functionality to get balance by address.
149
+ #
150
+ # @return [BigDecimal] the current address balance.
151
+ #
152
+ # @raise [Innox::Blockchain::ClientError,Innox::Blockchain::UnavailableAddressBalanceError]
153
+ # if error was raised on wallet API call ClientError is raised.
154
+ # if wallet API call was successful but we can't detect balance
155
+ # for address Error is raised.
156
+ def load_balance!
157
+ raise Innox::Wallet::UnavailableAddressBalanceError
158
+ end
159
+
160
+ # Performs API call(s) for preparing for deposit collection.
161
+ # E.g deposits ETH for collecting ERC20 tokens in case of Ethereum blockchain.
162
+ #
163
+ # @note Optional. Override this method only if you need additional step
164
+ # before deposit collection.
165
+ #
166
+ # @param [Innox::Transaction] deposit_transaction transaction which
167
+ # describes received deposit.
168
+ #
169
+ # @param [Array<Innox::Transaction>] spread_transactions result of deposit
170
+ # spread between wallets.
171
+ #
172
+ # @return [Array<Innox::Transaction>] transaction created for
173
+ # deposit collection preparing.
174
+ # By default return empty [Array]
175
+ def prepare_deposit_collection!(deposit_transaction, spread_transactions, deposit_currency)
176
+ # This method is mostly used for coins which needs additional fees
177
+ # to be deposited before deposit collection.
178
+ []
179
+ end
180
+
181
+ private
182
+
183
+ def abstract_method
184
+ method_not_implemented
185
+ end
186
+ end
187
+ end
188
+ end
@@ -0,0 +1,37 @@
1
+ module Innox
2
+ module Wallet
3
+ Error = Class.new(StandardError)
4
+
5
+ class ClientError < Error
6
+
7
+ attr_reader :wrapped_ex
8
+
9
+ def initialize(ex_or_string)
10
+ @wrapped_ex = nil
11
+
12
+ if ex_or_string.respond_to?(:backtrace)
13
+ super(ex_or_string.message)
14
+ @wrapped_exception = ex_or_string
15
+ else
16
+ super(ex_or_string.to_s)
17
+ end
18
+ end
19
+ end
20
+
21
+ class MissingSettingError < Error
22
+ def initialize(key)
23
+ super "#{key.capitalize} setting is missing"
24
+ end
25
+ end
26
+
27
+ class UnavailableAddressBalanceError < Error
28
+ def initialize(address)
29
+ @address = address
30
+ end
31
+
32
+ def message
33
+ "Unable to load #{@address} balance"
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,16 @@
1
+ require "innox/adapter_registry"
2
+
3
+ module Innox
4
+ module Wallet
5
+
6
+ VERSION = "1.0.0".freeze
7
+
8
+ class << self
9
+ def registry
10
+ @registry ||= Registry.new
11
+ end
12
+ end
13
+ class Registry < Innox::AdapterRegistry
14
+ end
15
+ end
16
+ end