coinbase-sdk 0.0.14 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/lib/coinbase/address/wallet_address.rb +31 -21
  3. data/lib/coinbase/address.rb +51 -17
  4. data/lib/coinbase/asset.rb +11 -8
  5. data/lib/coinbase/client/api/contract_events_api.rb +17 -9
  6. data/lib/coinbase/client/api/external_addresses_api.rb +85 -0
  7. data/lib/coinbase/client/api/networks_api.rb +85 -0
  8. data/lib/coinbase/client/api/stake_api.rb +74 -195
  9. data/lib/coinbase/client/api/validators_api.rb +2 -2
  10. data/lib/coinbase/client/api/wallet_stake_api.rb +263 -0
  11. data/lib/coinbase/client/models/address.rb +21 -4
  12. data/lib/coinbase/client/models/{native_eth_staking_context.rb → address_historical_balance_list.rb} +39 -35
  13. data/lib/coinbase/client/models/contract_event.rb +99 -8
  14. data/lib/coinbase/client/models/create_address_request.rb +14 -4
  15. data/lib/coinbase/client/models/create_transfer_request.rb +14 -4
  16. data/lib/coinbase/client/models/ethereum_validator_metadata.rb +11 -11
  17. data/lib/coinbase/client/models/feature.rb +2 -1
  18. data/lib/coinbase/client/models/feature_set.rb +307 -0
  19. data/lib/coinbase/client/models/{partial_eth_staking_context.rb → fetch_historical_staking_balances200_response.rb} +39 -35
  20. data/lib/coinbase/client/models/historical_balance.rb +273 -0
  21. data/lib/coinbase/client/models/network.rb +365 -0
  22. data/lib/coinbase/client/models/network_identifier.rb +44 -0
  23. data/lib/coinbase/client/models/sponsored_send.rb +338 -0
  24. data/lib/coinbase/client/models/staking_balance.rb +289 -0
  25. data/lib/coinbase/client/models/staking_context_context.rb +222 -74
  26. data/lib/coinbase/client/models/staking_operation.rb +2 -2
  27. data/lib/coinbase/client/models/staking_reward.rb +22 -6
  28. data/lib/coinbase/client/models/staking_reward_format.rb +2 -1
  29. data/lib/coinbase/client/models/staking_reward_usd_value.rb +257 -0
  30. data/lib/coinbase/client/models/transaction.rb +17 -7
  31. data/lib/coinbase/client/models/transaction_type.rb +2 -1
  32. data/lib/coinbase/client/models/transfer.rb +101 -8
  33. data/lib/coinbase/client/models/validator.rb +23 -2
  34. data/lib/coinbase/client/models/validator_status.rb +52 -0
  35. data/lib/coinbase/client/models/wallet.rb +13 -16
  36. data/lib/coinbase/client/models/webhook_event_type.rb +2 -1
  37. data/lib/coinbase/client.rb +12 -3
  38. data/lib/coinbase/constants.rb +0 -10
  39. data/lib/coinbase/contract_event.rb +104 -0
  40. data/lib/coinbase/correlation.rb +30 -0
  41. data/lib/coinbase/destination.rb +11 -9
  42. data/lib/coinbase/errors.rb +14 -0
  43. data/lib/coinbase/historical_balance.rb +53 -0
  44. data/lib/coinbase/middleware.rb +2 -0
  45. data/lib/coinbase/network.rb +103 -20
  46. data/lib/coinbase/server_signer.rb +14 -3
  47. data/lib/coinbase/smart_contract.rb +106 -0
  48. data/lib/coinbase/sponsored_send.rb +110 -0
  49. data/lib/coinbase/staking_balance.rb +92 -0
  50. data/lib/coinbase/staking_operation.rb +134 -36
  51. data/lib/coinbase/staking_reward.rb +18 -0
  52. data/lib/coinbase/trade.rb +10 -9
  53. data/lib/coinbase/transaction.rb +13 -3
  54. data/lib/coinbase/transfer.rb +65 -36
  55. data/lib/coinbase/validator.rb +18 -10
  56. data/lib/coinbase/version.rb +5 -0
  57. data/lib/coinbase/wallet/data.rb +31 -0
  58. data/lib/coinbase/wallet.rb +143 -182
  59. data/lib/coinbase/webhook.rb +181 -0
  60. data/lib/coinbase.rb +64 -21
  61. metadata +51 -5
  62. data/lib/coinbase/user.rb +0 -65
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coinbase
4
+ # A representation of a SmartContract on the blockchain.
5
+ class SmartContract
6
+ # Returns a list of ContractEvents for the provided network, contract, and event details.
7
+ # @param network_id [Symbol] The network ID
8
+ # @param protocol_name [String] The protocol name
9
+ # @param contract_address [String] The contract address
10
+ # @param contract_name [String] The contract name
11
+ # @param event_name [String] The event name
12
+ # @param from_block_height [Integer] The start block height
13
+ # @param to_block_height [Integer] The end block height
14
+ # @return [Enumerable<Coinbase::ContractEvent>] The contract events
15
+ def self.list_events(
16
+ network_id:,
17
+ protocol_name:,
18
+ contract_address:,
19
+ contract_name:,
20
+ event_name:,
21
+ from_block_height:,
22
+ to_block_height:
23
+ )
24
+ Coinbase::Pagination.enumerate(
25
+ lambda { |page|
26
+ list_events_page(network_id, protocol_name, contract_address, contract_name, event_name, from_block_height,
27
+ to_block_height, page)
28
+ }
29
+ ) do |contract_event|
30
+ Coinbase::ContractEvent.new(contract_event)
31
+ end
32
+ end
33
+
34
+ # Returns a new SmartContract object.
35
+ # @param model [Coinbase::Client::SmartContract] The underlying SmartContract object
36
+ def initialize(model)
37
+ @model = model
38
+ end
39
+
40
+ # Returns the network ID of the SmartContract.
41
+ # @return [String] The network ID
42
+ def network_id
43
+ Coinbase.to_sym(@model.network_id)
44
+ end
45
+
46
+ # Returns the protocol name of the SmartContract.
47
+ # @return [String] The protocol name
48
+ def protocol_name
49
+ @model.protocol_name
50
+ end
51
+
52
+ # Returns the contract name of the SmartContract.
53
+ # @return [String] The contract name
54
+ def contract_name
55
+ @model.contract_name
56
+ end
57
+
58
+ # Returns the address of the SmartContract.
59
+ # @return [String] The contract address
60
+ def address
61
+ @model.address
62
+ end
63
+
64
+ # Returns a string representation of the SmartContract.
65
+ # @return [String] a string representation of the SmartContract
66
+ def to_s
67
+ "Coinbase::SmartContract{
68
+ network_id: '#{network_id}',
69
+ protocol_name: '#{protocol_name}',
70
+ contract_name: '#{contract_name}',
71
+ address: '#{address}'}"
72
+ end
73
+
74
+ # Same as to_s.
75
+ # @return [String] a string representation of the SmartContract
76
+ def inspect
77
+ to_s
78
+ end
79
+
80
+ def self.contract_events_api
81
+ Coinbase::Client::ContractEventsApi.new(Coinbase.configuration.api_client)
82
+ end
83
+
84
+ def self.list_events_page(
85
+ network_id,
86
+ protocol_name,
87
+ contract_address,
88
+ contract_name,
89
+ event_name,
90
+ from_block_height,
91
+ to_block_height,
92
+ page
93
+ )
94
+ contract_events_api.list_contract_events(
95
+ Coinbase.normalize_network(network_id),
96
+ protocol_name,
97
+ contract_address,
98
+ contract_name,
99
+ event_name,
100
+ from_block_height,
101
+ to_block_height,
102
+ { next_page: page }
103
+ )
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'eth'
4
+
5
+ module Coinbase
6
+ # A representation of an onchain Sponsored Send.
7
+ # Sponsored Sends should be constructed via higher level abstractions like Transfer.
8
+ class SponsoredSend
9
+ # A representation of a Transaction status.
10
+ module Status
11
+ # The SponsoredSend is awaiting being signed.
12
+ PENDING = 'pending'
13
+
14
+ # The Sponsored Send has been signed, but has not been submitted to be
15
+ # built into a transaction yet.
16
+ SIGNED = 'signed'
17
+
18
+ # The Sponsored Send has been submitted to be built into a transaction,
19
+ # that the sponsor will sign and submit to the network.
20
+ # At this point, transaction hashes may not yet be assigned.
21
+ SUBMITTED = 'submitted'
22
+
23
+ # The Sponsored Send's corresponding transaction is complete and has
24
+ # confirmed on the Network.
25
+ COMPLETE = 'complete'
26
+
27
+ # The Sponsored Send has failed for some reason.
28
+ FAILED = 'failed'
29
+
30
+ # The states that are considered terminal on-chain.
31
+ TERMINAL_STATES = [COMPLETE, FAILED].freeze
32
+ end
33
+
34
+ # Returns a new SponsoredSend object. Do not use this method directly.
35
+ # @param model [Coinbase::Client::SponsoredSend] The underlying SponsoredSend object
36
+ def initialize(model)
37
+ raise unless model.is_a?(Coinbase::Client::SponsoredSend)
38
+
39
+ @model = model
40
+ end
41
+
42
+ # Returns the Keccak256 hash of the typed data. This payload must be signed
43
+ # by the sender to be used as an approval in the EIP-3009 transaction.
44
+ # @return [String] The Keccak256 hash of the typed data
45
+ def typed_data_hash
46
+ @model.typed_data_hash
47
+ end
48
+
49
+ # Returns the signature of the typed data.
50
+ def signature
51
+ @signature ||= @model.signature
52
+ end
53
+
54
+ # Signs the Transaction with the provided key and returns the hex signing payload.
55
+ # @return [String] The hex-encoded signed payload
56
+ def sign(key)
57
+ raise unless key.is_a?(Eth::Key)
58
+ raise Coinbase::AlreadySignedError if signed?
59
+
60
+ @signature = Eth::Util.prefix_hex(key.sign(Eth::Util.hex_to_bin(typed_data_hash)))
61
+ end
62
+
63
+ # Returns whether the Transaction has been signed.
64
+ # @return [Boolean] Whether the Transaction has been signed
65
+ def signed?
66
+ !signature.nil?
67
+ end
68
+
69
+ # Returns the status of the Transaction.
70
+ # @return [Symbol] The status
71
+ def status
72
+ @model.status
73
+ end
74
+
75
+ # Returns whether the Sponsored Send is in a terminal state.
76
+ # @return [Boolean] Whether the Transaction is in a terminal state
77
+ def terminal_state?
78
+ Status::TERMINAL_STATES.include?(status)
79
+ end
80
+
81
+ # Returns the Transaction Hash of the Transaction.
82
+ # @return [String] The Transaction Hash
83
+ def transaction_hash
84
+ @model.transaction_hash
85
+ end
86
+
87
+ # Returns the link to the transaction on the blockchain explorer.
88
+ # @return [String] The link to the transaction on the blockchain explorer
89
+ def transaction_link
90
+ @model.transaction_link
91
+ end
92
+
93
+ # Returns a String representation of the SponsoredSend.
94
+ # @return [String] a String representation of the SponsoredSend
95
+ def to_s
96
+ Coinbase.pretty_print_object(
97
+ self.class,
98
+ status: status,
99
+ transaction_hash: transaction_hash,
100
+ transaction_link: transaction_link
101
+ )
102
+ end
103
+
104
+ # Same as to_s.
105
+ # @return [String] a String representation of the SponsoredSend
106
+ def inspect
107
+ to_s
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'date'
4
+
5
+ module Coinbase
6
+ # A representation of a staking balance on a network for a given asset.
7
+ class StakingBalance
8
+ # Returns a list of StakingBalance for the provided network, asset, and addresses.
9
+ # @param network [Coinbase::Network, Symbol] The Network or Network ID
10
+ # @param asset_id [Symbol] The asset ID
11
+ # @param address_id [String] The address ID
12
+ # @param start_time [Time] The start time. Defaults to one month ago.
13
+ # @param end_time [Time] The end time. Defaults to the current time.
14
+ # @return [Enumerable<Coinbase::StakingBalance>] The staking balances
15
+ def self.list(network, asset_id, address_id, start_time: DateTime.now.prev_month(1), end_time: DateTime.now)
16
+ network = Coinbase::Network.from_id(network)
17
+
18
+ Coinbase::Pagination.enumerate(
19
+ ->(page) { list_page(network, asset_id, address_id, start_time, end_time, page) }
20
+ ) do |staking_balance|
21
+ new(staking_balance)
22
+ end
23
+ end
24
+
25
+ # Returns a new StakingBalance object.
26
+ # @param model [Coinbase::Client::StakingBalance] The underlying StakingBalance object
27
+ def initialize(model)
28
+ @model = model
29
+ end
30
+
31
+ # Returns the date of the StakingBalance.
32
+ # @return [Time] The date
33
+ def date
34
+ @model.date
35
+ end
36
+
37
+ # Returns the onchain address of the StakingBalance.
38
+ # @return [Time] The onchain address
39
+ def address
40
+ @model.address
41
+ end
42
+
43
+ # Returns the bonded stake as a Balance
44
+ # @return [Balance] The bonded stake
45
+ def bonded_stake
46
+ @bonded_stake ||= Balance.from_model(@model.bonded_stake)
47
+ end
48
+
49
+ # Returns the unbonded balance as a Balance
50
+ # @return [Balance] The unbonded balance
51
+ def unbonded_balance
52
+ @unbonded_balance ||= Balance.from_model(@model.unbonded_balance)
53
+ end
54
+
55
+ # Returns the participant type of the StakingBalance.
56
+ # @return [String] The participant type
57
+ def participant_type
58
+ @model.participant_type
59
+ end
60
+
61
+ # Returns a string representation of the StakingBalance.
62
+ # @return [String] a string representation of the StakingBalance
63
+ def to_s
64
+ "Coinbase::StakingBalance{date: '#{date}' address: '#{address}'}"
65
+ end
66
+
67
+ # Same as to_s.
68
+ # @return [String] a string representation of the StakingBalance
69
+ def inspect
70
+ to_s
71
+ end
72
+
73
+ def self.stake_api
74
+ Coinbase::Client::StakeApi.new(Coinbase.configuration.api_client)
75
+ end
76
+
77
+ private_class_method :stake_api
78
+
79
+ def self.list_page(network, asset_id, address_id, start_time, end_time, page)
80
+ stake_api.fetch_historical_staking_balances(
81
+ network.normalized_id,
82
+ asset_id,
83
+ address_id,
84
+ start_time.iso8601,
85
+ end_time.iso8601,
86
+ { next_page: page }
87
+ )
88
+ end
89
+
90
+ private_class_method :list_page
91
+ end
92
+ end
@@ -11,22 +11,24 @@ module Coinbase
11
11
 
12
12
  # Builds an ephemeral staking operation this is intended to be called via an Address or Wallet.
13
13
  # @param amount [BigDecimal] The amount to stake, in the primary denomination of the asset
14
- # @param network_id [Symbol] The Network ID
14
+ # @param network [Coinbase::Network, Symbol] The Network or Network ID
15
15
  # @param asset_id [Symbol] The Asset ID
16
16
  # @param address_id [String] The Address ID
17
17
  # @param action [Symbol] The action to perform
18
18
  # @param mode [Symbol] The staking mode
19
19
  # @param options [Hash] Additional options
20
20
  # @return [Coinbase::StakingOperation] The staking operation
21
- def self.build(amount, network_id, asset_id, address_id, action, mode, options)
21
+ def self.build(amount, network, asset_id, address_id, action, mode, options)
22
+ network = Coinbase::Network.from_id(network)
23
+ asset = network.get_asset(asset_id)
24
+
22
25
  model = Coinbase.call_api do
23
- asset = Coinbase::Asset.fetch(network_id, asset_id)
24
26
  stake_api.build_staking_operation(
25
27
  {
26
28
  asset_id: asset.primary_denomination.to_s,
27
29
  address_id: address_id,
28
30
  action: action,
29
- network_id: Coinbase.normalize_network(network_id),
31
+ network_id: Coinbase.normalize_network(network),
30
32
  options: {
31
33
  amount: asset.to_atomic_amount(amount).to_i.to_s,
32
34
  mode: mode
@@ -40,7 +42,7 @@ module Coinbase
40
42
 
41
43
  # Creates a persisted staking operation this is intended to be called via an Address or Wallet.
42
44
  # @param amount [BigDecimal] The amount to stake, in the primary denomination of the asset
43
- # @param network_id [Symbol] The Network ID
45
+ # @param network [Coinbase::Network, Symbol] The Network or Network ID
44
46
  # @param asset_id [Symbol] The Asset ID
45
47
  # @param address_id [String] The Address ID
46
48
  # @param wallet_id [String] The Wallet ID
@@ -48,17 +50,19 @@ module Coinbase
48
50
  # @param mode [Symbol] The staking mode
49
51
  # @param options [Hash] Additional options
50
52
  # @return [Coinbase::StakingOperation] The staking operation
51
- def self.create(amount, network_id, asset_id, address_id, wallet_id, action, mode, options)
53
+ def self.create(amount, network, asset_id, address_id, wallet_id, action, mode, options)
54
+ network = Coinbase::Network.from_id(network)
55
+ asset = network.get_asset(asset_id)
56
+
52
57
  model = Coinbase.call_api do
53
- asset = Coinbase::Asset.fetch(network_id, asset_id)
54
- stake_api.create_staking_operation(
58
+ wallet_stake_api.create_staking_operation(
55
59
  wallet_id,
56
60
  address_id,
57
61
  {
58
62
  asset_id: asset.primary_denomination.to_s,
59
63
  address_id: address_id,
60
64
  action: action,
61
- network_id: Coinbase.normalize_network(network_id),
65
+ network_id: Coinbase.normalize_network(network),
62
66
  options: {
63
67
  amount: asset.to_atomic_amount(amount).to_i.to_s,
64
68
  mode: mode
@@ -70,10 +74,24 @@ module Coinbase
70
74
  new(model)
71
75
  end
72
76
 
77
+ def self.stake_api
78
+ Coinbase::Client::StakeApi.new(Coinbase.configuration.api_client)
79
+ end
80
+
81
+ private_class_method :stake_api
82
+
83
+ def self.wallet_stake_api
84
+ Coinbase::Client::WalletStakeApi.new(Coinbase.configuration.api_client)
85
+ end
86
+
87
+ private_class_method :wallet_stake_api
88
+
73
89
  # Returns a new StakingOperation object.
74
90
  # @param model [Coinbase::Client::StakingOperation] The underlying StakingOperation object
75
91
  def initialize(model)
76
- from_model(model)
92
+ @model = model
93
+ @transactions ||= []
94
+ update_transactions(model.transactions)
77
95
  end
78
96
 
79
97
  # Returns the Staking Operation ID.
@@ -82,10 +100,10 @@ module Coinbase
82
100
  @model.id
83
101
  end
84
102
 
85
- # Returns the Network ID of the Staking Operation.
86
- # @return [Symbol] The Network ID
87
- def network_id
88
- Coinbase.to_sym(@model.network_id)
103
+ # Returns the Network of the Staking Operation.
104
+ # @return [Coinbase::Network] The Network
105
+ def network
106
+ @network ||= Coinbase::Network.from_id(@model.network_id)
89
107
  end
90
108
 
91
109
  # Returns the Address ID of the Staking Operation.
@@ -100,18 +118,48 @@ module Coinbase
100
118
  @model.status
101
119
  end
102
120
 
121
+ # Returns whether the Staking Operation is in a terminal state.
122
+ # @return [Boolean] Whether the Staking Operation is in a terminal state
123
+ def terminal_state?
124
+ failed? || completed?
125
+ end
126
+
127
+ # Returns whether the Staking Operation is in a failed state.
128
+ # @return [Boolean] Whether the Staking Operation is in a failed state
129
+ def failed?
130
+ status == 'failed'
131
+ end
132
+
133
+ # Returns whether the Staking Operation is in a complete state.
134
+ # @return [Boolean] Whether the Staking Operation is in a complete state
135
+ def completed?
136
+ status == 'complete'
137
+ end
138
+
139
+ # Returns a String representation of the Staking Operation.
140
+ # @return [String] a String representation of the Staking Operation
141
+ def to_s
142
+ Coinbase.pretty_print_object(
143
+ self.class,
144
+ id: id,
145
+ status: status,
146
+ network_id: network.id,
147
+ address_id: address_id
148
+ )
149
+ end
150
+
103
151
  # Returns the Wallet ID of the Staking Operation.
104
152
  # @return [String] The Wallet ID
105
153
  def wallet_id
106
154
  @model.wallet_id
107
155
  end
108
156
 
109
- # Waits until the Staking Operation is completed or failed by polling its status at the given interval. Raises a
110
- # Timeout::Error if the Staking Operation takes longer than the given timeout.
157
+ # Waits until the Staking Operation is completed or failed by polling its status at the given interval.
111
158
  # @param interval_seconds [Integer] The interval at which to poll, in seconds
112
159
  # @param timeout_seconds [Integer] The maximum amount of time
113
160
  # to wait for the StakingOperation to complete, in seconds
114
161
  # @return [StakingOperation] The completed StakingOperation object
162
+ # @raise [Timeout::Error] if the Staking Operation takes longer than the given timeout.
115
163
  def wait!(interval_seconds = 5, timeout_seconds = 3600)
116
164
  start_time = Time.now
117
165
 
@@ -119,7 +167,7 @@ module Coinbase
119
167
  reload
120
168
 
121
169
  # Wait for the Staking Operation to be in a terminal state.
122
- break if status == 'complete'
170
+ break if terminal_state?
123
171
 
124
172
  raise Timeout::Error, 'Staking Operation timed out' if Time.now - start_time > timeout_seconds
125
173
 
@@ -129,18 +177,58 @@ module Coinbase
129
177
  self
130
178
  end
131
179
 
180
+ # Complete helps the Staking Operation reach complete state, by polling its status at the given interval, signing
181
+ # and broadcasting any available transaction.
182
+ # @param key [Eth::Key] The key to sign the Staking Operation transactions with
183
+ # @param interval_seconds [Integer] The interval at which to poll, in seconds
184
+ # @param timeout_seconds [Integer] The maximum amount of time
185
+ # to wait for the StakingOperation to complete, in seconds
186
+ # @return [StakingOperation] The completed StakingOperation object
187
+ # @raise [Timeout::Error] if the Staking Operation takes longer than the given timeout.
188
+ def complete(key, interval_seconds: 5, timeout_seconds: 600)
189
+ start_time = Time.now
190
+
191
+ loop do
192
+ @transactions.each_with_index do |transaction, i|
193
+ next if transaction.signed?
194
+
195
+ transaction.sign(key)
196
+ @model = Coinbase.call_api do
197
+ stake_api.broadcast_staking_operation(
198
+ wallet_id,
199
+ address_id,
200
+ id,
201
+ { signed_payload: transaction.raw.hex, transaction_index: i }
202
+ )
203
+ end
204
+ end
205
+
206
+ return self if terminal_state?
207
+
208
+ reload
209
+
210
+ raise Timeout::Error, 'Staking Operation timed out' if Time.now - start_time > timeout_seconds
211
+
212
+ sleep interval_seconds
213
+ end
214
+
215
+ self
216
+ end
217
+
132
218
  # Fetch the StakingOperation with the provided network, address and staking operation ID.
133
- # @param network_id [Symbol] The Network ID
219
+ # @param network [Coinbase::Network, Symbol] The Network or Network ID
134
220
  # @param address_id [Symbol] The Address ID
135
221
  # @param id [String] The ID of the StakingOperation
136
222
  # @param wallet_id [String] The optional Wallet ID
137
223
  # @return [Coinbase::StakingOperation] The staking operation
138
- def self.fetch(network_id, address_id, id, wallet_id: nil)
224
+ def self.fetch(network, address_id, id, wallet_id: nil)
225
+ network = Coinbase::Network.from_id(network)
226
+
139
227
  staking_operation_model = Coinbase.call_api do
140
228
  if wallet_id.nil?
141
- stake_api.get_external_staking_operation(network_id, address_id, id)
229
+ stake_api.get_external_staking_operation(network.id, address_id, id)
142
230
  else
143
- stake_api.get_staking_operation(wallet_id, address_id, id)
231
+ wallet_stake_api.get_staking_operation(wallet_id, address_id, id)
144
232
  end
145
233
  end
146
234
 
@@ -160,13 +248,15 @@ module Coinbase
160
248
  def reload
161
249
  @model = Coinbase.call_api do
162
250
  if wallet_id.nil?
163
- stake_api.get_external_staking_operation(network_id, address_id, id)
251
+ stake_api.get_external_staking_operation(network.id, address_id, id)
164
252
  else
165
- stake_api.get_staking_operation(wallet_id, address_id, id)
253
+ wallet_stake_api.get_staking_operation(wallet_id, address_id, id)
166
254
  end
167
255
  end
168
256
 
169
- from_model(@model)
257
+ update_transactions(@model.transactions)
258
+
259
+ self
170
260
  end
171
261
 
172
262
  # Fetches the presigned_voluntary exit messages for the staking operation
@@ -191,7 +281,7 @@ module Coinbase
191
281
  raise TransactionNotSignedError unless transaction.signed?
192
282
 
193
283
  Coinbase.call_api do
194
- stake_api.broadcast_staking_operation(
284
+ wallet_stake_api.broadcast_staking_operation(
195
285
  wallet_id,
196
286
  address_id,
197
287
  id,
@@ -203,24 +293,32 @@ module Coinbase
203
293
  self
204
294
  end
205
295
 
206
- def self.stake_api
207
- Coinbase::Client::StakeApi.new(Coinbase.configuration.api_client)
208
- end
209
-
210
296
  private
211
297
 
212
298
  def stake_api
213
- @stake_api ||= self.class.stake_api
299
+ @stake_api ||= Coinbase::Client::StakeApi.new(Coinbase.configuration.api_client)
214
300
  end
215
301
 
216
- def from_model(model)
217
- @model = model
218
- @status = model.status
219
- @transactions = model.transactions.map do |transaction_model|
220
- Transaction.new(transaction_model)
302
+ def wallet_stake_api
303
+ @wallet_stake_api ||= Coinbase::Client::WalletStakeApi.new(Coinbase.configuration.api_client)
304
+ end
305
+
306
+ def update_transactions(transactions)
307
+ # Only overwrite the transactions if the response is populated.
308
+ return unless transactions && !transactions.empty?
309
+
310
+ # Create a set of existing unsigned payloads to avoid duplicates.
311
+ existing_unsigned_payloads = Set.new
312
+ @transactions.each do |transaction|
313
+ existing_unsigned_payloads.add(transaction.unsigned_payload)
221
314
  end
222
315
 
223
- self
316
+ # Add transactions that are not already in the transactions array.
317
+ transactions.each do |transaction_model|
318
+ unless existing_unsigned_payloads.include?(transaction_model.unsigned_payload)
319
+ @transactions << Transaction.new(transaction_model)
320
+ end
321
+ end
224
322
  end
225
323
  end
226
324
  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)
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
@@ -15,12 +15,13 @@ module Coinbase
15
15
  # @param from_asset_id [Symbol] The Asset ID of the Asset to trade from
16
16
  # @param to_asset_id [Symbol] The Asset ID of the Asset to trade to
17
17
  # @param amount [BigDecimal] The amount of the Asset to send
18
- # @param network_id [Symbol] The Network ID of the Asset
18
+ # @param network [Coinbase::Network, Symbol] The Network or Network ID of the Asset
19
19
  # @param wallet_id [String] The Wallet ID of the sending Wallet
20
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)
21
+ def create(address_id:, from_asset_id:, to_asset_id:, amount:, network:, wallet_id:)
22
+ network = Coinbase::Network.from_id(network)
23
+ from_asset = network.get_asset(from_asset_id)
24
+ to_asset = network.get_asset(to_asset_id)
24
25
 
25
26
  model = Coinbase.call_api do
26
27
  trades_api.create_trade(
@@ -75,10 +76,10 @@ module Coinbase
75
76
  @model.trade_id
76
77
  end
77
78
 
78
- # Returns the Network ID of the Trade.
79
- # @return [Symbol] The Network ID
80
- def network_id
81
- Coinbase.to_sym(@model.network_id)
79
+ # Returns the Network of the Trade.
80
+ # @return [Coinbase::Network] The Network the Trade is on
81
+ def network
82
+ @network ||= Coinbase::Network.from_id(@model.network_id)
82
83
  end
83
84
 
84
85
  # Returns the Wallet ID of the Trade.
@@ -198,7 +199,7 @@ module Coinbase
198
199
  # Returns a String representation of the Trade.
199
200
  # @return [String] a String representation of the Trade
200
201
  def to_s
201
- "Coinbase::Trade{transfer_id: '#{id}', network_id: '#{network_id}', " \
202
+ "Coinbase::Trade{transfer_id: '#{id}', network_id: '#{network.id}', " \
202
203
  "address_id: '#{address_id}', from_asset_id: '#{from_asset_id}', " \
203
204
  "to_asset_id: '#{to_asset_id}', from_amount: '#{from_amount}', " \
204
205
  "to_amount: '#{to_amount}' status: '#{status}'}"