coinbase-sdk 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
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