coinbase-sdk 0.0.13 → 0.0.16

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/lib/coinbase/address/external_address.rb +3 -166
  3. data/lib/coinbase/address/wallet_address.rb +51 -4
  4. data/lib/coinbase/address.rb +164 -0
  5. data/lib/coinbase/client/api/assets_api.rb +2 -2
  6. data/lib/coinbase/client/api/contract_events_api.rb +121 -0
  7. data/lib/coinbase/client/api/external_addresses_api.rb +85 -0
  8. data/lib/coinbase/client/api/networks_api.rb +85 -0
  9. data/lib/coinbase/client/api/stake_api.rb +361 -0
  10. data/lib/coinbase/client/api/webhooks_api.rb +286 -0
  11. data/lib/coinbase/client/models/address_historical_balance_list.rb +258 -0
  12. data/lib/coinbase/client/models/broadcast_staking_operation_request.rb +239 -0
  13. data/lib/coinbase/client/models/contract_event.rb +336 -0
  14. data/lib/coinbase/client/models/contract_event_list.rb +259 -0
  15. data/lib/coinbase/client/models/create_staking_operation_request.rb +274 -0
  16. data/lib/coinbase/client/models/create_transfer_request.rb +14 -4
  17. data/lib/coinbase/client/models/create_webhook_request.rb +282 -0
  18. data/lib/coinbase/client/models/ethereum_validator.rb +374 -0
  19. data/lib/coinbase/client/models/feature_set.rb +307 -0
  20. data/lib/coinbase/client/models/fetch_historical_staking_balances200_response.rb +258 -0
  21. data/lib/coinbase/client/models/get_validator200_response.rb +221 -0
  22. data/lib/coinbase/client/models/get_validator200_response_validator.rb +214 -0
  23. data/lib/coinbase/client/models/historical_balance.rb +273 -0
  24. data/lib/coinbase/client/models/network.rb +355 -0
  25. data/lib/coinbase/client/models/network_identifier.rb +44 -0
  26. data/lib/coinbase/client/models/sponsored_send.rb +338 -0
  27. data/lib/coinbase/client/models/staking_balance.rb +289 -0
  28. data/lib/coinbase/client/models/staking_context_context.rb +222 -74
  29. data/lib/coinbase/client/models/staking_operation.rb +15 -5
  30. data/lib/coinbase/client/models/staking_reward.rb +22 -6
  31. data/lib/coinbase/client/models/staking_reward_format.rb +2 -1
  32. data/lib/coinbase/client/models/staking_reward_usd_value.rb +257 -0
  33. data/lib/coinbase/client/models/transaction.rb +2 -2
  34. data/lib/coinbase/client/models/transaction_type.rb +2 -1
  35. data/lib/coinbase/client/models/transfer.rb +29 -24
  36. data/lib/coinbase/client/models/update_webhook_request.rb +289 -0
  37. data/lib/coinbase/client/models/validator_list_data.rb +216 -0
  38. data/lib/coinbase/client/models/wallet.rb +13 -16
  39. data/lib/coinbase/client/models/webhook.rb +299 -0
  40. data/lib/coinbase/client/models/webhook_event_filter.rb +236 -0
  41. data/lib/coinbase/client/models/webhook_event_type.rb +42 -0
  42. data/lib/coinbase/client/models/webhook_list.rb +244 -0
  43. data/lib/coinbase/client.rb +22 -3
  44. data/lib/coinbase/errors.rb +7 -0
  45. data/lib/coinbase/historical_balance.rb +53 -0
  46. data/lib/coinbase/middleware.rb +12 -0
  47. data/lib/coinbase/server_signer.rb +14 -3
  48. data/lib/coinbase/sponsored_send.rb +110 -0
  49. data/lib/coinbase/staking_balance.rb +86 -0
  50. data/lib/coinbase/staking_operation.rb +106 -5
  51. data/lib/coinbase/staking_reward.rb +18 -0
  52. data/lib/coinbase/trade.rb +1 -1
  53. data/lib/coinbase/transaction.rb +7 -3
  54. data/lib/coinbase/transfer.rb +56 -29
  55. data/lib/coinbase/wallet/data.rb +31 -0
  56. data/lib/coinbase/wallet.rb +91 -46
  57. data/lib/coinbase.rb +17 -4
  58. metadata +74 -2
@@ -9,6 +9,67 @@ module Coinbase
9
9
  class StakingOperation
10
10
  attr_reader :transactions
11
11
 
12
+ # Builds an ephemeral staking operation this is intended to be called via an Address or Wallet.
13
+ # @param amount [BigDecimal] The amount to stake, in the primary denomination of the asset
14
+ # @param network_id [Symbol] The Network ID
15
+ # @param asset_id [Symbol] The Asset ID
16
+ # @param address_id [String] The Address ID
17
+ # @param action [Symbol] The action to perform
18
+ # @param mode [Symbol] The staking mode
19
+ # @param options [Hash] Additional options
20
+ # @return [Coinbase::StakingOperation] The staking operation
21
+ def self.build(amount, network_id, asset_id, address_id, action, mode, options)
22
+ model = Coinbase.call_api do
23
+ asset = Coinbase::Asset.fetch(network_id, asset_id)
24
+ stake_api.build_staking_operation(
25
+ {
26
+ asset_id: asset.primary_denomination.to_s,
27
+ address_id: address_id,
28
+ action: action,
29
+ network_id: Coinbase.normalize_network(network_id),
30
+ options: {
31
+ amount: asset.to_atomic_amount(amount).to_i.to_s,
32
+ mode: mode
33
+ }.merge(options)
34
+ }
35
+ )
36
+ end
37
+
38
+ new(model)
39
+ end
40
+
41
+ # Creates a persisted staking operation this is intended to be called via an Address or Wallet.
42
+ # @param amount [BigDecimal] The amount to stake, in the primary denomination of the asset
43
+ # @param network_id [Symbol] The Network ID
44
+ # @param asset_id [Symbol] The Asset ID
45
+ # @param address_id [String] The Address ID
46
+ # @param wallet_id [String] The Wallet ID
47
+ # @param action [Symbol] The action to perform
48
+ # @param mode [Symbol] The staking mode
49
+ # @param options [Hash] Additional options
50
+ # @return [Coinbase::StakingOperation] The staking operation
51
+ def self.create(amount, network_id, asset_id, address_id, wallet_id, action, mode, options)
52
+ model = Coinbase.call_api do
53
+ asset = Coinbase::Asset.fetch(network_id, asset_id)
54
+ stake_api.create_staking_operation(
55
+ wallet_id,
56
+ address_id,
57
+ {
58
+ asset_id: asset.primary_denomination.to_s,
59
+ address_id: address_id,
60
+ action: action,
61
+ network_id: Coinbase.normalize_network(network_id),
62
+ options: {
63
+ amount: asset.to_atomic_amount(amount).to_i.to_s,
64
+ mode: mode
65
+ }.merge(options)
66
+ }
67
+ )
68
+ end
69
+
70
+ new(model)
71
+ end
72
+
12
73
  # Returns a new StakingOperation object.
13
74
  # @param model [Coinbase::Client::StakingOperation] The underlying StakingOperation object
14
75
  def initialize(model)
@@ -39,6 +100,12 @@ module Coinbase
39
100
  @model.status
40
101
  end
41
102
 
103
+ # Returns the Wallet ID of the Staking Operation.
104
+ # @return [String] The Wallet ID
105
+ def wallet_id
106
+ @model.wallet_id
107
+ end
108
+
42
109
  # Waits until the Staking Operation is completed or failed by polling its status at the given interval. Raises a
43
110
  # Timeout::Error if the Staking Operation takes longer than the given timeout.
44
111
  # @param interval_seconds [Integer] The interval at which to poll, in seconds
@@ -66,13 +133,18 @@ module Coinbase
66
133
  # @param network_id [Symbol] The Network ID
67
134
  # @param address_id [Symbol] The Address ID
68
135
  # @param id [String] The ID of the StakingOperation
136
+ # @param wallet_id [String] The optional Wallet ID
69
137
  # @return [Coinbase::StakingOperation] The staking operation
70
- def self.fetch(network_id, address_id, id)
138
+ def self.fetch(network_id, address_id, id, wallet_id: nil)
71
139
  staking_operation_model = Coinbase.call_api do
72
- stake_api.get_external_staking_operation(network_id, address_id, id)
140
+ if wallet_id.nil?
141
+ stake_api.get_external_staking_operation(network_id, address_id, id)
142
+ else
143
+ stake_api.get_staking_operation(wallet_id, address_id, id)
144
+ end
73
145
  end
74
146
 
75
- from_model(staking_operation_model)
147
+ new(staking_operation_model)
76
148
  end
77
149
 
78
150
  # Signs the Open Transactions with the provided key
@@ -87,7 +159,11 @@ module Coinbase
87
159
  # @return [Coinbase::StakingOperation] The updated staking operation
88
160
  def reload
89
161
  @model = Coinbase.call_api do
90
- stake_api.get_external_staking_operation(network_id, address_id, id)
162
+ if wallet_id.nil?
163
+ stake_api.get_external_staking_operation(network_id, address_id, id)
164
+ else
165
+ stake_api.get_staking_operation(wallet_id, address_id, id)
166
+ end
91
167
  end
92
168
 
93
169
  from_model(@model)
@@ -108,10 +184,33 @@ module Coinbase
108
184
  signed_voluntary_exit_messages
109
185
  end
110
186
 
187
+ # Broadcasts the Staking Operation transactions to the network
188
+ # @return [Coinbase::StakingOperation]
189
+ def broadcast!
190
+ transactions.each_with_index do |transaction, i|
191
+ raise TransactionNotSignedError unless transaction.signed?
192
+
193
+ Coinbase.call_api do
194
+ stake_api.broadcast_staking_operation(
195
+ wallet_id,
196
+ address_id,
197
+ id,
198
+ { signed_payload: transaction.raw.hex, transaction_index: i }
199
+ )
200
+ end
201
+ end
202
+
203
+ self
204
+ end
205
+
206
+ def self.stake_api
207
+ Coinbase::Client::StakeApi.new(Coinbase.configuration.api_client)
208
+ end
209
+
111
210
  private
112
211
 
113
212
  def stake_api
114
- @stake_api ||= Coinbase::Client::StakeApi.new(Coinbase.configuration.api_client)
213
+ @stake_api ||= self.class.stake_api
115
214
  end
116
215
 
117
216
  def from_model(model)
@@ -120,6 +219,8 @@ module Coinbase
120
219
  @transactions = model.transactions.map do |transaction_model|
121
220
  Transaction.new(transaction_model)
122
221
  end
222
+
223
+ self
123
224
  end
124
225
  end
125
226
  end
@@ -53,6 +53,24 @@ module Coinbase
53
53
  @model.address_id
54
54
  end
55
55
 
56
+ # Returns the USD value of the StakingReward.
57
+ # @return [BigDecimal] The USD value
58
+ def usd_value
59
+ BigDecimal(@model.usd_value.amount.to_i) / BigDecimal(100)
60
+ end
61
+
62
+ # Returns the USD conversion price of the StakingReward.
63
+ # @return [BigDecimal] The USD conversion price
64
+ def usd_conversion_price
65
+ BigDecimal(@model.usd_value.conversion_price.to_i) / BigDecimal(100)
66
+ end
67
+
68
+ # Returns the USD conversion time of the StakingReward.
69
+ # @return [Time] The USD conversion time
70
+ def usd_conversion_time
71
+ @model.usd_value.conversion_time
72
+ end
73
+
56
74
  # Returns a string representation of the StakingReward.
57
75
  # @return [String] a string representation of the StakingReward
58
76
  def to_s
@@ -147,7 +147,7 @@ module Coinbase
147
147
 
148
148
  payloads = { signed_payload: transaction.raw.hex }
149
149
 
150
- payloads[:approve_tx_signed_payload] = approve_transaction.raw.hex unless approve_transaction.nil?
150
+ payloads[:approve_transaction_signed_payload] = approve_transaction.raw.hex unless approve_transaction.nil?
151
151
 
152
152
  @model = Coinbase.call_api do
153
153
  trades_api.broadcast_trade(wallet_id, address_id, id, payloads)
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'constants'
4
- require 'bigdecimal'
5
3
  require 'eth'
6
4
  require 'json'
7
5
 
@@ -113,12 +111,18 @@ module Coinbase
113
111
  @raw = Eth::Tx::Eip1559.new(Eth::Tx.validate_eip1559_params(params))
114
112
  end
115
113
 
114
+ # Returns the signature of the Transaction.
115
+ # @return [String] The hex-encode signature
116
+ def signature
117
+ raw.hex
118
+ end
119
+
116
120
  # Signs the Transaction with the provided key and returns the hex signing payload.
117
121
  # @return [String] The hex-encoded signed payload
118
122
  def sign(key)
119
123
  raw.sign(key)
120
124
 
121
- raw.hex
125
+ signature
122
126
  end
123
127
 
124
128
  # Returns whether the Transaction has been signed.
@@ -3,7 +3,6 @@
3
3
  require_relative 'constants'
4
4
  require 'bigdecimal'
5
5
  require 'eth'
6
- require 'json'
7
6
 
8
7
  module Coinbase
9
8
  # A representation of a Transfer, which moves an amount of an Asset from
@@ -25,7 +24,7 @@ module Coinbase
25
24
  # @param wallet_id [String] The Wallet ID of the sending Wallet
26
25
  # @return [Transfer] The new pending Transfer object
27
26
  # @raise [Coinbase::ApiError] If the Transfer fails
28
- def create(address_id:, amount:, asset_id:, destination:, network_id:, wallet_id:)
27
+ def create(address_id:, amount:, asset_id:, destination:, network_id:, wallet_id:, gasless: false)
29
28
  asset = Asset.fetch(network_id, asset_id)
30
29
 
31
30
  model = Coinbase.call_api do
@@ -36,7 +35,8 @@ module Coinbase
36
35
  amount: asset.to_atomic_amount(amount).to_i.to_s,
37
36
  asset_id: asset.primary_denomination.to_s,
38
37
  destination: Coinbase::Destination.new(destination, network_id: network_id).address_id,
39
- network_id: Coinbase.normalize_network(network_id)
38
+ network_id: Coinbase.normalize_network(network_id),
39
+ gasless: gasless
40
40
  }
41
41
  )
42
42
  end
@@ -122,41 +122,52 @@ module Coinbase
122
122
  BigDecimal(@model.amount) / BigDecimal(10).power(@model.asset.decimals)
123
123
  end
124
124
 
125
- # Returns the link to the transaction on the blockchain explorer.
126
- # @return [String] The link to the transaction on the blockchain explorer
127
- def transaction_link
128
- # TODO: Parameterize this by Network.
129
- "https://sepolia.basescan.org/tx/#{transaction_hash}"
130
- end
125
+ # Signs the Transfer with the given key. This is required before broadcasting the Transfer.
126
+ # @param key [Eth::Key] The key to sign the Transfer with
127
+ # @raise [RuntimeError] If the key is not an Eth::Key
128
+ # @return [Transfer] The Transfer object
129
+ def sign(key)
130
+ raise unless key.is_a?(Eth::Key)
131
131
 
132
- # Returns the Unsigned Payload of the Transfer.
133
- # @return [String] The Unsigned Payload
134
- def unsigned_payload
135
- @model.unsigned_payload
136
- end
132
+ unless sponsored_send.nil?
133
+ sponsored_send.sign(key)
134
+
135
+ return
136
+ end
137
137
 
138
- # Returns the Signed Payload of the Transfer.
139
- # @return [String] The Signed Payload
140
- def signed_payload
141
- @model.signed_payload
138
+ transaction.sign(key)
139
+
140
+ self
142
141
  end
143
142
 
144
143
  # Returns the Transfer transaction.
145
144
  # @return [Coinbase::Transaction] The Transfer transaction
146
145
  def transaction
147
- @transaction ||= Coinbase::Transaction.new(@model.transaction)
146
+ @transaction ||= @model.transaction.nil? ? nil : Coinbase::Transaction.new(@model.transaction)
148
147
  end
149
148
 
150
- # Returns the Transaction Hash of the Transfer.
151
- # @return [String] The Transaction Hash
152
- def transaction_hash
153
- @model.transaction_hash
149
+ # Returns the SponsoredSend of the Transfer, if the transfer is gasless.
150
+ # @return [Coinbase::SponsoredSend] The SponsoredSend object
151
+ def sponsored_send
152
+ @sponsored_send ||= @model.sponsored_send.nil? ? nil : Coinbase::SponsoredSend.new(@model.sponsored_send)
154
153
  end
155
154
 
156
155
  # Returns the status of the Transfer.
157
156
  # @return [Symbol] The status
158
157
  def status
159
- transaction.status
158
+ send_tx_delegate.status
159
+ end
160
+
161
+ # Returns the link to the transaction on the blockchain explorer.
162
+ # @return [String] The link to the transaction on the blockchain explorer
163
+ def transaction_link
164
+ send_tx_delegate.transaction_link
165
+ end
166
+
167
+ # Returns the Transaction Hash of the Transfer.
168
+ # @return [String] The Transaction Hash
169
+ def transaction_hash
170
+ send_tx_delegate.transaction_hash
160
171
  end
161
172
 
162
173
  # Broadcasts the Transfer to the Network.
@@ -164,18 +175,19 @@ module Coinbase
164
175
  # @raise [RuntimeError] If the Transfer is not signed
165
176
  # @return [Transfer] The Transfer object
166
177
  def broadcast!
167
- raise TransactionNotSignedError unless transaction.signed?
178
+ raise TransactionNotSignedError unless send_tx_delegate.signed?
168
179
 
169
180
  @model = Coinbase.call_api do
170
181
  transfers_api.broadcast_transfer(
171
182
  wallet_id,
172
183
  from_address_id,
173
184
  id,
174
- { signed_payload: transaction.raw.hex }
185
+ { signed_payload: send_tx_delegate.signature }
175
186
  )
176
187
  end
177
188
 
178
- update_transaction(@model)
189
+ update_transaction(@model) unless @model.transaction.nil?
190
+ update_sponsored_send(@model) unless @model.sponsored_send.nil?
179
191
 
180
192
  self
181
193
  end
@@ -187,7 +199,8 @@ module Coinbase
187
199
  transfers_api.get_transfer(wallet_id, from_address_id, id)
188
200
  end
189
201
 
190
- update_transaction(@model)
202
+ update_transaction(@model) unless @model.transaction.nil?
203
+ update_sponsored_send(@model) unless @model.sponsored_send.nil?
191
204
 
192
205
  self
193
206
  end
@@ -203,7 +216,7 @@ module Coinbase
203
216
  loop do
204
217
  reload
205
218
 
206
- return self if transaction.terminal_state?
219
+ return self if terminal_state?
207
220
 
208
221
  raise Timeout::Error, 'Transfer timed out' if Time.now - start_time > timeout_seconds
209
222
 
@@ -230,6 +243,16 @@ module Coinbase
230
243
 
231
244
  private
232
245
 
246
+ def terminal_state?
247
+ send_tx_delegate.terminal_state?
248
+ end
249
+
250
+ def send_tx_delegate
251
+ return sponsored_send unless sponsored_send.nil?
252
+
253
+ transaction
254
+ end
255
+
233
256
  def transfers_api
234
257
  @transfers_api ||= Coinbase::Client::TransfersApi.new(Coinbase.configuration.api_client)
235
258
  end
@@ -237,5 +260,9 @@ module Coinbase
237
260
  def update_transaction(model)
238
261
  @transaction = Coinbase::Transaction.new(model.transaction)
239
262
  end
263
+
264
+ def update_sponsored_send(model)
265
+ @sponsored_send = Coinbase::SponsoredSend.new(model.sponsored_send)
266
+ end
240
267
  end
241
268
  end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coinbase
4
+ class Wallet
5
+ # The data required to recreate a Wallet.
6
+ class Data
7
+ attr_reader :wallet_id, :seed
8
+
9
+ # Returns a new Data object.
10
+ # @param wallet_id [String] The ID of the Wallet
11
+ # @param seed [String] The seed of the Wallet
12
+ def initialize(wallet_id:, seed:)
13
+ @wallet_id = wallet_id
14
+ @seed = seed
15
+ end
16
+
17
+ # Converts the Data object to a Hash.
18
+ # @return [Hash] The Hash representation of the Data object
19
+ def to_hash
20
+ { wallet_id: wallet_id, seed: seed }
21
+ end
22
+
23
+ # Creates a Data object from the given Hash.
24
+ # @param data [Hash] The Hash to create the Data object from
25
+ # @return [Data] The new Data object
26
+ def self.from_hash(data)
27
+ Data.new(wallet_id: data['wallet_id'], seed: data['seed'])
28
+ end
29
+ end
30
+ end
31
+ end
@@ -5,6 +5,8 @@ require 'json'
5
5
  require 'money-tree'
6
6
  require 'securerandom'
7
7
 
8
+ require_relative 'wallet/data'
9
+
8
10
  module Coinbase
9
11
  # A representation of a Wallet. Wallets come with a single default Address, but can expand to have a set of Addresses,
10
12
  # each of which can hold a balance of one or more Assets. Wallets can create new Addresses, list their addresses,
@@ -13,17 +15,6 @@ module Coinbase
13
15
  # The maximum number of addresses in a Wallet.
14
16
  MAX_ADDRESSES = 20
15
17
 
16
- # A representation of ServerSigner status in a Wallet.
17
- module ServerSignerStatus
18
- # The Wallet is awaiting seed creation by the ServerSigner. At this point,
19
- # the Wallet cannot create addresses or sign transactions.
20
- PENDING = 'pending_seed_creation'
21
-
22
- # The Wallet has an associated seed created by the ServerSigner. It is ready
23
- # to create addresses and sign transactions.
24
- ACTIVE = 'active_seed'
25
- end
26
-
27
18
  class << self
28
19
  # Imports a Wallet from previously exported wallet data.
29
20
  # @param data [Coinbase::Wallet::Data] the Wallet data to import
@@ -43,7 +34,7 @@ module Coinbase
43
34
  # converted to an array, etc...
44
35
  # @return [Enumerable<Coinbase::Wallet>] Enumerator that returns wallets
45
36
  def list
46
- Coinbase::Pagination.enumerate(lambda(&method(:fetch_wallets_page))) do |wallet|
37
+ Coinbase::Pagination.enumerate(method(:fetch_wallets_page)) do |wallet|
47
38
  Coinbase::Wallet.new(wallet, seed: '')
48
39
  end
49
40
  end
@@ -107,7 +98,7 @@ module Coinbase
107
98
  wallets_api.get_wallet(wallet_id)
108
99
  end
109
100
 
110
- return self if model.server_signer_status == ServerSignerStatus::ACTIVE
101
+ return self if model.server_signer_status == ServerSigner::Status::ACTIVE
111
102
 
112
103
  if Time.now - start_time > timeout_seconds
113
104
  raise Timeout::Error, 'Wallet creation timed out. Check status of your Server-Signer'
@@ -278,9 +269,15 @@ module Coinbase
278
269
  # @param asset_id [Symbol] The ID of the Asset to send
279
270
  # @param destination [Wallet | Address | String] The destination of the transfer. If a Wallet, sends to the Wallet's
280
271
  # default address. If a String, interprets it as the address ID.
272
+ # @param gasless [Boolean] Whether gas fee for the transfer should be covered by Coinbase.
273
+ # Defaults to false. Check the API documentation for network and asset support.
281
274
  # @return [Coinbase::Transfer] The Transfer object.
282
- def transfer(amount, asset_id, destination)
283
- default_address.transfer(amount, asset_id, destination)
275
+ def transfer(amount, asset_id, destination, options = {})
276
+ # For ruby 2.7 compatibility we cannot pass in keyword args when the create wallet
277
+ # options is empty
278
+ return default_address.transfer(amount, asset_id, destination) if options.empty?
279
+
280
+ default_address.transfer(amount, asset_id, destination, **options)
284
281
  end
285
282
 
286
283
  # Trades the given amount of the given Asset for another Asset.
@@ -294,8 +291,84 @@ module Coinbase
294
291
  default_address.trade(amount, from_asset_id, to_asset_id)
295
292
  end
296
293
 
294
+ # Stakes the given amount of the given Asset.
295
+ # Currently only the default_address is used to source the Stake.
296
+ # @param amount [Integer, Float, BigDecimal] The amount of the Asset to stake.
297
+ # @param asset_id [Symbol] The ID of the Asset to stake.
298
+ # @param mode [Symbol] (Optional) The staking mode. Defaults to :default.
299
+ # @param options [Hash] (Optional) Additional options for the staking operation.
300
+ # @return [Coinbase::StakingOperation] The stake operation
301
+ def stake(amount, asset_id, mode: :default, options: {})
302
+ default_address.stake(amount, asset_id, mode: mode, options: options)
303
+ end
304
+
305
+ # Unstakes the given amount of the given Asset.
306
+ # Currently only the default_address is used to source the Unstake.
307
+ # @param amount [Integer, Float, BigDecimal] The amount of the Asset to unstake.
308
+ # @param asset_id [Symbol] The ID of the Asset to unstake.
309
+ # @param mode [Symbol] (Optional) The staking mode. Defaults to :default.
310
+ # @param options [Hash] (Optional) Additional options for the unstaking operation.
311
+ # @return [Coinbase::StakingOperation] The unstake operation
312
+ def unstake(amount, asset_id, mode: :default, options: {})
313
+ default_address.unstake(amount, asset_id, mode: mode, options: options)
314
+ end
315
+
316
+ # Claims stake of the given amount of the given Asset.
317
+ # Currently only the default_address is used as the source for claim_stake.
318
+ # @param amount [Integer, Float, BigDecimal] The amount of the Asset to claim_stake.
319
+ # @param asset_id [Symbol] The ID of the Asset to claim_stake.
320
+ # @param mode [Symbol] (Optional) The staking mode. Defaults to :default.
321
+ # @param options [Hash] (Optional) Additional options for the unstaking operation.
322
+ # @return [Coinbase::StakingOperation] The claim_stake operation
323
+ def claim_stake(amount, asset_id, mode: :default, options: {})
324
+ default_address.claim_stake(amount, asset_id, mode: mode, options: options)
325
+ end
326
+
327
+ # Retrieves the balances used for staking for the supplied asset.
328
+ # Currently only the default_address is used to source the staking balances.
329
+ # @param asset_id [Symbol] The asset to retrieve staking balances for
330
+ # @param mode [Symbol] The staking mode. Defaults to :default.
331
+ # @param options [Hash] Additional options for the staking operation
332
+ # @return [Hash] The staking balances
333
+ # @return [BigDecimal] :stakeable_balance The amount of the asset that can be staked
334
+ # @return [BigDecimal] :unstakeable_balance The amount of the asset that is currently staked and cannot be unstaked
335
+ # @return [BigDecimal] :claimable_balance The amount of the asset that can be claimed
336
+ def staking_balances(asset_id, mode: :default, options: {})
337
+ default_address.staking_balances(asset_id, mode: mode, options: options)
338
+ end
339
+
340
+ # Retrieves the stakeable balance for the supplied asset.
341
+ # Currently only the default_address is used to source the stakeable balance.
342
+ # @param asset_id [Symbol] The asset to retrieve the stakeable balance for
343
+ # @param mode [Symbol] The staking mode. Defaults to :default.
344
+ # @param options [Hash] Additional options for the staking operation
345
+ # @return [BigDecimal] The stakeable balance
346
+ def stakeable_balance(asset_id, mode: :default, options: {})
347
+ default_address.stakeable_balance(asset_id, mode: mode, options: options)
348
+ end
349
+
350
+ # Retrieves the unstakeable balance for the supplied asset.
351
+ # Currently only the default_address is used to source the unstakeable balance.
352
+ # @param asset_id [Symbol] The asset to retrieve the unstakeable balance for
353
+ # @param mode [Symbol] The staking mode. Defaults to :default.
354
+ # @param options [Hash] Additional options for the staking operation
355
+ # @return [BigDecimal] The unstakeable balance
356
+ def unstakeable_balance(asset_id, mode: :default, options: {})
357
+ default_address.unstakeable_balance(asset_id, mode: mode, options: options)
358
+ end
359
+
360
+ # Retrieves the claimable balance for the supplied asset.
361
+ # Currently only the default_address is used to source the claimable balance.
362
+ # @param asset_id [Symbol] The asset to retrieve the claimable balance for
363
+ # @param mode [Symbol] The staking mode. Defaults to :default.
364
+ # @param options [Hash] Additional options for the staking operation
365
+ # @return [BigDecimal] The claimable balance
366
+ def claimable_balance(asset_id, mode: :default, options: {})
367
+ default_address.claimable_balance(asset_id, mode: mode, options: options)
368
+ end
369
+
297
370
  # Exports the Wallet's data to a Data object.
298
- # @return [Data] The Wallet data
371
+ # @return [Coinbase::Wallet::Data] The Wallet data
299
372
  def export
300
373
  # TODO: Improve this check by relying on the backend data to decide whether a wallet is server-signer backed.
301
374
  raise 'Cannot export data for Server-Signer backed Wallet' if Coinbase.use_server_signer?
@@ -357,9 +430,7 @@ module Coinbase
357
430
  iv: iv
358
431
  }
359
432
 
360
- File.open(file_path, 'w') do |file|
361
- file.write(JSON.pretty_generate(existing_seeds_in_store))
362
- end
433
+ File.write(file_path, JSON.pretty_generate(existing_seeds_in_store))
363
434
 
364
435
  "Successfully saved seed for wallet #{id} to #{file_path}."
365
436
  end
@@ -416,32 +487,6 @@ module Coinbase
416
487
  to_s
417
488
  end
418
489
 
419
- # The data required to recreate a Wallet.
420
- class Data
421
- attr_reader :wallet_id, :seed
422
-
423
- # Returns a new Data object.
424
- # @param wallet_id [String] The ID of the Wallet
425
- # @param seed [String] The seed of the Wallet
426
- def initialize(wallet_id:, seed:)
427
- @wallet_id = wallet_id
428
- @seed = seed
429
- end
430
-
431
- # Converts the Data object to a Hash.
432
- # @return [Hash] The Hash representation of the Data object
433
- def to_hash
434
- { wallet_id: wallet_id, seed: seed }
435
- end
436
-
437
- # Creates a Data object from the given Hash.
438
- # @param data [Hash] The Hash to create the Data object from
439
- # @return [Data] The new Data object
440
- def self.from_hash(data)
441
- Data.new(wallet_id: data['wallet_id'], seed: data['seed'])
442
- end
443
- end
444
-
445
490
  private
446
491
 
447
492
  # Reloads the Wallet with the latest data.
@@ -464,7 +509,7 @@ module Coinbase
464
509
  def address_path_prefix
465
510
  # TODO: Push this logic to the backend.
466
511
  @address_path_prefix ||= case network_id.to_s.split('_').first
467
- when 'base', 'ethereum'
512
+ when 'base', 'ethereum', 'polygon'
468
513
  "m/44'/60'/0'/0"
469
514
  else
470
515
  raise ArgumentError, "Unsupported network ID: #{network_id}"
data/lib/coinbase.rb CHANGED
@@ -7,6 +7,7 @@ require_relative 'coinbase/asset'
7
7
  require_relative 'coinbase/authenticator'
8
8
  require_relative 'coinbase/balance'
9
9
  require_relative 'coinbase/balance_map'
10
+ require_relative 'coinbase/historical_balance'
10
11
  require_relative 'coinbase/client'
11
12
  require_relative 'coinbase/constants'
12
13
  require_relative 'coinbase/destination'
@@ -21,6 +22,8 @@ require_relative 'coinbase/transaction'
21
22
  require_relative 'coinbase/user'
22
23
  require_relative 'coinbase/wallet'
23
24
  require_relative 'coinbase/server_signer'
25
+ require_relative 'coinbase/sponsored_send'
26
+ require_relative 'coinbase/staking_balance'
24
27
  require_relative 'coinbase/staking_operation'
25
28
  require_relative 'coinbase/staking_reward'
26
29
  require_relative 'coinbase/validator'
@@ -62,13 +65,14 @@ module Coinbase
62
65
 
63
66
  # Configuration object for the Coinbase SDK.
64
67
  class Configuration
65
- attr_accessor :api_url, :api_key_name, :api_key_private_key, :debug_api, :use_server_signer
68
+ attr_accessor :api_url, :api_key_name, :api_key_private_key, :debug_api, :use_server_signer, :max_network_tries
66
69
 
67
70
  # Initializes the configuration object.
68
71
  def initialize
69
72
  @api_url = 'https://api.cdp.coinbase.com'
70
73
  @debug_api = false
71
74
  @use_server_signer = false
75
+ @max_network_tries = 3
72
76
  end
73
77
 
74
78
  # Sets configuration values based on the provided CDP API Key JSON file.
@@ -110,7 +114,7 @@ module Coinbase
110
114
  # @param network_sym [Symbol] the network symbol to convert
111
115
  # @return [String] the converted string
112
116
  def self.normalize_network(network_sym)
113
- network_sym.to_s.gsub(/_/, '-')
117
+ network_sym.to_s.gsub('_', '-')
114
118
  end
115
119
 
116
120
  # Loads the default user.
@@ -127,8 +131,17 @@ module Coinbase
127
131
  yield
128
132
  rescue Coinbase::Client::ApiError => e
129
133
  raise Coinbase::APIError.from_error(e), cause: nil
130
- rescue StandardError => e
131
- raise e
134
+ end
135
+
136
+ # Returns a pretty-printed object string that contains the object's class name and
137
+ # the details of the object, filtering out nil values.
138
+ # @param klass [Class] the class of the object
139
+ # @param details [Hash] the details of the object
140
+ # @return [String] the pretty-printed object string
141
+ def self.pretty_print_object(klass, **details)
142
+ filtered_details = details.filter { |_, v| !v.nil? }.map { |k, v| "#{k}: '#{v}'" }
143
+
144
+ "#{klass}{#{filtered_details.join(', ')}}"
132
145
  end
133
146
 
134
147
  # Returns whether to use a server signer to manage private keys.