coinbase-sdk 0.0.10 → 0.0.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) 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 +80 -107
  4. data/lib/coinbase/address.rb +128 -0
  5. data/lib/coinbase/client/api/addresses_api.rb +1 -1
  6. data/lib/coinbase/client/api/assets_api.rb +3 -3
  7. data/lib/coinbase/client/api/contract_events_api.rb +121 -0
  8. data/lib/coinbase/client/api/external_addresses_api.rb +1 -1
  9. data/lib/coinbase/client/api/server_signers_api.rb +1 -1
  10. data/lib/coinbase/client/api/stake_api.rb +242 -1
  11. data/lib/coinbase/client/api/trades_api.rb +1 -1
  12. data/lib/coinbase/client/api/transfers_api.rb +1 -1
  13. data/lib/coinbase/client/api/users_api.rb +1 -1
  14. data/lib/coinbase/client/api/validators_api.rb +1 -1
  15. data/lib/coinbase/client/api/wallets_api.rb +1 -1
  16. data/lib/coinbase/client/api/webhooks_api.rb +286 -0
  17. data/lib/coinbase/client/api_client.rb +1 -1
  18. data/lib/coinbase/client/api_error.rb +1 -1
  19. data/lib/coinbase/client/configuration.rb +11 -1
  20. data/lib/coinbase/client/models/address.rb +1 -1
  21. data/lib/coinbase/client/models/address_balance_list.rb +1 -1
  22. data/lib/coinbase/client/models/address_list.rb +1 -1
  23. data/lib/coinbase/client/models/asset.rb +1 -1
  24. data/lib/coinbase/client/models/balance.rb +1 -1
  25. data/lib/coinbase/client/models/broadcast_staking_operation_request.rb +239 -0
  26. data/lib/coinbase/client/models/broadcast_trade_request.rb +1 -1
  27. data/lib/coinbase/client/models/broadcast_transfer_request.rb +1 -1
  28. data/lib/coinbase/client/models/build_staking_operation_request.rb +1 -1
  29. data/lib/coinbase/client/models/contract_event.rb +336 -0
  30. data/lib/coinbase/client/models/contract_event_list.rb +259 -0
  31. data/lib/coinbase/client/models/create_address_request.rb +1 -1
  32. data/lib/coinbase/client/models/create_server_signer_request.rb +1 -1
  33. data/lib/coinbase/client/models/create_staking_operation_request.rb +274 -0
  34. data/lib/coinbase/client/models/create_trade_request.rb +1 -1
  35. data/lib/coinbase/client/models/create_transfer_request.rb +1 -1
  36. data/lib/coinbase/client/models/create_wallet_request.rb +1 -1
  37. data/lib/coinbase/client/models/create_wallet_request_wallet.rb +1 -1
  38. data/lib/coinbase/client/models/create_webhook_request.rb +282 -0
  39. data/lib/coinbase/client/models/error.rb +1 -1
  40. data/lib/coinbase/client/models/ethereum_validator_metadata.rb +1 -1
  41. data/lib/coinbase/client/models/faucet_transaction.rb +1 -1
  42. data/lib/coinbase/client/models/feature.rb +1 -1
  43. data/lib/coinbase/client/models/fetch_staking_rewards200_response.rb +1 -1
  44. data/lib/coinbase/client/models/fetch_staking_rewards_request.rb +1 -1
  45. data/lib/coinbase/client/models/get_staking_context_request.rb +1 -1
  46. data/lib/coinbase/client/models/native_eth_staking_context.rb +1 -1
  47. data/lib/coinbase/client/models/partial_eth_staking_context.rb +1 -1
  48. data/lib/coinbase/client/models/seed_creation_event.rb +1 -1
  49. data/lib/coinbase/client/models/seed_creation_event_result.rb +1 -1
  50. data/lib/coinbase/client/models/server_signer.rb +1 -1
  51. data/lib/coinbase/client/models/server_signer_event.rb +1 -1
  52. data/lib/coinbase/client/models/server_signer_event_event.rb +1 -1
  53. data/lib/coinbase/client/models/server_signer_event_list.rb +1 -1
  54. data/lib/coinbase/client/models/server_signer_list.rb +1 -1
  55. data/lib/coinbase/client/models/signature_creation_event.rb +1 -1
  56. data/lib/coinbase/client/models/signature_creation_event_result.rb +1 -1
  57. data/lib/coinbase/client/models/signed_voluntary_exit_message_metadata.rb +1 -1
  58. data/lib/coinbase/client/models/staking_context.rb +1 -1
  59. data/lib/coinbase/client/models/staking_context_context.rb +1 -1
  60. data/lib/coinbase/client/models/staking_operation.rb +16 -6
  61. data/lib/coinbase/client/models/staking_operation_metadata.rb +1 -1
  62. data/lib/coinbase/client/models/staking_reward.rb +1 -1
  63. data/lib/coinbase/client/models/staking_reward_format.rb +1 -1
  64. data/lib/coinbase/client/models/trade.rb +1 -1
  65. data/lib/coinbase/client/models/trade_list.rb +1 -1
  66. data/lib/coinbase/client/models/transaction.rb +1 -1
  67. data/lib/coinbase/client/models/transaction_type.rb +1 -1
  68. data/lib/coinbase/client/models/transfer.rb +5 -93
  69. data/lib/coinbase/client/models/transfer_list.rb +1 -1
  70. data/lib/coinbase/client/models/update_webhook_request.rb +289 -0
  71. data/lib/coinbase/client/models/user.rb +1 -1
  72. data/lib/coinbase/client/models/validator.rb +1 -1
  73. data/lib/coinbase/client/models/validator_details.rb +1 -1
  74. data/lib/coinbase/client/models/validator_list.rb +1 -1
  75. data/lib/coinbase/client/models/wallet.rb +1 -1
  76. data/lib/coinbase/client/models/wallet_list.rb +1 -1
  77. data/lib/coinbase/client/models/webhook.rb +299 -0
  78. data/lib/coinbase/client/models/webhook_event_filter.rb +236 -0
  79. data/lib/coinbase/client/models/webhook_event_type.rb +41 -0
  80. data/lib/coinbase/client/models/webhook_list.rb +244 -0
  81. data/lib/coinbase/client/version.rb +1 -1
  82. data/lib/coinbase/client.rb +13 -1
  83. data/lib/coinbase/constants.rb +3 -0
  84. data/lib/coinbase/destination.rb +51 -0
  85. data/lib/coinbase/errors.rb +14 -0
  86. data/lib/coinbase/middleware.rb +12 -0
  87. data/lib/coinbase/staking_operation.rb +106 -5
  88. data/lib/coinbase/trade.rb +87 -5
  89. data/lib/coinbase/transaction.rb +13 -2
  90. data/lib/coinbase/transfer.rb +86 -7
  91. data/lib/coinbase/wallet.rb +77 -4
  92. data/lib/coinbase.rb +3 -1
  93. metadata +29 -2
@@ -3,6 +3,7 @@
3
3
  require_relative 'authenticator'
4
4
  require_relative 'client/configuration'
5
5
  require 'faraday'
6
+ require 'faraday/retry'
6
7
 
7
8
  module Coinbase
8
9
  # A module for middleware that can be used with Faraday.
@@ -18,6 +19,17 @@ module Coinbase
18
19
  config.host = uri.host + (uri.port ? ":#{uri.port}" : '')
19
20
  config.scheme = uri.scheme if uri.scheme
20
21
  config.request(:authenticator)
22
+ retry_options = {
23
+ max: Coinbase.configuration.max_network_tries,
24
+ interval: 0.05,
25
+ interval_randomness: 0.5,
26
+ backoff_factor: 2,
27
+ methods: %i[get],
28
+ retry_statuses: [500, 502, 503, 504]
29
+ }
30
+ config.configure_faraday_connection do |conn|
31
+ conn.request :retry, retry_options
32
+ end
21
33
  end
22
34
  end
23
35
  end
@@ -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
@@ -9,6 +9,57 @@ module Coinbase
9
9
  # The fee is assumed to be paid in the native Asset of the Network.
10
10
  # Trades should be created through Wallet#trade or # Address#trade.
11
11
  class Trade
12
+ class << self
13
+ # Creates a new Trade object.
14
+ # @param address_id [String] The Address ID of the sending Address
15
+ # @param from_asset_id [Symbol] The Asset ID of the Asset to trade from
16
+ # @param to_asset_id [Symbol] The Asset ID of the Asset to trade to
17
+ # @param amount [BigDecimal] The amount of the Asset to send
18
+ # @param network_id [Symbol] The Network ID of the Asset
19
+ # @param wallet_id [String] The Wallet ID of the sending Wallet
20
+ # @return [Send] The new pending Send object
21
+ def create(address_id:, from_asset_id:, to_asset_id:, amount:, network_id:, wallet_id:)
22
+ from_asset = Asset.fetch(network_id, from_asset_id)
23
+ to_asset = Asset.fetch(network_id, to_asset_id)
24
+
25
+ model = Coinbase.call_api do
26
+ trades_api.create_trade(
27
+ wallet_id,
28
+ address_id,
29
+ {
30
+ amount: from_asset.to_atomic_amount(amount).to_i.to_s,
31
+ from_asset_id: from_asset.primary_denomination.to_s,
32
+ to_asset_id: to_asset.primary_denomination.to_s
33
+ }
34
+ )
35
+ end
36
+
37
+ new(model)
38
+ end
39
+
40
+ # Enumerates the trades for a given address belonging to a wallet.
41
+ # The result is an enumerator that lazily fetches from the server, and can be iterated over,
42
+ # converted to an array, etc...
43
+ # @return [Enumerable<Coinbase::Trade>] Enumerator that returns trades
44
+ def list(wallet_id:, address_id:)
45
+ Coinbase::Pagination.enumerate(
46
+ ->(page) { fetch_page(wallet_id, address_id, page) }
47
+ ) do |trade|
48
+ new(trade)
49
+ end
50
+ end
51
+
52
+ private
53
+
54
+ def trades_api
55
+ Coinbase::Client::TradesApi.new(Coinbase.configuration.api_client)
56
+ end
57
+
58
+ def fetch_page(wallet_id, address_id, page)
59
+ trades_api.list_trades(wallet_id, address_id, { limit: DEFAULT_PAGE_LIMIT, page: page })
60
+ end
61
+ end
62
+
12
63
  # Returns a new Trade object. Do not use this method directly. Instead, use Wallet#trade or
13
64
  # Address#trade.
14
65
  # @param model [Coinbase::Client::Trade] The underlying Trade object
@@ -76,12 +127,37 @@ module Coinbase
76
127
  @approve_transaction ||= @model.approve_transaction ? Coinbase::Transaction.new(@model.approve_transaction) : nil
77
128
  end
78
129
 
130
+ # Returns the list of Transactions for the Trade.
131
+ def transactions
132
+ [approve_transaction, transaction].compact
133
+ end
134
+
79
135
  # Returns the status of the Trade.
80
136
  # @return [Symbol] The status
81
137
  def status
82
138
  transaction.status
83
139
  end
84
140
 
141
+ # Broadcasts the Trade to the Network.
142
+ # This raises an error if the Trade is not signed.
143
+ # @raise [RuntimeError] If the Trade is not signed
144
+ # @return [Trade] The Trade object
145
+ def broadcast!
146
+ raise TransactionNotSignedError unless transactions.all?(&:signed?)
147
+
148
+ payloads = { signed_payload: transaction.raw.hex }
149
+
150
+ payloads[:approve_transaction_signed_payload] = approve_transaction.raw.hex unless approve_transaction.nil?
151
+
152
+ @model = Coinbase.call_api do
153
+ trades_api.broadcast_trade(wallet_id, address_id, id, payloads)
154
+ end
155
+
156
+ update_transactions(@model)
157
+
158
+ self
159
+ end
160
+
85
161
  # Waits until the Trade is completed or failed by polling the Network at the given interval. Raises a
86
162
  # Timeout::Error if the Trade takes longer than the given timeout.
87
163
  # @param interval_seconds [Integer] The interval at which to poll the Network, in seconds
@@ -114,11 +190,7 @@ module Coinbase
114
190
  trades_api.get_trade(wallet_id, address_id, id)
115
191
  end
116
192
 
117
- # Update the memoized transaction.
118
- @transaction = Coinbase::Transaction.new(@model.transaction)
119
-
120
- # Update the memoized approve transaction if it exists.
121
- @approve_transaction = @model.approve_transaction ? Coinbase::Transaction.new(@model.approve_transaction) : nil
193
+ update_transactions(@model)
122
194
 
123
195
  self
124
196
  end
@@ -140,6 +212,16 @@ module Coinbase
140
212
 
141
213
  private
142
214
 
215
+ def update_transactions(model)
216
+ # Update the memoized transaction.
217
+ @transaction = Coinbase::Transaction.new(model.transaction)
218
+
219
+ return if model.approve_transaction.nil?
220
+
221
+ # Update the memoized approve transaction if it exists.
222
+ @approve_transaction = Coinbase::Transaction.new(model.approve_transaction)
223
+ end
224
+
143
225
  def trades_api
144
226
  @trades_api ||= Coinbase::Client::TradesApi.new(Coinbase.configuration.api_client)
145
227
  end
@@ -15,6 +15,9 @@ module Coinbase
15
15
  # At this point, transaction hashes may not yet be assigned.
16
16
  PENDING = 'pending'
17
17
 
18
+ # The Transaction has been signed, but has not been successfully broadcast yet.
19
+ SIGNED = 'signed'
20
+
18
21
  # The Transaction has been broadcast to the Network.
19
22
  # At this point, at least the transaction hash should be assigned.
20
23
  BROADCAST = 'broadcast'
@@ -84,6 +87,14 @@ module Coinbase
84
87
  def raw
85
88
  return @raw unless @raw.nil?
86
89
 
90
+ # If the transaction is signed, decode the signed payload.
91
+ unless signed_payload.nil?
92
+ @raw = Eth::Tx::Eip1559.decode(signed_payload)
93
+
94
+ return @raw
95
+ end
96
+
97
+ # If the transaction is unsigned, parse the unsigned payload into an EIP-1559 transaction.
87
98
  raw_payload = [unsigned_payload].pack('H*')
88
99
  parsed_payload = JSON.parse(raw_payload)
89
100
 
@@ -93,8 +104,8 @@ module Coinbase
93
104
  priority_fee: parsed_payload['maxPriorityFeePerGas'].to_i(16),
94
105
  max_gas_fee: parsed_payload['maxFeePerGas'].to_i(16),
95
106
  gas_limit: parsed_payload['gas'].to_i(16), # TODO: Handle multiple currencies.
96
- from: Eth::Address.new(from_address_id),
97
- to: Eth::Address.new(parsed_payload['to']),
107
+ from: from_address_id,
108
+ to: parsed_payload['to'],
98
109
  value: parsed_payload['value'].to_i(16),
99
110
  data: parsed_payload['input'] || ''
100
111
  }
@@ -11,6 +11,62 @@ module Coinbase
11
11
  # in the native Asset of the Network. Transfers should be created through Wallet#transfer or
12
12
  # Address#transfer.
13
13
  class Transfer
14
+ class << self
15
+ # Creates a new Transfer object.
16
+ # @param address_id [String] The Address ID of the sending Address
17
+ # @param amount [BigDecimal] The amount of the Asset to send
18
+ # @param asset_id [Symbol] The Asset ID of the Asset to send
19
+ # @param destination [Coinbase::Destination, Coinbase::Wallet, Coinbase::Address, String]
20
+ # The destination of the transfer.
21
+ # If the destination is a Wallet, it uses the default Address of the Wallet.
22
+ # If the destination is an Address, it uses the Address's ID.
23
+ # If the destination is a String, it uses it as the Address ID.
24
+ # @param network_id [Symbol] The Network ID of the Asset
25
+ # @param wallet_id [String] The Wallet ID of the sending Wallet
26
+ # @return [Transfer] The new pending Transfer object
27
+ # @raise [Coinbase::ApiError] If the Transfer fails
28
+ def create(address_id:, amount:, asset_id:, destination:, network_id:, wallet_id:)
29
+ asset = Asset.fetch(network_id, asset_id)
30
+
31
+ model = Coinbase.call_api do
32
+ transfers_api.create_transfer(
33
+ wallet_id,
34
+ address_id,
35
+ {
36
+ amount: asset.to_atomic_amount(amount).to_i.to_s,
37
+ asset_id: asset.primary_denomination.to_s,
38
+ destination: Coinbase::Destination.new(destination, network_id: network_id).address_id,
39
+ network_id: Coinbase.normalize_network(network_id)
40
+ }
41
+ )
42
+ end
43
+
44
+ new(model)
45
+ end
46
+
47
+ # Enumerates the transfers for a given address belonging to a wallet.
48
+ # The result is an enumerator that lazily fetches from the server, and can be iterated over,
49
+ # converted to an array, etc...
50
+ # @return [Enumerable<Coinbase::Transfer>] Enumerator that returns transfers
51
+ def list(wallet_id:, address_id:)
52
+ Coinbase::Pagination.enumerate(
53
+ ->(page) { fetch_page(wallet_id, address_id, page) }
54
+ ) do |transfer|
55
+ new(transfer)
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ def transfers_api
62
+ Coinbase::Client::TransfersApi.new(Coinbase.configuration.api_client)
63
+ end
64
+
65
+ def fetch_page(wallet_id, address_id, page)
66
+ transfers_api.list_transfers(wallet_id, address_id, { limit: DEFAULT_PAGE_LIMIT, page: page })
67
+ end
68
+ end
69
+
14
70
  # Returns a new Transfer object. Do not use this method directly. Instead, use Wallet#transfer or
15
71
  # Address#transfer.
16
72
  # @param model [Coinbase::Client::Transfer] The underlying Transfer object
@@ -69,20 +125,19 @@ module Coinbase
69
125
  # Returns the link to the transaction on the blockchain explorer.
70
126
  # @return [String] The link to the transaction on the blockchain explorer
71
127
  def transaction_link
72
- # TODO: Parameterize this by Network.
73
- "https://sepolia.basescan.org/tx/#{transaction_hash}"
128
+ transaction.transaction_link
74
129
  end
75
130
 
76
131
  # Returns the Unsigned Payload of the Transfer.
77
132
  # @return [String] The Unsigned Payload
78
133
  def unsigned_payload
79
- @model.unsigned_payload
134
+ transaction.unsigned_payload
80
135
  end
81
136
 
82
137
  # Returns the Signed Payload of the Transfer.
83
138
  # @return [String] The Signed Payload
84
139
  def signed_payload
85
- @model.signed_payload
140
+ transaction.signed_payload
86
141
  end
87
142
 
88
143
  # Returns the Transfer transaction.
@@ -94,7 +149,7 @@ module Coinbase
94
149
  # Returns the Transaction Hash of the Transfer.
95
150
  # @return [String] The Transaction Hash
96
151
  def transaction_hash
97
- @model.transaction_hash
152
+ transaction.transaction_hash
98
153
  end
99
154
 
100
155
  # Returns the status of the Transfer.
@@ -103,6 +158,27 @@ module Coinbase
103
158
  transaction.status
104
159
  end
105
160
 
161
+ # Broadcasts the Transfer to the Network.
162
+ # This raises an error if the Transfer is not signed.
163
+ # @raise [RuntimeError] If the Transfer is not signed
164
+ # @return [Transfer] The Transfer object
165
+ def broadcast!
166
+ raise TransactionNotSignedError unless transaction.signed?
167
+
168
+ @model = Coinbase.call_api do
169
+ transfers_api.broadcast_transfer(
170
+ wallet_id,
171
+ from_address_id,
172
+ id,
173
+ { signed_payload: transaction.raw.hex }
174
+ )
175
+ end
176
+
177
+ update_transaction(@model)
178
+
179
+ self
180
+ end
181
+
106
182
  # Reload reloads the Transfer model with the latest version from the server side.
107
183
  # @return [Transfer] The most recent version of Transfer from the server.
108
184
  def reload
@@ -110,8 +186,7 @@ module Coinbase
110
186
  transfers_api.get_transfer(wallet_id, from_address_id, id)
111
187
  end
112
188
 
113
- # Update memoized transaction.
114
- @transaction = Coinbase::Transaction.new(@model.transaction)
189
+ update_transaction(@model)
115
190
 
116
191
  self
117
192
  end
@@ -157,5 +232,9 @@ module Coinbase
157
232
  def transfers_api
158
233
  @transfers_api ||= Coinbase::Client::TransfersApi.new(Coinbase.configuration.api_client)
159
234
  end
235
+
236
+ def update_transaction(model)
237
+ @transaction = Coinbase::Transaction.new(model.transaction)
238
+ end
160
239
  end
161
240
  end
@@ -13,9 +13,6 @@ module Coinbase
13
13
  # The maximum number of addresses in a Wallet.
14
14
  MAX_ADDRESSES = 20
15
15
 
16
- # The maximum number of wallets to fetch in a single page.
17
- PAGE_LIMIT = 100
18
-
19
16
  # A representation of ServerSigner status in a Wallet.
20
17
  module ServerSignerStatus
21
18
  # The Wallet is awaiting seed creation by the ServerSigner. At this point,
@@ -131,7 +128,7 @@ module Coinbase
131
128
  end
132
129
 
133
130
  def fetch_wallets_page(page)
134
- wallets_api.list_wallets({ limit: PAGE_LIMIT, page: page })
131
+ wallets_api.list_wallets({ limit: DEFAULT_PAGE_LIMIT, page: page })
135
132
  end
136
133
  end
137
134
 
@@ -297,6 +294,82 @@ module Coinbase
297
294
  default_address.trade(amount, from_asset_id, to_asset_id)
298
295
  end
299
296
 
297
+ # Stakes the given amount of the given Asset.
298
+ # Currently only the default_address is used to source the Stake.
299
+ # @param amount [Integer, Float, BigDecimal] The amount of the Asset to stake.
300
+ # @param asset_id [Symbol] The ID of the Asset to stake.
301
+ # @param mode [Symbol] (Optional) The staking mode. Defaults to :default.
302
+ # @param options [Hash] (Optional) Additional options for the staking operation.
303
+ # @return [Coinbase::StakingOperation] The stake operation
304
+ def stake(amount, asset_id, mode: :default, options: {})
305
+ default_address.stake(amount, asset_id, mode: mode, options: options)
306
+ end
307
+
308
+ # Unstakes the given amount of the given Asset.
309
+ # Currently only the default_address is used to source the Unstake.
310
+ # @param amount [Integer, Float, BigDecimal] The amount of the Asset to unstake.
311
+ # @param asset_id [Symbol] The ID of the Asset to unstake.
312
+ # @param mode [Symbol] (Optional) The staking mode. Defaults to :default.
313
+ # @param options [Hash] (Optional) Additional options for the unstaking operation.
314
+ # @return [Coinbase::StakingOperation] The unstake operation
315
+ def unstake(amount, asset_id, mode: :default, options: {})
316
+ default_address.unstake(amount, asset_id, mode: mode, options: options)
317
+ end
318
+
319
+ # Claims stake of the given amount of the given Asset.
320
+ # Currently only the default_address is used as the source for claim_stake.
321
+ # @param amount [Integer, Float, BigDecimal] The amount of the Asset to claim_stake.
322
+ # @param asset_id [Symbol] The ID of the Asset to claim_stake.
323
+ # @param mode [Symbol] (Optional) The staking mode. Defaults to :default.
324
+ # @param options [Hash] (Optional) Additional options for the unstaking operation.
325
+ # @return [Coinbase::StakingOperation] The claim_stake operation
326
+ def claim_stake(amount, asset_id, mode: :default, options: {})
327
+ default_address.claim_stake(amount, asset_id, mode: mode, options: options)
328
+ end
329
+
330
+ # Retrieves the balances used for staking for the supplied asset.
331
+ # Currently only the default_address is used to source the staking balances.
332
+ # @param asset_id [Symbol] The asset to retrieve staking balances for
333
+ # @param mode [Symbol] The staking mode. Defaults to :default.
334
+ # @param options [Hash] Additional options for the staking operation
335
+ # @return [Hash] The staking balances
336
+ # @return [BigDecimal] :stakeable_balance The amount of the asset that can be staked
337
+ # @return [BigDecimal] :unstakeable_balance The amount of the asset that is currently staked and cannot be unstaked
338
+ # @return [BigDecimal] :claimable_balance The amount of the asset that can be claimed
339
+ def staking_balances(asset_id, mode: :default, options: {})
340
+ default_address.staking_balances(asset_id, mode: mode, options: options)
341
+ end
342
+
343
+ # Retrieves the stakeable balance for the supplied asset.
344
+ # Currently only the default_address is used to source the stakeable balance.
345
+ # @param asset_id [Symbol] The asset to retrieve the stakeable balance for
346
+ # @param mode [Symbol] The staking mode. Defaults to :default.
347
+ # @param options [Hash] Additional options for the staking operation
348
+ # @return [BigDecimal] The stakeable balance
349
+ def stakeable_balance(asset_id, mode: :default, options: {})
350
+ default_address.stakeable_balance(asset_id, mode: mode, options: options)
351
+ end
352
+
353
+ # Retrieves the unstakeable balance for the supplied asset.
354
+ # Currently only the default_address is used to source the unstakeable balance.
355
+ # @param asset_id [Symbol] The asset to retrieve the unstakeable balance for
356
+ # @param mode [Symbol] The staking mode. Defaults to :default.
357
+ # @param options [Hash] Additional options for the staking operation
358
+ # @return [BigDecimal] The unstakeable balance
359
+ def unstakeable_balance(asset_id, mode: :default, options: {})
360
+ default_address.unstakeable_balance(asset_id, mode: mode, options: options)
361
+ end
362
+
363
+ # Retrieves the claimable balance for the supplied asset.
364
+ # Currently only the default_address is used to source the claimable balance.
365
+ # @param asset_id [Symbol] The asset to retrieve the claimable balance for
366
+ # @param mode [Symbol] The staking mode. Defaults to :default.
367
+ # @param options [Hash] Additional options for the staking operation
368
+ # @return [BigDecimal] The claimable balance
369
+ def claimable_balance(asset_id, mode: :default, options: {})
370
+ default_address.claimable_balance(asset_id, mode: mode, options: options)
371
+ end
372
+
300
373
  # Exports the Wallet's data to a Data object.
301
374
  # @return [Data] The Wallet data
302
375
  def export
data/lib/coinbase.rb CHANGED
@@ -9,6 +9,7 @@ require_relative 'coinbase/balance'
9
9
  require_relative 'coinbase/balance_map'
10
10
  require_relative 'coinbase/client'
11
11
  require_relative 'coinbase/constants'
12
+ require_relative 'coinbase/destination'
12
13
  require_relative 'coinbase/errors'
13
14
  require_relative 'coinbase/faucet_transaction'
14
15
  require_relative 'coinbase/middleware'
@@ -61,13 +62,14 @@ module Coinbase
61
62
 
62
63
  # Configuration object for the Coinbase SDK.
63
64
  class Configuration
64
- attr_accessor :api_url, :api_key_name, :api_key_private_key, :debug_api, :use_server_signer
65
+ attr_accessor :api_url, :api_key_name, :api_key_private_key, :debug_api, :use_server_signer, :max_network_tries
65
66
 
66
67
  # Initializes the configuration object.
67
68
  def initialize
68
69
  @api_url = 'https://api.cdp.coinbase.com'
69
70
  @debug_api = false
70
71
  @use_server_signer = false
72
+ @max_network_tries = 3
71
73
  end
72
74
 
73
75
  # Sets configuration values based on the provided CDP API Key JSON file.