blockbee 1.0.0 → 1.1.0

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 (7) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/README.md +91 -29
  4. data/lib/blockbee.rb +158 -125
  5. data/sig/blockbee.rbs +50 -70
  6. metadata +19 -10
  7. data/.DS_Store +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c080ab8111b7508dc3daca4996dd881cf24a1efad69689cd3657bc954932e656
4
- data.tar.gz: e7887ce185ad0f67b40dd219964238cfabd58ee07ce4c1dd9476ceb4f7f8f65c
3
+ metadata.gz: becf07a555e1c0b7698363dff5c0457f3d410c2a683fb10f17aa4c2534ec1e39
4
+ data.tar.gz: 5f0b5a6540ecfd72aa0b465452a2acdb6970556e7967e6354c8825872d6043be
5
5
  SHA512:
6
- metadata.gz: ec6e38347c2af3918cbd4f04e52978698ace2c662c8762f4f371ce69684daa1b04795b2dd4225daa182af5bfc1b6e43a6682e73e9a462744f06ddc8e71b17ad1
7
- data.tar.gz: e300deeb203d4da1c92f9093889ef1e3c8329c9c47f50c7318944932203d07a2b648a2d94232dc2539ed26ed69d689147eb4d09c2ff0d439dd6172f97b9a2ebf
6
+ metadata.gz: cf2c2c22bfcfbaf8a05ef47f25dadfe0651d9867cc6d95debed0d6d0480976ccdcb55ba354055cc001db011a152dbb3149d42791f35cad644064e73742414732
7
+ data.tar.gz: 4595ea4e231ab5918e3ac0cc437cbc6f739e843076abf2949ad6f02f3e00d9db6abd5e750afae5d505943d86b408fa0839a5245d2e934584f9effa87c1adeaeb
data/CHANGELOG.md CHANGED
@@ -2,5 +2,11 @@
2
2
 
3
3
  ## 1.0.0
4
4
 
5
+ ## 1.0.1
6
+ * Minor bugfix
7
+
8
+ ## 1.1.0
9
+ * Various improvements
10
+
5
11
  ### Features
6
12
  - Support for BlockBee API, Payouts and Checkout page
data/README.md CHANGED
@@ -19,15 +19,15 @@ Ruby >= 3
19
19
 
20
20
  ## Installation
21
21
 
22
- TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
23
-
24
22
  Install the gem and add to the application's Gemfile by executing:
25
23
 
26
- $ bundle add UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
24
+ $ bundle add blockbee
27
25
 
28
26
  If bundler is not being used to manage dependencies, install the gem by executing:
29
27
 
30
- $ gem install UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
28
+ $ gem install blockbee
29
+
30
+ [RubyGem Page](https://rubygems.org/gems/blockbee/versions/1.0.0)
31
31
 
32
32
  ## API and utils
33
33
 
@@ -42,17 +42,16 @@ require 'blockbee'
42
42
  ```ruby
43
43
  require 'blockbee'
44
44
 
45
- info = BlockBee::API.get_info(coin, api_key, prices)
45
+ info = BlockBee::API.get_info(coin, prices)
46
46
 
47
47
  # or if you wish to get full BlockBee service information
48
48
 
49
- info = BlockBee::API.get_info(nil, api_key, prices)
49
+ info = BlockBee::API.get_info(nil, prices)
50
50
 
51
51
  ```
52
52
 
53
53
  ### Where
54
54
  * ``coin`` is the coin you wish to use, from BlockBee's supported currencies (e.g 'btc', 'eth', 'erc20_usdt', ...).
55
- * ``api_key`` is the API Key provided by BlockBee's [dashboard](https://dash.blockbee.io/).
56
55
  * ``prices`` by default `0`. If `1` will return the prices of the cryptocurrencies converted to all supported FIAT currencies.
57
56
 
58
57
  ### Generating a new Address
@@ -60,7 +59,7 @@ info = BlockBee::API.get_info(nil, api_key, prices)
60
59
  ```ruby
61
60
  require 'blockbee'
62
61
 
63
- blockbee_helper = BlockBee::API.new(coin, own_address, callback_url, parameters, bb_params, api_key)
62
+ blockbee_helper = BlockBee::API.new(coin, callback_url, api_key, own_address: own_address, parameters: parameters, bb_params: bb_params)
64
63
 
65
64
  address = blockbee_helper.get_address
66
65
 
@@ -70,11 +69,11 @@ address = blockbee_helper.get_address
70
69
  #### Where:
71
70
 
72
71
  * ``coin`` is the coin you wish to use, from BlockBee's supported currencies (e.g 'btc', 'eth', 'erc20_usdt', ...).
73
- * ``own_address`` is your own crypto address, where your funds will be sent to.
74
72
  * ``callback_url`` is the URL that will be called upon payment.
75
- * ``parameters`` is any parameter you wish to send to identify the payment, such as `{orderId: 1234}`.
76
- * ``bb_params`` parameters that will be passed to BlockBee _(check which extra parameters are available here: https://docs.blockbee.io/#operation/create).
77
73
  * ``api_key`` is the API Key provided by BlockBee's [dashboard](https://dash.blockbee.io/).
74
+ * ``own_address`` (optional) is your own crypto address, where your funds will be sent to.
75
+ * ``parameters`` (optional) is any parameter you wish to send to identify the payment, such as `{orderId: 1234}`.
76
+ * ``bb_params`` (optional) parameters that will be passed to BlockBee _(check which extra parameters are available here: https://docs.blockbee.io/#operation/create).
78
77
 
79
78
  #### Response sample:
80
79
 
@@ -99,7 +98,7 @@ address = blockbee_helper.get_address
99
98
  ```ruby
100
99
  require 'blockbee'
101
100
 
102
- blockbee_helper = BlockBee::API.new(coin, own_address, callback_url, parameters, bb_params, api_key)
101
+ blockbee_helper = BlockBee::API.new(coin, callback_url, api_key, own_address: own_address, parameters: parameters, bb_params: bb_params)
103
102
 
104
103
  logs = blockbee_helper.get_logs
105
104
  ```
@@ -125,16 +124,15 @@ logs = blockbee_helper.get_logs
125
124
  ```ruby
126
125
  require 'blockbee'
127
126
 
128
- blockbee_helper = BlockBee::API.new(coin, own_address, callback_url, parameters, bb_params, api_key)
127
+ blockbee_helper = BlockBee::API.new(coin, callback_url, api_key, own_address: own_address, parameters: parameters, bb_params: bb_params)
129
128
 
130
- qrcode = blockbee_helper.get_qrcode(value, size)
129
+ qrcode = blockbee_helper.get_qrcode(value: value, size: size)
131
130
  ```
132
131
 
133
132
  #### Where:
134
133
 
135
134
  * ``value`` is the value requested to the user in the coin to which the request was done. **Optional**, can be empty if you don't wish to add the value to the QR Code.
136
- * ``size`` Size of the QR Code image in pixels. Optional, leave empty to use the default size of 512.
137
- * ``api_key`` is the API Key provided by BlockBee's [dashboard](https://dash.blockbee.io/).
135
+ * ``size`` Size of the QR Code image in pixels. Optional, leave empty to use the default size of 300.
138
136
 
139
137
  > Response is an object with `qr_code` (base64 encoded image data) and `payment_uri` (the value encoded in the QR), see https://docs.blockbee.io/#operation/qrcode for more information.
140
138
 
@@ -157,14 +155,13 @@ qrcode = blockbee_helper.get_qrcode(value, size)
157
155
  ```ruby
158
156
  require 'blockbee'
159
157
 
160
- estimation = BlockBee::API.get_estimate(coin, addresses, priority, api_key)
158
+ estimation = BlockBee::API.get_estimate(coin, addresses, priority)
161
159
  ```
162
160
 
163
161
  #### Where:
164
162
  * ``coin`` is the coin you wish to check, from BlockBee's supported currencies (e.g 'btc', 'eth', 'erc20_usdt', ...)
165
163
  * ``addresses`` The number of addresses to forward the funds to. Optional, defaults to 1.
166
164
  * ``priority`` Confirmation priority, (check [this](https://support.blockbee.io/article/how-the-priority-parameter-works) article to learn more about it). Optional, defaults to ``default``.
167
- * ``api_key`` is the API Key provided by BlockBee's [dashboard](https://dash.blockbee.io/).
168
165
 
169
166
  > Response is an object with ``estimated_cost`` and ``estimated_cost_usd``, see https://docs.blockbee.io/#operation/estimate for more information.
170
167
 
@@ -188,7 +185,7 @@ estimation = BlockBee::API.get_estimate(coin, addresses, priority, api_key)
188
185
  ```ruby
189
186
  require 'blockbee'
190
187
 
191
- blockbee_helper = BlockBee::API.new(coin, own_address, callback_url, parameters, bb_params, api_key)
188
+ blockbee_helper = BlockBee::API.new(coin, callback_url, api_key, own_address: own_address, parameters: parameters, bb_params: bb_params)
192
189
 
193
190
  conversion = blockbee_helper.get_conversion(from_coin, value)
194
191
  ```
@@ -215,12 +212,9 @@ conversion = blockbee_helper.get_conversion(from_coin, value)
215
212
  ```ruby
216
213
  require 'blockbee'
217
214
 
218
- supported_coins = BlockBee::API.get_supported_coins(api_key)
215
+ supported_coins = BlockBee::API.get_supported_coins
219
216
  ```
220
217
 
221
- ### Where:
222
- * ``api_key`` is the API Key provided by BlockBee's [dashboard](https://dash.blockbee.io/).
223
-
224
218
  > Response is an array with all supported coins.
225
219
 
226
220
  #### Response sample:
@@ -414,8 +408,8 @@ If `process` is `false`.
414
408
  {
415
409
  "status": "success",
416
410
  "request_ids": [
417
- 103227,
418
- 103228
411
+ "3825d29b-7a8f-47da-8623-e99850674247",
412
+ "d9925105-ea5f-4661-8d01-505096212ac5"
419
413
  ]
420
414
  }
421
415
  ```
@@ -424,6 +418,22 @@ If `process` is `true`.
424
418
  ```json
425
419
  {
426
420
  "status": "success",
421
+ "payout_info": {
422
+ "id": "d9219d07-a8e5-4d89-a869-3c5717a25b27",
423
+ "status": "Created",
424
+ "from": "",
425
+ "requests": {
426
+ "0xA8EbeD50f2e05fB4a25b2DdCdc651A7CA769B5CF": "0.300000000000000000",
427
+ "0xA6B78B56ee062185E405a1DDDD18cE8fcBC4395d": "0.200000000000000000"
428
+ },
429
+ "total_requested": "0.5",
430
+ "total_with_fee": "0.505",
431
+ "total_fiat": "",
432
+ "fee": "0.005",
433
+ "coin": "bep20_usdt",
434
+ "txid": "",
435
+ "timestamp": "05/03/2024 15:00:00"
436
+ },
427
437
  "queued": true
428
438
  }
429
439
  ```
@@ -456,7 +466,7 @@ list_payouts = BlockBee::API.list_payouts(coin, status, page, api_key, payout_re
456
466
  "status": "success",
457
467
  "payouts": [
458
468
  {
459
- "id": 2460,
469
+ "id": "3825d29b-7a8f-47da-8623-e99850674247",
460
470
  "status": "Done",
461
471
  "total_requested": "0.6",
462
472
  "total_with_fee": "0.606",
@@ -514,7 +524,7 @@ payout = BlockBee::API.create_payout_by_ids(api_key, payout_ids)
514
524
  {
515
525
  "status": "success",
516
526
  "payout_info": {
517
- "id": 2461,
527
+ "id": "d9219d07-a8e5-4d89-a869-3c5717a25b27",
518
528
  "status": "Created",
519
529
  "from": "",
520
530
  "requests": {
@@ -550,7 +560,23 @@ payout = BlockBee::API.process_payout(api_key, payout_ids)
550
560
 
551
561
  ```json
552
562
  {
553
- "status": "success",
563
+ "status": "success",
564
+ "payout_info": {
565
+ "id": "d9219d07-a8e5-4d89-a869-3c5717a25b27",
566
+ "status": "Created",
567
+ "from": "",
568
+ "requests": {
569
+ "0xA8EbeD50f2e05fB4a25b2DdCdc651A7CA769B5CF": "0.300000000000000000",
570
+ "0xA6B78B56ee062185E405a1DDDD18cE8fcBC4395d": "0.200000000000000000"
571
+ },
572
+ "total_requested": "0.5",
573
+ "total_with_fee": "0.505",
574
+ "total_fiat": "",
575
+ "fee": "0.005",
576
+ "coin": "bep20_usdt",
577
+ "txid": "",
578
+ "timestamp": "05/03/2024 15:00:00"
579
+ },
554
580
  "queued": true
555
581
  }
556
582
  ```
@@ -577,7 +603,7 @@ status = BlockBee::API.check_payout_status(api_key, payout_id)
577
603
  {
578
604
  "status": "success",
579
605
  "payout_info": {
580
- "id": 2463,
606
+ "id": "d9219d07-a8e5-4d89-a869-3c5717a25b27",
581
607
  "status": "Done",
582
608
  "from": "0x18B211A1Ba5880C7d62C250B6441C2400d588589",
583
609
  "requests": {
@@ -595,6 +621,42 @@ status = BlockBee::API.check_payout_status(api_key, payout_id)
595
621
  }
596
622
  ```
597
623
 
624
+ ## Testing
625
+
626
+ ### Option 1: Using .env file (Recommended)
627
+
628
+ 1. Copy the example environment file:
629
+ ```bash
630
+ cp .env.example .env
631
+ ```
632
+
633
+ 2. Edit `.env` with your actual API credentials:
634
+ ```bash
635
+ # Required: Your BlockBee API Key from https://dash.blockbee.io/
636
+ BLOCKBEE_API_KEY=your-actual-api-key-here
637
+
638
+ # Required: Callback URL for payment notifications
639
+ BLOCKBEE_CALLBACK_URL=https://your-domain.com/webhook
640
+ ```
641
+
642
+ 3. Install dependencies and run tests:
643
+ ```bash
644
+ bundle install
645
+ bundle exec rake test
646
+ ```
647
+
648
+ ### Option 2: Using environment variables
649
+
650
+ Alternatively, you can set environment variables directly:
651
+
652
+ ```bash
653
+ export BLOCKBEE_API_KEY="your-api-key-here"
654
+ export BLOCKBEE_CALLBACK_URL="https://your-domain.com/webhook"
655
+ bundle exec rake test
656
+ ```
657
+
658
+ **Note:** If no API key is provided, only basic tests (like version check) will run. The `.env` file is automatically ignored by git to keep your credentials secure.
659
+
598
660
  ## Help
599
661
 
600
662
  Need help?
data/lib/blockbee.rb CHANGED
@@ -5,36 +5,79 @@ require 'uri'
5
5
  require 'json'
6
6
 
7
7
  module BlockBee
8
+ class APIError < StandardError
9
+ attr_reader :status_code
10
+
11
+ def initialize(message, status_code)
12
+ super(message)
13
+ @status_code = status_code
14
+ end
15
+
16
+ def self.from_status_code(status_code, message)
17
+ case status_code
18
+ when 400
19
+ new("Bad Request: #{message}", 400)
20
+ when 401
21
+ new("Unauthorized: #{message}", 401)
22
+ when 403
23
+ new("Forbidden: #{message}", 403)
24
+ when 404
25
+ new("Not Found: #{message}", 404)
26
+ when 500
27
+ new("Internal Server Error", 500)
28
+ else
29
+ new("Unexpected Error: #{message}", status_code)
30
+ end
31
+ end
32
+ end
33
+
34
+ class MissingAPIKeyError < StandardError; end
35
+
36
+ class CallbackURLMissing < StandardError; end
37
+
8
38
  class Error < StandardError; end
9
39
 
10
- VERSION = "1.0.0"
40
+ VERSION = "1.1.0"
11
41
 
12
42
  BLOCKBEE_URL = 'https://api.blockbee.io/'
13
43
  BLOCKBEE_HOST = 'api.blockbee.io'
14
44
 
15
45
  class API
16
- def initialize(coin, own_address = '', callback_url, parameters, bb_params, api_key)
17
- raise 'API Key Missing' if api_key.nil?
18
-
19
- raise 'Callback URL Missing' if callback_url.nil?
20
-
21
- @callback_url = callback_url
22
- @coin = coin
23
- @own_address = own_address
24
- @parameters = parameters || {}
25
- @bb_params = bb_params || {}
26
- @api_key = api_key
27
- @payment_address = ''
28
-
29
- if parameters
30
- _cb = URI::parse(callback_url)
46
+ def initialize(coin, callback_url, api_key, own_address: '', parameters: {}, bb_params: {})
47
+ raise BlockBee::MissingAPIKeyError, 'Provide your API Key' if api_key.nil? || api_key.empty?
48
+ raise BlockBee::CallbackURLMissing, 'Provide your callback URL' if callback_url.nil? || callback_url.empty?
49
+ raise ArgumentError, 'Coin must be a string' unless coin.nil? || coin.is_a?(String)
50
+ raise ArgumentError, 'Parameters must be a hash' unless parameters.is_a?(Hash)
51
+ raise ArgumentError, 'BB params must be a hash' unless bb_params.is_a?(Hash)
52
+
53
+ begin
54
+ _cb = URI.parse(callback_url)
55
+ raise ArgumentError, 'Invalid callback URL' unless _cb.scheme && _cb.host
56
+ rescue URI::InvalidURIError
57
+ raise ArgumentError, 'Invalid callback URL format'
58
+ end
31
59
 
60
+ # Preserve original scheme (HTTP/HTTPS) for development flexibility
61
+ if _cb.scheme.downcase == 'https'
32
62
  @callback_url = URI::HTTPS.build(
33
63
  host: _cb.host,
34
64
  path: _cb.path,
35
65
  query: URI.encode_www_form(parameters)
36
66
  )
67
+ else
68
+ @callback_url = URI::HTTP.build(
69
+ host: _cb.host,
70
+ path: _cb.path,
71
+ query: URI.encode_www_form(parameters)
72
+ )
37
73
  end
74
+
75
+ @coin = coin
76
+ @own_address = own_address
77
+ @parameters = parameters
78
+ @bb_params = bb_params
79
+ @api_key = api_key
80
+ @payment_address = ''
38
81
  end
39
82
 
40
83
  def get_address
@@ -46,12 +89,10 @@ module BlockBee
46
89
  }.merge(@bb_params)
47
90
 
48
91
  if !@own_address.nil? && !@own_address.empty?
49
- (_params['address'] = @own_address)
92
+ (_params['address'] = @own_address)
50
93
  end
51
94
 
52
- _address = BlockBee::process_request_get(@coin, 'create', _params)
53
-
54
- return nil unless _address
95
+ _address = BlockBee::process_request_get(@coin, 'create', params: _params)
55
96
 
56
97
  @payment_address = _address['address_in']
57
98
 
@@ -64,17 +105,17 @@ module BlockBee
64
105
  'apikey' => @api_key
65
106
  }
66
107
 
67
- _logs = BlockBee::process_request_get(@coin, 'logs', _params)
68
-
69
- return nil unless _logs
70
-
71
- p _logs
108
+ _logs = BlockBee::process_request_get(@coin, 'logs', params: _params)
72
109
 
73
110
  _logs
74
111
  end
75
112
 
76
- def get_qrcode(value = '', size = 300)
113
+ def get_qrcode(value: nil, size: 300)
77
114
  return nil if @coin.nil?
115
+
116
+ raise ArgumentError, 'Size must be a positive integer' unless size.is_a?(Integer) && size > 0
117
+ raise ArgumentError, 'Value must be numeric if provided' unless value.nil? || value.is_a?(Numeric)
118
+ raise ArgumentError, 'Value must be positive if provided' if value.is_a?(Numeric) && value <= 0
78
119
 
79
120
  address = @payment_address
80
121
 
@@ -82,15 +123,14 @@ module BlockBee
82
123
 
83
124
  _params = {
84
125
  'address' => address,
85
- 'size' => size,
86
- 'apikey' => @api_key
126
+ 'size' => size
87
127
  }
88
128
 
89
- _params['value'] = value unless value.empty?
90
-
91
- _qrcode = BlockBee::process_request_get(@coin, 'qrcode', _params)
129
+ if value.is_a? Numeric
130
+ _params['value'] = value
131
+ end
92
132
 
93
- return nil unless _qrcode
133
+ _qrcode = BlockBee::process_request_get(@coin, 'qrcode', params: _params)
94
134
 
95
135
  _qrcode
96
136
  end
@@ -99,35 +139,23 @@ module BlockBee
99
139
  _params = {
100
140
  'from' => from_coin,
101
141
  'value' => value,
102
- 'apikey' => @api_key
103
142
  }
104
143
 
105
- _conversion = BlockBee::process_request_get(@coin, 'convert', _params)
106
-
107
- return nil unless _conversion
144
+ _conversion = BlockBee::process_request_get(@coin, 'convert', params: _params)
108
145
 
109
146
  _conversion
110
147
  end
111
148
 
112
- def self.get_info(coin, api_key, prices = 0)
113
- raise 'API Key Missing' if api_key.nil?
114
-
149
+ def self.get_info(coin, prices: 0)
115
150
  _params = {
116
151
  'prices' => prices,
117
- 'apikey' => api_key
118
152
  }
119
153
 
120
- _info = BlockBee::process_request_get(coin, 'info', _params)
121
-
122
- return nil unless _info
123
-
124
- _info
154
+ _info = BlockBee::process_request_get(coin, 'info', params: _params)
125
155
  end
126
156
 
127
- def self.get_supported_coins(api_key)
128
- raise 'API Key Missing' if api_key.nil?
129
-
130
- _info = get_info(nil, api_key )
157
+ def self.get_supported_coins()
158
+ _info = get_info(nil)
131
159
 
132
160
  _info.delete('fee_tiers')
133
161
 
@@ -146,67 +174,62 @@ module BlockBee
146
174
  _coins
147
175
  end
148
176
 
149
- def self.get_estimate(coin, addresses = 1, priority = 'default', api_key)
150
- raise 'API Key Missing' if api_key.nil?
177
+ def self.get_estimate(coin, api_key, addresses: 1, priority: 'default')
178
+ raise BlockBee::MissingAPIKeyError, 'Provide your API Key' if api_key.nil?
151
179
 
152
- params = {
180
+ _params = {
153
181
  'addresses' => addresses,
154
182
  'priority' => priority,
155
- 'apikey' => api_key
156
183
  }
157
184
 
158
- _estimate = BlockBee::process_request_get(coin, 'estimate', params)
159
-
160
- return nil unless _estimate
185
+ _estimate = BlockBee::process_request_get(coin, 'estimate', params: _params)
161
186
 
162
187
  _estimate
163
188
  end
164
189
 
165
- def self.create_payout(coin, payout_requests, api_key, process = false)
166
- raise 'No requests provided' if payout_requests.nil? || payout_requests.empty?
167
-
190
+ def self.create_payout(coin, payout_requests, api_key, process: false)
168
191
  body = { 'outputs' => payout_requests }
169
192
 
170
193
  endpoint = 'payout/request/bulk'
171
194
 
172
195
  endpoint += '/process' if process
173
196
 
174
- _payout = BlockBee::process_request_post(coin, endpoint, api_key, body, true)
175
-
176
- return nil unless _payout['status'] == 'success'
197
+ _payout = BlockBee::process_request_post(coin, endpoint, api_key, body: body, is_json: true)
177
198
 
178
199
  _payout
179
200
  end
180
201
 
181
- def self.list_payouts(coin, status: 'all', page: 1, api_key:, payout_request: false)
182
- return nil if api_key.nil?
183
-
202
+ def self.list_payouts(coin, api_key, status: 'all', page: 1, payout_request: false)
184
203
  _params = {
185
204
  'apikey' => api_key,
186
205
  'status' => status,
187
- 'page' => page
206
+ 'p' => page
188
207
  }
189
208
 
190
209
  endpoint = 'payout/list'
191
210
 
192
211
  endpoint = 'payout/request/list' if payout_request
193
212
 
194
- _payouts = BlockBee::process_request_get(coin, endpoint, _params)
195
-
196
- return nil unless _payouts['status'] == 'success'
213
+ _payouts = BlockBee::process_request_get(coin, endpoint, params: _params)
197
214
 
198
215
  _payouts
199
216
  end
200
217
 
201
218
  def self.get_payout_wallet(coin, api_key, balance = false)
202
- wallet = BlockBee::process_request_get(coin, 'payout/address', 'apikey' => api_key)
219
+ wallet = BlockBee::process_request_get(coin, 'payout/address', params: { 'apikey' => api_key })
203
220
 
204
- return nil unless wallet['status'] == 'success'
221
+ if wallet['status'] == 'error'
222
+ raise BlockBee::Error, wallet['error']
223
+ end
205
224
 
206
225
  output = { 'address' => wallet['address'] }
207
226
 
208
227
  if balance
209
- wallet_balance = BlockBee::process_request_get(coin, 'payout/balance', 'apikey' => api_key)
228
+ wallet_balance = BlockBee::process_request_get(coin, 'payout/balance', params: { 'apikey' => api_key })
229
+
230
+ if wallet_balance['status'] == 'error'
231
+ raise BlockBee::Error, wallet_balance['error']
232
+ end
210
233
 
211
234
  if wallet_balance['status'] == 'success'
212
235
  output['balance'] = wallet_balance['balance']
@@ -217,31 +240,19 @@ module BlockBee
217
240
  end
218
241
 
219
242
  def self.create_payout_by_ids(api_key, payout_ids)
220
- raise 'Please provide the Payout Request(s) ID(s)' if payout_ids.nil? || payout_ids.empty?
221
-
222
- _payout = BlockBee::process_request_post(nil, 'payout/create', api_key, { 'request_ids' => payout_ids.join(',') })
223
-
224
- return nil unless _payout['status'] == 'success'
243
+ _payout = BlockBee::process_request_post(nil, 'payout/create', api_key, body: { 'request_ids' => payout_ids.join(',') })
225
244
 
226
245
  _payout
227
246
  end
228
247
 
229
248
  def self.process_payout(api_key, payout_id)
230
- return nil if payout_id.nil?
231
-
232
- _process = BlockBee::process_request_post(nil, 'payout/process', api_key, { 'payout_id' => payout_id })
233
-
234
- return nil unless _process['status'] == 'success'
249
+ _process = BlockBee::process_request_post(nil, 'payout/process', api_key, body: { 'payout_id' => payout_id })
235
250
 
236
251
  _process
237
252
  end
238
253
 
239
254
  def self.check_payout_status(api_key, payout_id)
240
- raise 'Please provide the Payout ID' if payout_id.nil? or (payout_id.is_a? String and payout_id.empty?)
241
-
242
- _status = BlockBee::process_request_post(nil, 'payout/status', api_key, { 'payout_id' => payout_id })
243
-
244
- return nil unless _status['status'] == 'success'
255
+ _status = BlockBee::process_request_post(nil, 'payout/status', api_key, body: { 'payout_id' => payout_id })
245
256
 
246
257
  _status
247
258
  end
@@ -249,7 +260,10 @@ module BlockBee
249
260
 
250
261
  class Checkout
251
262
  def initialize(parameters: {}, bb_params: {}, notify_url:, api_key:)
252
- raise 'API Key Missing' if api_key.nil?
263
+ raise BlockBee::MissingAPIKeyError, 'Provide your API Key' if api_key.nil? || api_key.empty?
264
+ raise BlockBee::CallbackURLMissing, 'Provide your notify URL' if notify_url.nil? || notify_url.empty?
265
+ raise ArgumentError, 'Parameters must be a hash' unless parameters.is_a?(Hash)
266
+ raise ArgumentError, 'BB params must be a hash' unless bb_params.is_a?(Hash)
253
267
 
254
268
  @parameters = parameters
255
269
  @bb_params = bb_params
@@ -257,20 +271,42 @@ module BlockBee
257
271
  @notify_url = notify_url
258
272
 
259
273
  if @parameters
260
- _nu = URI::parse(notify_url)
274
+ begin
275
+ _nu = URI.parse(notify_url)
276
+ raise ArgumentError, 'Invalid notify URL' unless _nu.scheme && _nu.host
277
+ rescue URI::InvalidURIError
278
+ raise ArgumentError, 'Invalid notify URL format'
279
+ end
261
280
 
262
- @notify_url = URI::HTTPS.build(
263
- host: _nu.host,
264
- path: _nu.path,
265
- query: URI.encode_www_form(parameters)
266
- )
281
+ # Preserve original scheme (HTTP/HTTPS) for development flexibility
282
+ if _nu.scheme.downcase == 'https'
283
+ @notify_url = URI::HTTPS.build(
284
+ host: _nu.host,
285
+ path: _nu.path,
286
+ query: URI.encode_www_form(parameters)
287
+ )
288
+ else
289
+ @notify_url = URI::HTTP.build(
290
+ host: _nu.host,
291
+ path: _nu.path,
292
+ query: URI.encode_www_form(parameters)
293
+ )
294
+ end
267
295
  end
268
296
  end
269
297
 
270
298
  def payment_request(redirect_url, value)
271
- raise 'Please provide a redirect url' if redirect_url.nil? or redirect_url.empty?
272
-
273
- raise 'Value must be a integer' unless value.is_a?(Integer)
299
+ raise ArgumentError, 'Provide a valid number' unless value.is_a?(Numeric)
300
+ raise ArgumentError, 'Value must be positive' unless value > 0
301
+ raise ArgumentError, 'Redirect URL cannot be empty' if redirect_url.nil? || redirect_url.empty?
302
+
303
+ # Validate redirect URL format
304
+ begin
305
+ _redirect = URI.parse(redirect_url)
306
+ raise ArgumentError, 'Invalid redirect URL' unless _redirect.scheme && _redirect.host
307
+ rescue URI::InvalidURIError
308
+ raise ArgumentError, 'Invalid redirect URL format'
309
+ end
274
310
 
275
311
  _params = {
276
312
  'redirect_url' => redirect_url,
@@ -279,7 +315,7 @@ module BlockBee
279
315
  'apikey' => @api_key
280
316
  }.merge(@bb_params)
281
317
 
282
- _request = BlockBee::process_request_get(nil, 'checkout/request', _params)
318
+ _request = BlockBee::process_request_get(nil, 'checkout/request', params: _params)
283
319
 
284
320
  return nil unless _request['status'] == 'success'
285
321
 
@@ -287,48 +323,34 @@ module BlockBee
287
323
  end
288
324
 
289
325
  def self.payment_logs(token, api_key)
290
- raise 'API Key required' if api_key.nil? or api_key.empty?
291
-
292
- raise 'Token required' if token.nil? or token.empty?
293
-
294
326
  _params = {
295
327
  'apikey' => api_key,
296
328
  'token' => token
297
329
  }
298
330
 
299
- _logs = BlockBee::process_request_get(nil, 'checkout/logs', _params)
300
-
301
- return nil unless _logs['status'] == 'success'
331
+ _logs = BlockBee::process_request_get(nil, 'checkout/logs', params: _params)
302
332
 
303
333
  _logs
304
334
  end
305
335
 
306
- def deposit_request()
336
+ def deposit_request
307
337
  _params = {
308
338
  'notify_url' => @notify_url,
309
339
  'apikey' => @api_key
310
340
  }.merge(@bb_params)
311
341
 
312
- _request = BlockBee::process_request_get(nil, 'deposit/request', _params)
313
-
314
- return nil unless _request['status'] == 'success'
342
+ _request = BlockBee::process_request_get(nil, 'deposit/request', params: _params)
315
343
 
316
344
  _request
317
345
  end
318
346
 
319
347
  def self.deposit_logs(token, api_key)
320
- raise 'API Key required' if api_key.nil? or api_key.empty?
321
-
322
- raise 'Token required' if token.nil? or token.empty?
323
-
324
348
  _params = {
325
349
  'apikey' => api_key,
326
350
  'token' => token
327
351
  }
328
352
 
329
- _logs = BlockBee::process_request_get(nil, 'deposit/logs', _params)
330
-
331
- return nil unless _logs['status'] == 'success'
353
+ _logs = BlockBee::process_request_get(nil, 'deposit/logs', params: _params)
332
354
 
333
355
  _logs
334
356
  end
@@ -336,24 +358,27 @@ module BlockBee
336
358
 
337
359
  private
338
360
 
339
- def self.process_request_get(coin = '', endpoint = '', params = nil)
361
+ def self.process_request_get(coin, endpoint, params: {})
340
362
  coin = coin.nil? ? '' : "#{coin.tr('_', '/')}/"
341
363
 
342
- response = Net::HTTP.get(URI.parse("#{BLOCKBEE_URL}#{coin}#{endpoint}/?#{URI.encode_www_form(params)}"))
364
+ response = Net::HTTP.get_response(URI.parse("#{BLOCKBEE_URL}#{coin}#{endpoint}/?#{URI.encode_www_form(params)}"))
365
+
366
+ response_obj = JSON.parse(response.body)
343
367
 
344
- JSON.parse(response)
368
+ if !response.is_a?(Net::HTTPSuccess) || response_obj['status'] == 'error'
369
+ error = APIError.from_status_code(response.code.to_i, response_obj['error'])
370
+ raise error
371
+ end
372
+
373
+ response_obj
345
374
  end
346
375
 
347
- def self.process_request_post(coin = '', endpoint = '', api_key = '', body = nil, is_json = false)
376
+ def self.process_request_post(coin, endpoint, api_key, body: nil, is_json: false)
348
377
  coin_path = coin.nil? ? '' : "#{coin.tr('_', '/')}/"
349
378
 
350
- p coin_path
351
-
352
379
  url = "#{BLOCKBEE_URL}#{coin_path}#{endpoint}/?apikey=#{api_key}"
353
380
  uri = URI.parse(url)
354
381
 
355
- p url
356
-
357
382
  req = Net::HTTP::Post.new(uri)
358
383
  req['Host'] = BLOCKBEE_HOST
359
384
 
@@ -366,6 +391,14 @@ module BlockBee
366
391
 
367
392
  res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
368
393
 
369
- JSON.parse(res.body)
394
+ response_obj = JSON.parse(res.body)
395
+
396
+ if res.is_a?(Net::HTTPSuccess) && response_obj['status'] == 'success'
397
+ response_obj
398
+ else
399
+ error_message = response_obj['error'] || "Unexpected error occurred"
400
+ error = APIError.from_status_code(res.code.to_i, error_message)
401
+ raise error
402
+ end
370
403
  end
371
404
  end
data/sig/blockbee.rbs CHANGED
@@ -1,103 +1,83 @@
1
1
  module BlockBee
2
- BLOCKBEE_HOST: string
3
- BLOCKBEE_URL: string
2
+ BLOCKBEE_HOST: String
3
+ BLOCKBEE_URL: String
4
4
  VERSION: String
5
5
 
6
- class API
7
- @callback_url: string
8
- @coin: string
9
- @own_address: string
10
- @coin: string
11
- @parameters: Hash[untyped, untyped]
12
- @bb_params: Hash[untyped, untyped]
13
- @api_key: string
14
- @payment_address: string
15
-
16
- def get_address: -> string
17
-
18
- def get_conversion: -> untyped
19
-
20
- def get_logs: -> untyped
21
-
22
- def get_qrcode: -> untyped
23
-
24
- def get_info: -> untyped
6
+ class APIError < StandardError
7
+ @status_code: Integer
25
8
 
26
- def self.get_supported_coins: -> untyped
27
-
28
- def self.get_estimate: -> untyped
29
-
30
- def self.create_payout: -> untyped
31
-
32
- def self.list_payouts: -> untyped
33
-
34
- def self.get_payout_wallet: -> untyped
35
-
36
- def self.create_payout_by_ids: -> untyped
37
-
38
- def self.process_payout: -> untyped
39
-
40
- def self.check_payout_status: -> untyped
9
+ def initialize: (String message, Integer status_code) -> void
10
+ def self.from_status_code: (Integer status_code, String message) -> APIError
41
11
 
12
+ attr_reader status_code: Integer
42
13
  end
43
14
 
44
- class Checkout
45
-
46
- @api_key: string
47
- @bb_params: hash[untyped, untyped]
48
- @parameters: hash[untyped, untyped]
49
- @notify_url: string
15
+ class MissingAPIKeyError < StandardError
16
+ end
50
17
 
51
- def self.deposit_logs: -> untyped
18
+ class CallbackURLMissing < StandardError
19
+ end
52
20
 
53
- def self.payment_logs: -> untyped
21
+ class Error < StandardError
22
+ end
54
23
 
55
- def deposit_request: -> untyped
24
+ class API
25
+ @callback_url: String
26
+ @coin: String?
27
+ @own_address: String
28
+ @parameters: Hash[untyped, untyped]
29
+ @bb_params: Hash[untyped, untyped]
30
+ @api_key: String
31
+ @payment_address: String
56
32
 
57
- def payment_request: -> untyped
33
+ def initialize: (String? coin, String callback_url, String api_key, ?own_address: String, ?parameters: Hash[untyped, untyped], ?bb_params: Hash[untyped, untyped]) -> void
58
34
 
59
- end
35
+ def get_address: () -> Hash[String, untyped]?
60
36
 
61
- private
37
+ def get_logs: () -> Hash[String, untyped]
62
38
 
63
- def self.process_request_get: -> untyped
64
- def self.process_request_post: -> untyped
65
- end
39
+ def get_qrcode: (?value: Numeric?, ?size: Integer) -> Hash[String, untyped]
66
40
 
67
- class TestBlockBee
68
- def test_can_check_payout_status: -> TrueClass
41
+ def get_conversion: (String from_coin, Numeric value) -> Hash[String, untyped]
69
42
 
70
- def test_can_create_checkout_payment: -> TrueClass
43
+ def self.get_info: (String? coin, ?prices: Integer) -> Hash[String, untyped]
71
44
 
72
- def test_can_create_deposit: -> TrueClass
45
+ def self.get_supported_coins: () -> Hash[String, String]
73
46
 
74
- def test_can_create_payout_by_is: -> TrueClass
47
+ def self.get_estimate: (String coin, String api_key, ?addresses: Integer, ?priority: String) -> Hash[String, untyped]
75
48
 
76
- def test_can_create_payouts: -> TrueClass
49
+ def self.create_payout: (String coin, Hash[String, Numeric] payout_requests, String api_key, ?process: bool) -> Hash[String, untyped]
77
50
 
78
- def test_can_fetch_deposit_logs: -> TrueClass
51
+ def self.list_payouts: (String coin, String api_key, ?status: String, ?page: Integer, ?payout_request: bool) -> Hash[String, untyped]
79
52
 
80
- def test_can_fetch_logs: -> TrueClass
53
+ def self.get_payout_wallet: (String coin, String api_key, ?bool balance) -> Hash[String, untyped]
81
54
 
82
- def test_can_fetch_payment_logs: -> TrueClass
55
+ def self.create_payout_by_ids: (String api_key, Array[Integer] payout_ids) -> Hash[String, untyped]
83
56
 
84
- def test_can_generate_address: -> TrueClass
57
+ def self.process_payout: (String api_key, Integer payout_id) -> Hash[String, untyped]
85
58
 
86
- def test_can_get_conversion: -> TrueClass
59
+ def self.check_payout_status: (String api_key, Integer payout_id) -> Hash[String, untyped]
60
+ end
87
61
 
88
- def test_can_get_estimate: -> TrueClass
62
+ class Checkout
63
+ @api_key: String
64
+ @bb_params: Hash[untyped, untyped]
65
+ @parameters: Hash[untyped, untyped]
66
+ @notify_url: String
89
67
 
90
- def test_can_get_info: -> TrueClass
68
+ def initialize: (?parameters: Hash[untyped, untyped], ?bb_params: Hash[untyped, untyped], notify_url: String, api_key: String) -> void
91
69
 
92
- def test_can_get_payout_wallet: -> TrueClass
70
+ def self.deposit_logs: (String token, String api_key) -> Hash[String, untyped]
93
71
 
94
- def test_can_get_qrcode: -> TrueClass
72
+ def self.payment_logs: (String token, String api_key) -> Hash[String, untyped]
95
73
 
96
- def test_can_get_supported_coins: -> TrueClass
74
+ def deposit_request: () -> Hash[String, untyped]
97
75
 
98
- def test_can_list_payouts: -> TrueClass
76
+ def payment_request: (String redirect_url, Numeric value) -> Hash[String, untyped]?
77
+ end
99
78
 
100
- def test_can_process_payout_by_id: -> TrueClass
79
+ private
101
80
 
102
- def test_that_it_has_a_version_number: -> TrueClass
81
+ def self.process_request_get: (String? coin, String endpoint, ?params: Hash[String, untyped]) -> Hash[String, untyped]
82
+ def self.process_request_post: (String? coin, String endpoint, String api_key, ?body: Hash[String, untyped]?, ?is_json: bool) -> Hash[String, untyped]
103
83
  end
metadata CHANGED
@@ -1,23 +1,34 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: blockbee
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - BlockBee
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2024-04-17 00:00:00.000000000 Z
12
- dependencies: []
13
- description:
10
+ date: 2025-09-25 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: dotenv
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '2.8'
19
+ type: :development
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '2.8'
14
26
  email:
15
27
  - info@blockbee.io
16
28
  executables: []
17
29
  extensions: []
18
30
  extra_rdoc_files: []
19
31
  files:
20
- - ".DS_Store"
21
32
  - CHANGELOG.md
22
33
  - LICENSE.txt
23
34
  - README.md
@@ -31,8 +42,7 @@ licenses:
31
42
  metadata:
32
43
  homepage_uri: https://blockbee.io
33
44
  source_code_uri: https://github.com/blockbee-io/ruby-blockbee
34
- changelog_uri: https://github.com/blockbee-io/ruby-blockbee/blob/main/CHANGELOG.md
35
- post_install_message:
45
+ changelog_uri: https://github.com/blockbee-io/ruby-blockbee/blob/master/CHANGELOG.md
36
46
  rdoc_options: []
37
47
  require_paths:
38
48
  - lib
@@ -47,8 +57,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
47
57
  - !ruby/object:Gem::Version
48
58
  version: '0'
49
59
  requirements: []
50
- rubygems_version: 3.5.9
51
- signing_key:
60
+ rubygems_version: 3.6.6
52
61
  specification_version: 4
53
62
  summary: Ruby implementation of BlockBee's payment gateway
54
63
  test_files: []
data/.DS_Store DELETED
Binary file