coinbase-sdk 0.0.5 → 0.0.7

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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/lib/coinbase/address.rb +113 -40
  3. data/lib/coinbase/asset.rb +18 -4
  4. data/lib/coinbase/authenticator.rb +1 -1
  5. data/lib/coinbase/client/api/server_signers_api.rb +429 -0
  6. data/lib/coinbase/client/api/stake_api.rb +86 -0
  7. data/lib/coinbase/client/api/trades_api.rb +342 -0
  8. data/lib/coinbase/client/models/broadcast_trade_request.rb +232 -0
  9. data/lib/coinbase/client/models/build_staking_operation_request.rb +291 -0
  10. data/lib/coinbase/client/models/create_address_request.rb +0 -14
  11. data/lib/coinbase/client/models/create_server_signer_request.rb +239 -0
  12. data/lib/coinbase/client/models/create_trade_request.rb +256 -0
  13. data/lib/coinbase/client/models/create_wallet_request.rb +1 -1
  14. data/lib/coinbase/client/models/create_wallet_request_wallet.rb +233 -0
  15. data/lib/coinbase/client/models/feature.rb +42 -0
  16. data/lib/coinbase/client/models/request_faucet_funds200_response.rb +222 -0
  17. data/lib/coinbase/client/models/seed_creation_event.rb +240 -0
  18. data/lib/coinbase/client/models/seed_creation_event_result.rb +274 -0
  19. data/lib/coinbase/client/models/server_signer.rb +235 -0
  20. data/lib/coinbase/client/models/server_signer_event.rb +239 -0
  21. data/lib/coinbase/client/models/server_signer_event_event.rb +105 -0
  22. data/lib/coinbase/client/models/server_signer_event_list.rb +275 -0
  23. data/lib/coinbase/client/models/server_signer_list.rb +275 -0
  24. data/lib/coinbase/client/models/signature_creation_event.rb +363 -0
  25. data/lib/coinbase/client/models/signature_creation_event_result.rb +329 -0
  26. data/lib/coinbase/client/models/staking_operation.rb +222 -0
  27. data/lib/coinbase/client/models/trade.rb +365 -0
  28. data/lib/coinbase/client/models/trade_list.rb +275 -0
  29. data/lib/coinbase/client/models/transaction.rb +338 -0
  30. data/lib/coinbase/client/models/transaction_type.rb +39 -0
  31. data/lib/coinbase/client/models/transfer.rb +33 -1
  32. data/lib/coinbase/client/models/wallet.rb +74 -4
  33. data/lib/coinbase/client.rb +23 -0
  34. data/lib/coinbase/errors.rb +3 -0
  35. data/lib/coinbase/server_signer.rb +57 -0
  36. data/lib/coinbase/trade.rb +147 -0
  37. data/lib/coinbase/transaction.rb +125 -0
  38. data/lib/coinbase/transfer.rb +38 -71
  39. data/lib/coinbase/user.rb +14 -89
  40. data/lib/coinbase/wallet.rb +188 -27
  41. data/lib/coinbase.rb +19 -4
  42. metadata +43 -2
@@ -17,6 +17,17 @@ module Coinbase
17
17
  # The maximum number of addresses in a Wallet.
18
18
  MAX_ADDRESSES = 20
19
19
 
20
+ # A representation of ServerSigner status in a Wallet.
21
+ module ServerSignerStatus
22
+ # The Wallet is awaiting seed creation by the ServerSigner. At this point,
23
+ # the Wallet cannot create addresses or sign transactions.
24
+ PENDING = 'pending_seed_creation'
25
+
26
+ # The Wallet has an associated seed created by the ServerSigner. It is ready
27
+ # to create addresses and sign transactions.
28
+ ACTIVE = 'active_seed'
29
+ end
30
+
20
31
  class << self
21
32
  # Imports a Wallet from previously exported wallet data.
22
33
  # @param data [Coinbase::Wallet::Data] the Wallet data to import
@@ -37,13 +48,18 @@ module Coinbase
37
48
 
38
49
  # Creates a new Wallet on the specified Network and generate a default address for it.
39
50
  # @param network_id [String] (Optional) the ID of the blockchain network. Defaults to 'base-sepolia'.
51
+ # @param interval_seconds [Integer] The interval at which to poll the CDPService for the Wallet to
52
+ # have an active seed, if using a ServerSigner, in seconds
53
+ # @param timeout_seconds [Integer] The maximum amount of time to wait for the ServerSigner to
54
+ # create a seed for the Wallet, in seconds
40
55
  # @return [Coinbase::Wallet] the new Wallet
41
- def create(network_id: 'base-sepolia')
56
+ def create(network_id: 'base-sepolia', interval_seconds: 0.2, timeout_seconds: 20)
42
57
  model = Coinbase.call_api do
43
58
  wallets_api.create_wallet(
44
59
  create_wallet_request: {
45
60
  wallet: {
46
- network_id: network_id
61
+ network_id: network_id,
62
+ use_server_signer: Coinbase.use_server_signer?
47
63
  }
48
64
  }
49
65
  )
@@ -51,13 +67,42 @@ module Coinbase
51
67
 
52
68
  wallet = new(model)
53
69
 
54
- wallet.create_address
70
+ # When used with a ServerSigner, the Signer must first register
71
+ # with the Wallet before addresses can be created.
72
+ wait_for_signer(wallet.id, interval_seconds, timeout_seconds) if Coinbase.use_server_signer?
55
73
 
74
+ wallet.create_address
56
75
  wallet
57
76
  end
58
77
 
59
78
  private
60
79
 
80
+ # Wait_for_signer waits until the ServerSigner has created a seed for the Wallet.
81
+ # Timeout::Error if the ServerSigner takes longer than the given timeout to create the seed.
82
+ # @param wallet_id [string] The ID of the Wallet that is awaiting seed creation.
83
+ # @param interval_seconds [Integer] The interval at which to poll the CDPService, in seconds
84
+ # @param timeout_seconds [Integer] The maximum amount of time to wait for the Signer to create a seed, in seconds
85
+ # @return [Wallet] The completed Wallet object that is ready to create addresses.
86
+ def wait_for_signer(wallet_id, interval_seconds, timeout_seconds)
87
+ start_time = Time.now
88
+
89
+ loop do
90
+ model = Coinbase.call_api do
91
+ wallets_api.get_wallet(wallet_id)
92
+ end
93
+
94
+ return self if model.server_signer_status == ServerSignerStatus::ACTIVE
95
+
96
+ if Time.now - start_time > timeout_seconds
97
+ raise Timeout::Error, 'Wallet creation timed out. Check status of your Server-Signer'
98
+ end
99
+
100
+ self.sleep interval_seconds
101
+ end
102
+
103
+ self
104
+ end
105
+
61
106
  # TODO: Memoize these objects in a thread-safe way at the top-level.
62
107
  def addresses_api
63
108
  Coinbase::Client::AddressesApi.new(Coinbase.configuration.api_client)
@@ -78,12 +123,15 @@ module Coinbase
78
123
  # with the Wallet. If not provided, the Wallet will derive the first default address.
79
124
  # @param client [Jimson::Client] (Optional) The JSON RPC client to use for interacting with the Network
80
125
  def initialize(model, seed: nil, address_models: [])
81
- validate_seed_and_address_models(seed, address_models)
126
+ validate_seed_and_address_models(seed, address_models) unless Coinbase.use_server_signer?
82
127
 
83
128
  @model = model
84
- @master = master_node(seed)
85
129
  @addresses = []
86
- @private_key_index = 0
130
+
131
+ unless Coinbase.use_server_signer?
132
+ @master = master_node(seed)
133
+ @private_key_index = 0
134
+ end
87
135
 
88
136
  derive_addresses(address_models)
89
137
  end
@@ -100,6 +148,12 @@ module Coinbase
100
148
  Coinbase.to_sym(@model.network_id)
101
149
  end
102
150
 
151
+ # Returns the ServerSigner Status of the Wallet.
152
+ # @return [Symbol] The ServerSigner Status
153
+ def server_signer_status
154
+ Coinbase.to_sym(@model.server_signer_status)
155
+ end
156
+
103
157
  # Sets the seed of the Wallet. This seed is used to derive keys and sign transactions.
104
158
  # @param seed [String] The seed to set. Expects a 32-byte hexadecimal with no 0x prefix.
105
159
  def seed=(seed)
@@ -121,16 +175,19 @@ module Coinbase
121
175
  # Creates a new Address in the Wallet.
122
176
  # @return [Address] The new Address
123
177
  def create_address
124
- key = derive_key
125
- attestation = create_attestation(key)
126
- public_key = key.public_key.compressed.unpack1('H*')
178
+ opts = { create_address_request: {} }
127
179
 
128
- opts = {
129
- create_address_request: {
130
- public_key: public_key,
131
- attestation: attestation
180
+ unless Coinbase.use_server_signer?
181
+ key = derive_key
182
+
183
+ opts = {
184
+ create_address_request: {
185
+ public_key: key.public_key.compressed.unpack1('H*'),
186
+ attestation: create_attestation(key)
187
+ }
132
188
  }
133
- }
189
+ end
190
+
134
191
  address_model = Coinbase.call_api do
135
192
  addresses_api.create_address(id, opts)
136
193
  end
@@ -177,30 +234,34 @@ module Coinbase
177
234
  Coinbase::Balance.from_model_and_asset_id(response, asset_id).amount
178
235
  end
179
236
 
180
- # Transfers the given amount of the given Asset to the given address. Only same-Network Transfers are supported.
181
- # Currently only the default_address is used to source the Transfer.
237
+ # Transfers the given amount of the given Asset to the specified address or wallet.
238
+ # Only same-network Transfers are supported. Currently only the default_address is used to source the Transfer.
182
239
  # @param amount [Integer, Float, BigDecimal] The amount of the Asset to send
183
240
  # @param asset_id [Symbol] The ID of the Asset to send
184
241
  # @param destination [Wallet | Address | String] The destination of the transfer. If a Wallet, sends to the Wallet's
185
242
  # default address. If a String, interprets it as the address ID.
186
- # @return [Transfer] The hash of the Transfer transaction.
243
+ # @return [Coinbase::Transfer] The Transfer object.
187
244
  def transfer(amount, asset_id, destination)
188
- if destination.is_a?(Wallet)
189
- raise ArgumentError, 'Transfer must be on the same Network' if destination.network_id != network_id
190
-
191
- destination = destination.default_address.id
192
- elsif destination.is_a?(Address)
193
- raise ArgumentError, 'Transfer must be on the same Network' if destination.network_id != network_id
194
-
195
- destination = destination.id
196
- end
197
-
198
245
  default_address.transfer(amount, asset_id, destination)
199
246
  end
200
247
 
248
+ # Trades the given amount of the given Asset for another Asset.
249
+ # Currently only the default_address is used to source the Trade
250
+ # @param amount [Integer, Float, BigDecimal] The amount of the Asset to send.
251
+ # @param from_asset_id [Symbol] The ID of the Asset to trade from. For Ether, :eth, :gwei, and :wei are supported.
252
+ # @param to_asset_id [Symbol] The ID of the Asset to trade to. For Ether, :eth, :gwei, and :wei are supported.
253
+ # default address. If a String, interprets it as the address ID.
254
+ # @return [Coinbase::Trade] The Trade object.
255
+ def trade(amount, from_asset_id, to_asset_id)
256
+ default_address.trade(amount, from_asset_id, to_asset_id)
257
+ end
258
+
201
259
  # Exports the Wallet's data to a Data object.
202
260
  # @return [Data] The Wallet data
203
261
  def export
262
+ # TODO: Improve this check by relying on the backend data to decide whether a wallet is server-signer backed.
263
+ raise 'Cannot export data for Server-Signer backed Wallet' if Coinbase.use_server_signer?
264
+
204
265
  raise 'Cannot export Wallet without loaded seed' if @master.nil?
205
266
 
206
267
  Data.new(wallet_id: id, seed: @master.seed_hex)
@@ -223,6 +284,87 @@ module Coinbase
223
284
  !@master.nil?
224
285
  end
225
286
 
287
+ # Saves the seed of the Wallet to the given file. Wallets whose seeds are saved this way can be
288
+ # rehydrated using load_seed. A single file can be used for multiple Wallet seeds.
289
+ # This is an insecure method of storing Wallet seeds and should only be used for development purposes.
290
+ #
291
+ # @param file_path [String] The path of the file to save the seed to
292
+ # @param encrypt [bool] (Optional) Whether the seed information persisted to the local file system should be
293
+ # encrypted or not. Data is unencrypted by default.
294
+ # @return [String] A string indicating the success of the operation
295
+ def save_seed!(file_path, encrypt: false)
296
+ raise 'Wallet does not have seed loaded' if @master.nil?
297
+
298
+ existing_seeds_in_store = existing_seeds(file_path)
299
+
300
+ seed_to_store = @master.seed_hex
301
+ auth_tag = ''
302
+ iv = ''
303
+ if encrypt
304
+ cipher = OpenSSL::Cipher.new('aes-256-gcm').encrypt
305
+ cipher.key = OpenSSL::Digest.digest('SHA256', encryption_key)
306
+ iv = cipher.random_iv
307
+ cipher.iv = iv
308
+ cipher.auth_data = ''
309
+ encrypted_data = cipher.update(@master.seed_hex) + cipher.final
310
+ auth_tag = cipher.auth_tag.unpack1('H*')
311
+ iv = iv.unpack1('H*')
312
+ seed_to_store = encrypted_data.unpack1('H*')
313
+ end
314
+
315
+ existing_seeds_in_store[id] = {
316
+ seed: seed_to_store,
317
+ encrypted: encrypt,
318
+ auth_tag: auth_tag,
319
+ iv: iv
320
+ }
321
+
322
+ File.open(file_path, 'w') do |file|
323
+ file.write(JSON.pretty_generate(existing_seeds_in_store))
324
+ end
325
+
326
+ "Successfully saved seed for wallet #{id} to #{file_path}."
327
+ end
328
+
329
+ # Loads the seed of the Wallet from the given file.
330
+ # @param file_path [String] The path of the file to load the seed from
331
+ # @return [String] A string indicating the success of the operation
332
+ def load_seed(file_path)
333
+ raise 'Wallet already has seed loaded' unless @master.nil?
334
+
335
+ existing_seeds_in_store = existing_seeds(file_path)
336
+
337
+ raise ArgumentError, "File #{file_path} does not contain seed data" if existing_seeds_in_store == {}
338
+
339
+ if existing_seeds_in_store[id].nil?
340
+ raise ArgumentError, "File #{file_path} does not contain seed data for wallet #{id}"
341
+ end
342
+
343
+ seed_data = existing_seeds_in_store[id]
344
+ local_seed = seed_data['seed']
345
+
346
+ raise ArgumentError, 'Seed data is malformed' if local_seed.nil? || local_seed == ''
347
+
348
+ if seed_data['encrypted']
349
+ raise ArgumentError, 'Encrypted seed data is malformed' if seed_data['iv'] == '' ||
350
+ seed_data['auth_tag'] == ''
351
+
352
+ cipher = OpenSSL::Cipher.new('aes-256-gcm').decrypt
353
+ cipher.key = OpenSSL::Digest.digest('SHA256', encryption_key)
354
+ iv = [seed_data['iv']].pack('H*')
355
+ cipher.iv = iv
356
+ auth_tag = [seed_data['auth_tag']].pack('H*')
357
+ cipher.auth_tag = auth_tag
358
+ cipher.auth_data = ''
359
+ hex_decoded_data = [seed_data['seed']].pack('H*')
360
+ local_seed = cipher.update(hex_decoded_data) + cipher.final
361
+ end
362
+
363
+ self.seed = local_seed
364
+
365
+ "Successfully loaded seed for wallet #{id} from #{file_path}."
366
+ end
367
+
226
368
  # Returns a String representation of the Wallet.
227
369
  # @return [String] a String representation of the Wallet
228
370
  def to_s
@@ -390,6 +532,25 @@ module Coinbase
390
532
  raise ArgumentError, 'Seed must be empty if address_models are not provided'
391
533
  end
392
534
 
535
+ # Loads the Hash of Wallet seeds from the given file.
536
+ # @param file_path [String] The path of the file to load the seed from
537
+ # @return [Hash<String, Hash>] The Hash of from Wallet IDs to seed data
538
+ def existing_seeds(file_path)
539
+ existing_seed_data = '{}'
540
+ existing_seed_data = File.read(file_path) if File.exist?(file_path)
541
+ existing_seeds = JSON.parse(existing_seed_data)
542
+ raise ArgumentError, "#{file_path} is malformed, must be a valid JSON object" unless existing_seeds.is_a?(Hash)
543
+
544
+ existing_seeds
545
+ end
546
+
547
+ # Returns the shared secret to use for encrypting the seed.
548
+ def encryption_key
549
+ pk = OpenSSL::PKey.read(Coinbase.configuration.api_key_private_key)
550
+ public_key = pk.public_key # use own public key to generate the shared secret.
551
+ pk.dh_compute_key(public_key)
552
+ end
553
+
393
554
  def addresses_api
394
555
  @addresses_api ||= Coinbase::Client::AddressesApi.new(Coinbase.configuration.api_client)
395
556
  end
data/lib/coinbase.rb CHANGED
@@ -11,9 +11,12 @@ require_relative 'coinbase/errors'
11
11
  require_relative 'coinbase/faucet_transaction'
12
12
  require_relative 'coinbase/middleware'
13
13
  require_relative 'coinbase/network'
14
+ require_relative 'coinbase/trade'
14
15
  require_relative 'coinbase/transfer'
16
+ require_relative 'coinbase/transaction'
15
17
  require_relative 'coinbase/user'
16
18
  require_relative 'coinbase/wallet'
19
+ require_relative 'coinbase/server_signer'
17
20
  require 'json'
18
21
 
19
22
  # The Coinbase SDK.
@@ -27,27 +30,33 @@ module Coinbase
27
30
  end
28
31
 
29
32
  # Configures the Coinbase SDK.
33
+ # @return [String] A string indicating successful configuration
30
34
  def self.configure
31
35
  yield(configuration)
32
36
 
33
37
  raise InvalidConfiguration, 'API key private key is not set' unless configuration.api_key_private_key
34
38
  raise InvalidConfiguration, 'API key name is not set' unless configuration.api_key_name
39
+
40
+ 'Successfully configured Coinbase SDK'
35
41
  end
36
42
 
37
43
  # Configures the Coinbase SDK from the given CDP API Key JSON file.
38
44
  # @param file_path [String] (Optional) the path to the CDP API Key JSON file
39
45
  # file in the root directory by default.
40
- def self.configure_from_json(file_path = 'coinbase_cloud_api_key.json')
46
+ # @return [String] A string indicating successful configuration
47
+ def self.configure_from_json(file_path = 'cdp_api_key.json')
41
48
  configuration.from_json(file_path)
42
49
 
43
50
  raise InvalidConfiguration, 'API key private key is not set' unless configuration.api_key_private_key
44
51
  raise InvalidConfiguration, 'API key name is not set' unless configuration.api_key_name
52
+
53
+ 'Successfully configured Coinbase SDK'
45
54
  end
46
55
 
47
56
  # Configuration object for the Coinbase SDK.
48
57
  class Configuration
49
58
  attr_reader :base_sepolia_rpc_url, :base_sepolia_client
50
- attr_accessor :api_url, :api_key_name, :api_key_private_key, :debug_api, :backup_file_path
59
+ attr_accessor :api_url, :api_key_name, :api_key_private_key, :debug_api, :use_server_signer
51
60
 
52
61
  # Initializes the configuration object.
53
62
  def initialize
@@ -55,13 +64,13 @@ module Coinbase
55
64
  @base_sepolia_client = Jimson::Client.new(@base_sepolia_rpc_url)
56
65
  @api_url = 'https://api.cdp.coinbase.com'
57
66
  @debug_api = false
58
- @backup_file_path = 'seeds.json'
67
+ @use_server_signer = false
59
68
  end
60
69
 
61
70
  # Sets configuration values based on the provided CDP API Key JSON file.
62
71
  # @param file_path [String] (Optional) the path to the CDP API Key JSON file
63
72
  # file in the root directory by default.
64
- def from_json(file_path = 'coinbase_cloud_api_key.json')
73
+ def from_json(file_path = 'cdp_api_key.json')
65
74
  # Expand paths to respect shortcuts like ~.
66
75
  file_path = File.expand_path(file_path)
67
76
 
@@ -117,4 +126,10 @@ module Coinbase
117
126
  rescue StandardError => e
118
127
  raise e
119
128
  end
129
+
130
+ # Returns whether to use a server signer to manage private keys.
131
+ # @return [bool] whether to use a server signer to manage private keys.
132
+ def self.use_server_signer?
133
+ Coinbase.configuration.use_server_signer
134
+ end
120
135
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: coinbase-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yuga Cohler
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-05-20 00:00:00.000000000 Z
11
+ date: 2024-06-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bigdecimal
@@ -192,6 +192,20 @@ dependencies:
192
192
  - - '='
193
193
  - !ruby/object:Gem::Version
194
194
  version: 1.63.1
195
+ - !ruby/object:Gem::Dependency
196
+ name: simplecov
197
+ requirement: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - ">="
200
+ - !ruby/object:Gem::Version
201
+ version: '0'
202
+ type: :development
203
+ prerelease: false
204
+ version_requirements: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - ">="
207
+ - !ruby/object:Gem::Version
208
+ version: '0'
195
209
  - !ruby/object:Gem::Dependency
196
210
  name: yard
197
211
  requirement: !ruby/object:Gem::Requirement
@@ -234,6 +248,9 @@ files:
234
248
  - lib/coinbase/balance_map.rb
235
249
  - lib/coinbase/client.rb
236
250
  - lib/coinbase/client/api/addresses_api.rb
251
+ - lib/coinbase/client/api/server_signers_api.rb
252
+ - lib/coinbase/client/api/stake_api.rb
253
+ - lib/coinbase/client/api/trades_api.rb
237
254
  - lib/coinbase/client/api/transfers_api.rb
238
255
  - lib/coinbase/client/api/users_api.rb
239
256
  - lib/coinbase/client/api/wallets_api.rb
@@ -245,12 +262,33 @@ files:
245
262
  - lib/coinbase/client/models/address_list.rb
246
263
  - lib/coinbase/client/models/asset.rb
247
264
  - lib/coinbase/client/models/balance.rb
265
+ - lib/coinbase/client/models/broadcast_trade_request.rb
248
266
  - lib/coinbase/client/models/broadcast_transfer_request.rb
267
+ - lib/coinbase/client/models/build_staking_operation_request.rb
249
268
  - lib/coinbase/client/models/create_address_request.rb
269
+ - lib/coinbase/client/models/create_server_signer_request.rb
270
+ - lib/coinbase/client/models/create_trade_request.rb
250
271
  - lib/coinbase/client/models/create_transfer_request.rb
251
272
  - lib/coinbase/client/models/create_wallet_request.rb
273
+ - lib/coinbase/client/models/create_wallet_request_wallet.rb
252
274
  - lib/coinbase/client/models/error.rb
253
275
  - lib/coinbase/client/models/faucet_transaction.rb
276
+ - lib/coinbase/client/models/feature.rb
277
+ - lib/coinbase/client/models/request_faucet_funds200_response.rb
278
+ - lib/coinbase/client/models/seed_creation_event.rb
279
+ - lib/coinbase/client/models/seed_creation_event_result.rb
280
+ - lib/coinbase/client/models/server_signer.rb
281
+ - lib/coinbase/client/models/server_signer_event.rb
282
+ - lib/coinbase/client/models/server_signer_event_event.rb
283
+ - lib/coinbase/client/models/server_signer_event_list.rb
284
+ - lib/coinbase/client/models/server_signer_list.rb
285
+ - lib/coinbase/client/models/signature_creation_event.rb
286
+ - lib/coinbase/client/models/signature_creation_event_result.rb
287
+ - lib/coinbase/client/models/staking_operation.rb
288
+ - lib/coinbase/client/models/trade.rb
289
+ - lib/coinbase/client/models/trade_list.rb
290
+ - lib/coinbase/client/models/transaction.rb
291
+ - lib/coinbase/client/models/transaction_type.rb
254
292
  - lib/coinbase/client/models/transfer.rb
255
293
  - lib/coinbase/client/models/transfer_list.rb
256
294
  - lib/coinbase/client/models/user.rb
@@ -262,6 +300,9 @@ files:
262
300
  - lib/coinbase/faucet_transaction.rb
263
301
  - lib/coinbase/middleware.rb
264
302
  - lib/coinbase/network.rb
303
+ - lib/coinbase/server_signer.rb
304
+ - lib/coinbase/trade.rb
305
+ - lib/coinbase/transaction.rb
265
306
  - lib/coinbase/transfer.rb
266
307
  - lib/coinbase/user.rb
267
308
  - lib/coinbase/wallet.rb