coinbase-sdk 0.0.3 → 0.0.4

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cac6b46a83009db9f165f0a2c4396122a2bf4bfa5bf895867b135695c346465e
4
- data.tar.gz: 0b8cfea979b389b9890a09104b8c7533e334873a789b19d7f704789cdcf6a70d
3
+ metadata.gz: d4413913708fadc44dcbb49a00a72fe55382187c8084531b9cec43894e0ee9a0
4
+ data.tar.gz: e47f6295ce5f8bc1d8888b49ba71cdbc1558d606e708e66452f0ae6a76127249
5
5
  SHA512:
6
- metadata.gz: bccd3af15fec48789603988eadf3c67ad4ec67e5b3081fd2f06c7877d6ac35c6d2eda16db533ff149cf2f9f38d59ba38527284a0205529c84da6ac781dad8e3a
7
- data.tar.gz: 072d5372f38da2b9a3eb97a024f4a289ac7ef1906df8cf1da22de0b37c77e18b9a724db7771019fc9c6eb3834720f48010edb869f310dcc114429cb0e0bd1403
6
+ metadata.gz: acb6233add651f82063b7f2a73da8b7a8112687603d61fb77f3160713d813ea07447e25b5b69e83dd81c1852478c1b9999c1b207c9137ae08868db495721181b
7
+ data.tar.gz: 3b72b12e92386e7114e0146f257032b904a4f26a2a97369bff19c1bc722b195372c830a2bb405e1a2f2655c81608beeee8d601deab293f87c1adf5fb18ca64e9
@@ -35,45 +35,32 @@ module Coinbase
35
35
 
36
36
  # Returns the Address ID.
37
37
  # @return [String] The Address ID
38
- def address_id
38
+ def id
39
39
  @model.address_id
40
40
  end
41
41
 
42
42
  # Returns the balances of the Address.
43
43
  # @return [BalanceMap] The balances of the Address, keyed by asset ID. Ether balances are denominated
44
44
  # in ETH.
45
- def list_balances
45
+ def balances
46
46
  response = Coinbase.call_api do
47
- addresses_api.list_address_balances(wallet_id, address_id)
47
+ addresses_api.list_address_balances(wallet_id, id)
48
48
  end
49
49
 
50
- Coinbase.to_balance_map(response)
50
+ Coinbase::BalanceMap.from_balances(response.data)
51
51
  end
52
52
 
53
53
  # Returns the balance of the provided Asset.
54
54
  # @param asset_id [Symbol] The Asset to retrieve the balance for
55
55
  # @return [BigDecimal] The balance of the Asset
56
- def get_balance(asset_id)
57
- normalized_asset_id = normalize_asset_id(asset_id)
58
-
56
+ def balance(asset_id)
59
57
  response = Coinbase.call_api do
60
- addresses_api.get_address_balance(wallet_id, address_id, normalized_asset_id.to_s)
58
+ addresses_api.get_address_balance(wallet_id, id, Coinbase::Asset.primary_denomination(asset_id).to_s)
61
59
  end
62
60
 
63
61
  return BigDecimal('0') if response.nil?
64
62
 
65
- amount = BigDecimal(response.amount)
66
-
67
- case asset_id
68
- when :eth
69
- amount / BigDecimal(Coinbase::WEI_PER_ETHER.to_s)
70
- when :gwei
71
- amount / BigDecimal(Coinbase::GWEI_PER_ETHER.to_s)
72
- when :usdc
73
- amount / BigDecimal(Coinbase::ATOMIC_UNITS_PER_USDC.to_s)
74
- else
75
- amount
76
- end
63
+ Coinbase::Balance.from_model_and_asset_id(response, asset_id).amount
77
64
  end
78
65
 
79
66
  # Transfers the given amount of the given Asset to the given address. Only same-Network Transfers are supported.
@@ -83,36 +70,32 @@ module Coinbase
83
70
  # default address. If a String, interprets it as the address ID.
84
71
  # @return [String] The hash of the Transfer transaction.
85
72
  def transfer(amount, asset_id, destination)
86
- raise ArgumentError, "Unsupported asset: #{asset_id}" unless Coinbase::SUPPORTED_ASSET_IDS[asset_id]
73
+ raise ArgumentError, "Unsupported asset: #{asset_id}" unless Coinbase::Asset.supported?(asset_id)
87
74
 
88
75
  if destination.is_a?(Wallet)
89
76
  raise ArgumentError, 'Transfer must be on the same Network' if destination.network_id != network_id
90
77
 
91
- destination = destination.default_address.address_id
78
+ destination = destination.default_address.id
92
79
  elsif destination.is_a?(Address)
93
80
  raise ArgumentError, 'Transfer must be on the same Network' if destination.network_id != network_id
94
81
 
95
- destination = destination.address_id
82
+ destination = destination.id
96
83
  end
97
84
 
98
- current_balance = get_balance(asset_id)
85
+ current_balance = balance(asset_id)
99
86
  if current_balance < amount
100
87
  raise ArgumentError, "Insufficient funds: #{amount} requested, but only #{current_balance} available"
101
88
  end
102
89
 
103
- normalized_amount = normalize_asset_amount(amount, asset_id)
104
-
105
- normalized_asset_id = normalize_asset_id(asset_id)
106
-
107
90
  create_transfer_request = {
108
- amount: normalized_amount.to_i.to_s,
91
+ amount: Coinbase::Asset.to_atomic_amount(amount, asset_id).to_i.to_s,
109
92
  network_id: network_id,
110
- asset_id: normalized_asset_id.to_s,
93
+ asset_id: Coinbase::Asset.primary_denomination(asset_id).to_s,
111
94
  destination: destination
112
95
  }
113
96
 
114
97
  transfer_model = Coinbase.call_api do
115
- transfers_api.create_transfer(wallet_id, address_id, create_transfer_request)
98
+ transfers_api.create_transfer(wallet_id, id, create_transfer_request)
116
99
  end
117
100
 
118
101
  transfer = Coinbase::Transfer.new(transfer_model)
@@ -127,7 +110,7 @@ module Coinbase
127
110
  }
128
111
 
129
112
  transfer_model = Coinbase.call_api do
130
- transfers_api.broadcast_transfer(wallet_id, address_id, transfer.transfer_id, broadcast_transfer_request)
113
+ transfers_api.broadcast_transfer(wallet_id, id, transfer.id, broadcast_transfer_request)
131
114
  end
132
115
 
133
116
  Coinbase::Transfer.new(transfer_model)
@@ -136,7 +119,7 @@ module Coinbase
136
119
  # Returns a String representation of the Address.
137
120
  # @return [String] a String representation of the Address
138
121
  def to_s
139
- "Coinbase::Address{address_id: '#{address_id}', network_id: '#{network_id}', wallet_id: '#{wallet_id}'}"
122
+ "Coinbase::Address{id: '#{id}', network_id: '#{network_id}', wallet_id: '#{wallet_id}'}"
140
123
  end
141
124
 
142
125
  # Same as to_s.
@@ -148,11 +131,11 @@ module Coinbase
148
131
  # Requests funds for the address from the faucet and returns the faucet transaction.
149
132
  # This is only supported on testnet networks.
150
133
  # @return [Coinbase::FaucetTransaction] The successful faucet transaction
151
- # @raise [Coinbase::FaucetLimitReached] If the faucet limit has been reached for the address or user.
134
+ # @raise [Coinbase::FaucetLimitReachedError] If the faucet limit has been reached for the address or user.
152
135
  # @raise [Coinbase::Client::ApiError] If an unexpected error occurs while requesting faucet funds.
153
136
  def faucet
154
137
  Coinbase.call_api do
155
- Coinbase::FaucetTransaction.new(addresses_api.request_faucet_funds(wallet_id, address_id))
138
+ Coinbase::FaucetTransaction.new(addresses_api.request_faucet_funds(wallet_id, id))
156
139
  end
157
140
  end
158
141
 
@@ -162,61 +145,30 @@ module Coinbase
162
145
  @key.private_hex
163
146
  end
164
147
 
165
- # Lists the IDs of all Transfers associated with the given Wallet and Address.
166
- # @return [Array<String>] The IDs of all Transfers belonging to the Wallet and Address
167
- def list_transfer_ids
168
- transfer_ids = []
148
+ # Returns all of the transfers associated with the address.
149
+ # @return [Array<Coinbase::Transfer>] The transfers associated with the address
150
+ def transfers
151
+ transfers = []
169
152
  page = nil
170
153
 
171
154
  loop do
155
+ puts "fetch transfers page: #{page}"
172
156
  response = Coinbase.call_api do
173
- transfers_api.list_transfers(wallet_id, address_id, { limit: 100, page: page })
157
+ transfers_api.list_transfers(wallet_id, id, { limit: 100, page: page })
174
158
  end
175
159
 
176
- transfer_ids.concat(response.data.map(&:transfer_id)) if response.data
160
+ transfers.concat(response.data.map { |transfer| Coinbase::Transfer.new(transfer) }) if response.data
177
161
 
178
162
  break unless response.has_more
179
163
 
180
164
  page = response.next_page
181
165
  end
182
166
 
183
- transfer_ids
167
+ transfers
184
168
  end
185
169
 
186
170
  private
187
171
 
188
- # Normalizes the amount of the Asset to send to the atomic unit.
189
- # @param amount [Integer, Float, BigDecimal] The amount to normalize
190
- # @param asset_id [Symbol] The ID of the Asset being transferred
191
- # @return [BigDecimal] The normalized amount in atomic units
192
- def normalize_asset_amount(amount, asset_id)
193
- big_amount = BigDecimal(amount.to_s)
194
-
195
- case asset_id
196
- when :eth
197
- big_amount * Coinbase::WEI_PER_ETHER
198
- when :gwei
199
- big_amount * Coinbase::WEI_PER_GWEI
200
- when :usdc
201
- big_amount * Coinbase::ATOMIC_UNITS_PER_USDC
202
- when :weth
203
- big_amount * Coinbase::WEI_PER_ETHER
204
- else
205
- big_amount
206
- end
207
- end
208
-
209
- # Normalizes the asset ID to use during requests.
210
- # @param asset_id [Symbol] The asset ID to normalize
211
- # @return [Symbol] The normalized asset ID
212
- def normalize_asset_id(asset_id)
213
- if %i[wei gwei].include?(asset_id)
214
- :eth
215
- else
216
- asset_id
217
- end
218
- end
219
-
220
172
  def addresses_api
221
173
  @addresses_api ||= Coinbase::Client::AddressesApi.new(Coinbase.configuration.api_client)
222
174
  end
@@ -3,7 +3,63 @@
3
3
  module Coinbase
4
4
  # A representation of an Asset.
5
5
  class Asset
6
- attr_reader :network_id, :asset_id, :display_name, :address_id
6
+ # Retuns whether the provided asset ID is supported.
7
+ # @param asset_id [Symbol] The Asset ID
8
+ # @return [Boolean] Whether the Asset ID is supported
9
+ def self.supported?(asset_id)
10
+ !!Coinbase::SUPPORTED_ASSET_IDS[asset_id]
11
+ end
12
+
13
+ # Converts the amount of the Asset to the atomic units of the primary denomination of the Asset.
14
+ # @param amount [Integer, Float, BigDecimal] The amount to normalize
15
+ # @param asset_id [Symbol] The ID of the Asset being transferred
16
+ # @return [BigDecimal] The normalized amount in atomic units
17
+ def self.to_atomic_amount(amount, asset_id)
18
+ case asset_id
19
+ when :eth
20
+ amount * BigDecimal(Coinbase::WEI_PER_ETHER.to_s)
21
+ when :gwei
22
+ amount * BigDecimal(Coinbase::WEI_PER_GWEI.to_s)
23
+ when :usdc
24
+ amount * BigDecimal(Coinbase::ATOMIC_UNITS_PER_USDC.to_s)
25
+ when :weth
26
+ amount * BigDecimal(Coinbase::WEI_PER_ETHER)
27
+ else
28
+ amount
29
+ end
30
+ end
31
+
32
+ # Converts an amount from the atomic value of the primary denomination of the provided Asset ID
33
+ # to whole units of the specified asset ID.
34
+ # @param atomic_amount [BigDecimal] The amount in atomic units
35
+ # @param asset_id [Symbol] The Asset ID
36
+ # @return [BigDecimal] The amount in whole units of the specified asset ID
37
+ def self.from_atomic_amount(atomic_amount, asset_id)
38
+ case asset_id
39
+ when :eth
40
+ atomic_amount / BigDecimal(Coinbase::WEI_PER_ETHER.to_s)
41
+ when :gwei
42
+ atomic_amount / BigDecimal(Coinbase::WEI_PER_GWEI.to_s)
43
+ when :usdc
44
+ atomic_amount / BigDecimal(Coinbase::ATOMIC_UNITS_PER_USDC.to_s)
45
+ when :weth
46
+ atomic_amount / BigDecimal(Coinbase::WEI_PER_ETHER)
47
+ else
48
+ atomic_amount
49
+ end
50
+ end
51
+
52
+ # Returns the primary denomination for the provided Asset ID.
53
+ # For assets with multiple denominations, e.g. eth can also be denominated in wei and gwei,
54
+ # this method will return the primary denomination.
55
+ # e.g. eth.
56
+ # @param asset_id [Symbol] The Asset ID
57
+ # @return [Symbol] The primary denomination for the Asset ID
58
+ def self.primary_denomination(asset_id)
59
+ return :eth if %i[wei gwei].include?(asset_id)
60
+
61
+ asset_id
62
+ end
7
63
 
8
64
  # Returns a new Asset object. Do not use this method. Instead, use the Asset constants defined in
9
65
  # the Coinbase module.
@@ -17,5 +73,20 @@ module Coinbase
17
73
  @display_name = display_name
18
74
  @address_id = address_id
19
75
  end
76
+
77
+ attr_reader :network_id, :asset_id, :display_name, :address_id
78
+
79
+ # Returns a string representation of the Asset.
80
+ # @return [String] a string representation of the Asset
81
+ def to_s
82
+ "Coinbase::Asset{network_id: '#{network_id}', asset_id: '#{asset_id}', display_name: '#{display_name}'" +
83
+ (address_id.nil? ? '}' : ", address_id: '#{address_id}'}")
84
+ end
85
+
86
+ # Same as to_s.
87
+ # @return [String] a string representation of the Balance
88
+ def inspect
89
+ to_s
90
+ end
20
91
  end
21
92
  end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coinbase
4
+ # A representation of an Balance.
5
+ class Balance
6
+ # Converts a Coinbase::Client::Balance model to a Coinbase::Balance
7
+ # @param balance_model [Coinbase::Client::Balance] The balance fetched from the API.
8
+ # @return [Balance] The converted Balance object.
9
+ def self.from_model(balance_model)
10
+ asset_id = Coinbase.to_sym(balance_model.asset.asset_id.downcase)
11
+
12
+ from_model_and_asset_id(balance_model, asset_id)
13
+ end
14
+
15
+ # Converts a Coinbase::Client::Balance model and asset ID to a Coinbase::Balance
16
+ # This can be used to specify a non-primary denomination that we want the balance
17
+ # to be converted to.
18
+ # @param balance_model [Coinbase::Client::Balance] The balance fetched from the API.
19
+ # @param asset_id [Symbol] The Asset ID of the denomination we want returned.
20
+ # @return [Balance] The converted Balance object.
21
+ def self.from_model_and_asset_id(balance_model, asset_id)
22
+ new(
23
+ amount: Coinbase::Asset.from_atomic_amount(BigDecimal(balance_model.amount), asset_id),
24
+ asset_id: asset_id
25
+ )
26
+ end
27
+
28
+ # Returns a new Asset object. Do not use this method. Instead, use the Asset constants defined in
29
+ # the Coinbase module.
30
+ # @param network_id [Symbol] The ID of the Network to which the Asset belongs
31
+ # @param asset_id [Symbol] The Asset ID
32
+ # @param display_name [String] The Asset's display name
33
+ # @param address_id [String] (Optional) The Asset's address ID, if one exists
34
+ def initialize(amount:, asset_id:)
35
+ @amount = amount
36
+ @asset_id = asset_id
37
+ end
38
+
39
+ attr_reader :amount, :asset_id
40
+
41
+ # Returns a string representation of the Balance.
42
+ # @return [String] a string representation of the Balance
43
+ def to_s
44
+ "Coinbase::Balance{amount: '#{amount.to_i}', asset_id: '#{asset_id}'}"
45
+ end
46
+
47
+ # Same as to_s.
48
+ # @return [String] a string representation of the Balance
49
+ def inspect
50
+ to_s
51
+ end
52
+ end
53
+ end
@@ -5,15 +5,27 @@ require 'bigdecimal'
5
5
  module Coinbase
6
6
  # A convenience class for printing out Asset balances in a human-readable format.
7
7
  class BalanceMap < Hash
8
- # Returns a new BalanceMap object.
9
- # @param hash [Map<Symbol, BigDecimal>] The hash to initialize with
10
- def initialize(hash = {})
11
- super()
12
- hash.each do |key, value|
13
- self[key] = value
8
+ # Converts a list of Coinbase::Client::Balance models to a Coinbase::BalanceMap.
9
+ # @param balances [Array<Coinbase::Client::Balance>] The list of balances fetched from the API.
10
+ # @return [BalanceMap] The converted BalanceMap object.
11
+ def self.from_balances(balances)
12
+ BalanceMap.new.tap do |balance_map|
13
+ balances.each do |balance_model|
14
+ balance = Coinbase::Balance.from_model(balance_model)
15
+
16
+ balance_map.add(balance)
17
+ end
14
18
  end
15
19
  end
16
20
 
21
+ # Adds a balance to the map.
22
+ # @param balance [Coinbase::Balance] The balance to add to the map.
23
+ def add(balance)
24
+ raise ArgumentError, 'balance must be a Coinbase::Balance' unless balance.is_a?(Coinbase::Balance)
25
+
26
+ self[balance.asset_id] = balance.amount
27
+ end
28
+
17
29
  # Returns a string representation of the balance map.
18
30
  # @return [String] The string representation of the balance
19
31
  def to_s
@@ -37,7 +37,7 @@ module Coinbase
37
37
 
38
38
  # Returns the Transfer ID.
39
39
  # @return [String] The Transfer ID
40
- def transfer_id
40
+ def id
41
41
  @model.transfer_id
42
42
  end
43
43
 
@@ -179,7 +179,7 @@ module Coinbase
179
179
  # Returns a String representation of the Transfer.
180
180
  # @return [String] a String representation of the Transfer
181
181
  def to_s
182
- "Coinbase::Transfer{transfer_id: '#{transfer_id}', network_id: '#{network_id}', " \
182
+ "Coinbase::Transfer{transfer_id: '#{id}', network_id: '#{network_id}', " \
183
183
  "from_address_id: '#{from_address_id}', destination_address_id: '#{destination_address_id}', " \
184
184
  "asset_id: '#{asset_id}', amount: '#{amount}', transaction_hash: '#{transaction_hash}', " \
185
185
  "transaction_link: '#{transaction_link}', status: '#{status}'}"
data/lib/coinbase/user.rb CHANGED
@@ -15,7 +15,7 @@ module Coinbase
15
15
 
16
16
  # Returns the User ID.
17
17
  # @return [String] the User ID
18
- def user_id
18
+ def id
19
19
  @model.id
20
20
  end
21
21
 
@@ -41,20 +41,12 @@ module Coinbase
41
41
  # @param data [Coinbase::Wallet::Data] the Wallet data to import
42
42
  # @return [Coinbase::Wallet] the imported Wallet
43
43
  def import_wallet(data)
44
- model = Coinbase.call_api do
45
- wallets_api.get_wallet(data.wallet_id)
46
- end
47
-
48
- address_count = Coinbase.call_api do
49
- addresses_api.list_addresses(model.id).total_count
50
- end
51
-
52
- Wallet.new(model, seed: data.seed, address_count: address_count)
44
+ Wallet.import(data)
53
45
  end
54
46
 
55
47
  # Lists the IDs of the Wallets belonging to the User.
56
48
  # @return [Array<String>] the IDs of the Wallets belonging to the User
57
- def list_wallet_ids
49
+ def wallet_ids
58
50
  wallets = Coinbase.call_api do
59
51
  wallets_api.list_wallets
60
52
  end
@@ -62,10 +54,10 @@ module Coinbase
62
54
  wallets.data.map(&:id)
63
55
  end
64
56
 
65
- # Saves a wallet to local file system. Wallet saved this way can be re-instantiated with `load_wallets` function,
66
- # provided the backup_file is available. This is an insecure method of storing wallet seeds and should only be used
67
- # for development purposes. If you call save_wallet twice with wallets containing the same wallet_id, the backup
68
- # will be overwritten during the second attempt.
57
+ # Saves a wallet to local file system. Wallet saved this way can be re-instantiated with load_wallets_from_local
58
+ # function, provided the backup_file is available. This is an insecure method of storing wallet seeds and should
59
+ # only be used for development purposes. If you call save_wallet_locally! twice with wallets containing the same
60
+ # wallet_id, the backup will be overwritten during the second attempt.
69
61
  # The default backup_file is `seeds.json` in the root folder. It can be configured by changing
70
62
  # Coinbase.configuration.backup_file_path.
71
63
  #
@@ -73,7 +65,7 @@ module Coinbase
73
65
  # @param encrypt [bool] (Optional) Boolean representing whether the backup persisted to local file system should be
74
66
  # encrypted or not. Data is unencrypted by default.
75
67
  # @return [Coinbase::Wallet] the saved wallet.
76
- def save_wallet(wallet, encrypt: false)
68
+ def save_wallet_locally!(wallet, encrypt: false)
77
69
  existing_seeds_in_store = existing_seeds
78
70
  data = wallet.export
79
71
  seed_to_store = data.seed
@@ -107,7 +99,7 @@ module Coinbase
107
99
 
108
100
  # Loads all wallets belonging to the User with backup persisted to the local file system.
109
101
  # @return [Map<String>Coinbase::Wallet] the map of wallet_ids to the wallets.
110
- def load_wallets
102
+ def load_wallets_from_local
111
103
  existing_seeds_in_store = existing_seeds
112
104
  raise ArgumentError, 'Backup file not found' if existing_seeds_in_store == {}
113
105
 
@@ -141,7 +133,7 @@ module Coinbase
141
133
  # Returns a string representation of the User.
142
134
  # @return [String] a string representation of the User
143
135
  def to_s
144
- "Coinbase::User{user_id: '#{user_id}'}"
136
+ "Coinbase::User{user_id: '#{id}'}"
145
137
  end
146
138
 
147
139
  # Same as to_s.
@@ -12,6 +12,39 @@ module Coinbase
12
12
  # list their balances, and transfer Assets to other Addresses. Wallets should be created through User#create_wallet or
13
13
  # User#import_wallet.
14
14
  class Wallet
15
+ attr_reader :addresses
16
+
17
+ class << self
18
+ # Imports a Wallet from previously exported wallet data.
19
+ # @param data [Coinbase::Wallet::Data] the Wallet data to import
20
+ # @return [Coinbase::Wallet] the imported Wallet
21
+ def import(data)
22
+ raise ArgumentError, 'data must be a Coinbase::Wallet::Data object' unless data.is_a?(Data)
23
+
24
+ model = Coinbase.call_api do
25
+ wallets_api.get_wallet(data.wallet_id)
26
+ end
27
+
28
+ # TODO: Pass these addresses in directly
29
+ address_count = Coinbase.call_api do
30
+ addresses_api.list_addresses(model.id).total_count
31
+ end
32
+
33
+ new(model, seed: data.seed, address_count: address_count)
34
+ end
35
+
36
+ private
37
+
38
+ # TODO: Memoize these objects in a thread-safe way at the top-level.
39
+ def addresses_api
40
+ Coinbase::Client::AddressesApi.new(Coinbase.configuration.api_client)
41
+ end
42
+
43
+ def wallets_api
44
+ Coinbase::Client::WalletsApi.new(Coinbase.configuration.api_client)
45
+ end
46
+ end
47
+
15
48
  # Returns a new Wallet object. Do not use this method directly. Instead, use User#create_wallet or
16
49
  # User#import_wallet.
17
50
  # @param model [Coinbase::Client::Wallet] The underlying Wallet object
@@ -45,7 +78,7 @@ module Coinbase
45
78
 
46
79
  # Returns the Wallet ID.
47
80
  # @return [String] The Wallet ID
48
- def wallet_id
81
+ def id
49
82
  @model.id
50
83
  end
51
84
 
@@ -69,7 +102,7 @@ module Coinbase
69
102
  }
70
103
  }
71
104
  address_model = Coinbase.call_api do
72
- addresses_api.create_address(wallet_id, opts)
105
+ addresses_api.create_address(id, opts)
73
106
  end
74
107
 
75
108
  cache_address(address_model, key)
@@ -78,60 +111,37 @@ module Coinbase
78
111
  # Returns the default address of the Wallet.
79
112
  # @return [Address] The default address
80
113
  def default_address
81
- @addresses.find { |address| address.address_id == @model.default_address.address_id }
114
+ address(@model.default_address.address_id)
82
115
  end
83
116
 
84
117
  # Returns the Address with the given ID.
85
118
  # @param address_id [String] The ID of the Address to retrieve
86
119
  # @return [Address] The Address
87
- def get_address(address_id)
88
- @addresses.find { |address| address.address_id == address_id }
89
- end
90
-
91
- # Returns the list of Addresses in the Wallet.
92
- # @return [Array<Address>] The list of Addresses
93
- def list_addresses
94
- @addresses
120
+ def address(address_id)
121
+ @addresses.find { |address| address.id == address_id }
95
122
  end
96
123
 
97
124
  # Returns the list of balances of this Wallet. Balances are aggregated across all Addresses in the Wallet.
98
125
  # @return [BalanceMap] The list of balances. The key is the Asset ID, and the value is the balance.
99
- def list_balances
126
+ def balances
100
127
  response = Coinbase.call_api do
101
- wallets_api.list_wallet_balances(wallet_id)
128
+ wallets_api.list_wallet_balances(id)
102
129
  end
103
130
 
104
- Coinbase.to_balance_map(response)
131
+ Coinbase::BalanceMap.from_balances(response.data)
105
132
  end
106
133
 
107
134
  # Returns the balance of the provided Asset. Balances are aggregated across all Addresses in the Wallet.
108
135
  # @param asset_id [Symbol] The ID of the Asset to retrieve the balance for
109
136
  # @return [BigDecimal] The balance of the Asset
110
- def get_balance(asset_id)
111
- normalized_asset_id = if %i[wei gwei].include?(asset_id)
112
- :eth
113
- else
114
- asset_id
115
- end
116
-
137
+ def balance(asset_id)
117
138
  response = Coinbase.call_api do
118
- wallets_api.get_wallet_balance(wallet_id, normalized_asset_id.to_s)
139
+ wallets_api.get_wallet_balance(id, Coinbase::Asset.primary_denomination(asset_id).to_s)
119
140
  end
120
141
 
121
142
  return BigDecimal('0') if response.nil?
122
143
 
123
- amount = BigDecimal(response.amount)
124
-
125
- case asset_id
126
- when :eth
127
- amount / BigDecimal(Coinbase::WEI_PER_ETHER.to_s)
128
- when :gwei
129
- amount / BigDecimal(Coinbase::GWEI_PER_ETHER.to_s)
130
- when :usdc
131
- amount / BigDecimal(Coinbase::ATOMIC_UNITS_PER_USDC.to_s)
132
- else
133
- amount
134
- end
144
+ Coinbase::Balance.from_model_and_asset_id(response, asset_id).amount
135
145
  end
136
146
 
137
147
  # Transfers the given amount of the given Asset to the given address. Only same-Network Transfers are supported.
@@ -145,11 +155,11 @@ module Coinbase
145
155
  if destination.is_a?(Wallet)
146
156
  raise ArgumentError, 'Transfer must be on the same Network' if destination.network_id != @network_id
147
157
 
148
- destination = destination.default_address.address_id
158
+ destination = destination.default_address.id
149
159
  elsif destination.is_a?(Address)
150
160
  raise ArgumentError, 'Transfer must be on the same Network' if destination.network_id != @network_id
151
161
 
152
- destination = destination.address_id
162
+ destination = destination.id
153
163
  end
154
164
 
155
165
  default_address.transfer(amount, asset_id, destination)
@@ -158,14 +168,25 @@ module Coinbase
158
168
  # Exports the Wallet's data to a Data object.
159
169
  # @return [Data] The Wallet data
160
170
  def export
161
- Data.new(wallet_id: wallet_id, seed: @master.seed_hex)
171
+ Data.new(wallet_id: id, seed: @master.seed_hex)
172
+ end
173
+
174
+ # Requests funds from the faucet for the Wallet's default address and returns the faucet transaction.
175
+ # This is only supported on testnet networks.
176
+ # @return [Coinbase::FaucetTransaction] The successful faucet transaction
177
+ # @raise [Coinbase::FaucetLimitReachedError] If the faucet limit has been reached for the address or user.
178
+ # @raise [Coinbase::Client::ApiError] If an unexpected error occurs while requesting faucet funds.
179
+ def faucet
180
+ Coinbase.call_api do
181
+ Coinbase::FaucetTransaction.new(addresses_api.request_faucet_funds(id, default_address.id))
182
+ end
162
183
  end
163
184
 
164
185
  # Returns a String representation of the Wallet.
165
186
  # @return [String] a String representation of the Wallet
166
187
  def to_s
167
- "Coinbase::Wallet{wallet_id: '#{wallet_id}', network_id: '#{network_id}', " \
168
- "default_address: '#{default_address.address_id}'}"
188
+ "Coinbase::Wallet{wallet_id: '#{id}', network_id: '#{network_id}', " \
189
+ "default_address: '#{default_address.id}'}"
169
190
  end
170
191
 
171
192
  # Same as to_s.
@@ -209,7 +230,7 @@ module Coinbase
209
230
 
210
231
  address_id = key.address.to_s
211
232
  address_model = Coinbase.call_api do
212
- addresses_api.get_address(wallet_id, address_id)
233
+ addresses_api.get_address(id, address_id)
213
234
  end
214
235
 
215
236
  cache_address(address_model, key)
@@ -240,7 +261,7 @@ module Coinbase
240
261
  def create_attestation(key)
241
262
  public_key = key.public_key.compressed.unpack1('H*')
242
263
  payload = {
243
- wallet_id: wallet_id,
264
+ wallet_id: id,
244
265
  public_key: public_key
245
266
  }.to_json
246
267
  hashed_payload = Digest::SHA256.digest(payload)
@@ -261,7 +282,7 @@ module Coinbase
261
282
  # Updates the Wallet model with the latest data.
262
283
  def update_model
263
284
  @model = Coinbase.call_api do
264
- wallets_api.get_wallet(wallet_id)
285
+ wallets_api.get_wallet(id)
265
286
  end
266
287
  end
267
288
 
data/lib/coinbase.rb CHANGED
@@ -3,6 +3,7 @@
3
3
  require_relative 'coinbase/address'
4
4
  require_relative 'coinbase/asset'
5
5
  require_relative 'coinbase/authenticator'
6
+ require_relative 'coinbase/balance'
6
7
  require_relative 'coinbase/balance_map'
7
8
  require_relative 'coinbase/client'
8
9
  require_relative 'coinbase/constants'
@@ -18,7 +19,6 @@ require 'json'
18
19
  # The Coinbase SDK.
19
20
  module Coinbase
20
21
  class InvalidConfiguration < StandardError; end
21
- class FaucetLimitReached < StandardError; end
22
22
 
23
23
  # Returns the configuration object.
24
24
  # @return [Configuration] the configuration object
@@ -100,30 +100,6 @@ module Coinbase
100
100
  value.to_s.gsub('-', '_').to_sym
101
101
  end
102
102
 
103
- # Converts a Coinbase::Client::AddressBalanceList to a BalanceMap.
104
- # @param address_balance_list [Coinbase::Client::AddressBalanceList] The AddressBalanceList to convert
105
- # @return [BalanceMap] The converted BalanceMap
106
- def self.to_balance_map(address_balance_list)
107
- balances = {}
108
-
109
- address_balance_list.data.each do |balance|
110
- asset_id = Coinbase.to_sym(balance.asset.asset_id.downcase)
111
- amount = case asset_id
112
- when :eth
113
- BigDecimal(balance.amount) / BigDecimal(Coinbase::WEI_PER_ETHER)
114
- when :usdc
115
- BigDecimal(balance.amount) / BigDecimal(Coinbase::ATOMIC_UNITS_PER_USDC)
116
- when :weth
117
- BigDecimal(balance.amount) / BigDecimal(Coinbase::WEI_PER_ETHER)
118
- else
119
- BigDecimal(balance.amount)
120
- end
121
- balances[asset_id] = amount
122
- end
123
-
124
- BalanceMap.new(balances)
125
- end
126
-
127
103
  # Loads the default user.
128
104
  # @return [Coinbase::User] the default user
129
105
  def self.load_default_user
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.3
4
+ version: 0.0.4
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-07 00:00:00.000000000 Z
11
+ date: 2024-05-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: eth
@@ -216,6 +216,7 @@ files:
216
216
  - lib/coinbase/address.rb
217
217
  - lib/coinbase/asset.rb
218
218
  - lib/coinbase/authenticator.rb
219
+ - lib/coinbase/balance.rb
219
220
  - lib/coinbase/balance_map.rb
220
221
  - lib/coinbase/client.rb
221
222
  - lib/coinbase/client/api/addresses_api.rb