coinbase-sdk 0.0.3 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/coinbase/address.rb +45 -75
- data/lib/coinbase/asset.rb +72 -1
- data/lib/coinbase/balance.rb +51 -0
- data/lib/coinbase/balance_map.rb +22 -10
- data/lib/coinbase/middleware.rb +4 -1
- data/lib/coinbase/transfer.rb +2 -2
- data/lib/coinbase/user.rb +40 -34
- data/lib/coinbase/wallet.rb +199 -74
- data/lib/coinbase.rb +1 -25
- metadata +17 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 98cd32134ee8acb14c9dc018f39e7af188646b546998c4182cd50d7ae75f2816
|
4
|
+
data.tar.gz: df6ff19c63798ec10f054972aa75edef79fe65ae39c93cbe0941c77db251e5d6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a209d25aa72fc185fb667a5ef7b8de617341dba449b0a02b15ad95bc0c434140932353e12258f4665b35ef60e37b5346efca76db811cc5a308cfc69b907f37b8
|
7
|
+
data.tar.gz: 8856f048ea3ecb664559665e2422d60b6c12d607526aea4bea75f8e8273cf0584b2206e14dcb4e99bdca3436114b03961558be36029b40614d018028f9d41183
|
data/lib/coinbase/address.rb
CHANGED
@@ -15,7 +15,7 @@ module Coinbase
|
|
15
15
|
# Returns a new Address object. Do not use this method directly. Instead, use Wallet#create_address, or use
|
16
16
|
# the Wallet's default_address.
|
17
17
|
# @param model [Coinbase::Client::Address] The underlying Address object
|
18
|
-
# @param key [Eth::Key] The key backing the Address
|
18
|
+
# @param key [Eth::Key] The key backing the Address. Can be nil.
|
19
19
|
def initialize(model, key)
|
20
20
|
@model = model
|
21
21
|
@key = key
|
@@ -35,45 +35,40 @@ module Coinbase
|
|
35
35
|
|
36
36
|
# Returns the Address ID.
|
37
37
|
# @return [String] The Address ID
|
38
|
-
def
|
38
|
+
def id
|
39
39
|
@model.address_id
|
40
40
|
end
|
41
41
|
|
42
|
+
# Sets the private key backing the Address. This key is used to sign transactions.
|
43
|
+
# @param key [Eth::Key] The key backing the Address
|
44
|
+
def key=(key)
|
45
|
+
raise 'Private key is already set' unless @key.nil?
|
46
|
+
|
47
|
+
@key = key
|
48
|
+
end
|
49
|
+
|
42
50
|
# Returns the balances of the Address.
|
43
51
|
# @return [BalanceMap] The balances of the Address, keyed by asset ID. Ether balances are denominated
|
44
52
|
# in ETH.
|
45
|
-
def
|
53
|
+
def balances
|
46
54
|
response = Coinbase.call_api do
|
47
|
-
addresses_api.list_address_balances(wallet_id,
|
55
|
+
addresses_api.list_address_balances(wallet_id, id)
|
48
56
|
end
|
49
57
|
|
50
|
-
Coinbase.
|
58
|
+
Coinbase::BalanceMap.from_balances(response.data)
|
51
59
|
end
|
52
60
|
|
53
61
|
# Returns the balance of the provided Asset.
|
54
62
|
# @param asset_id [Symbol] The Asset to retrieve the balance for
|
55
63
|
# @return [BigDecimal] The balance of the Asset
|
56
|
-
def
|
57
|
-
normalized_asset_id = normalize_asset_id(asset_id)
|
58
|
-
|
64
|
+
def balance(asset_id)
|
59
65
|
response = Coinbase.call_api do
|
60
|
-
addresses_api.get_address_balance(wallet_id,
|
66
|
+
addresses_api.get_address_balance(wallet_id, id, Coinbase::Asset.primary_denomination(asset_id).to_s)
|
61
67
|
end
|
62
68
|
|
63
69
|
return BigDecimal('0') if response.nil?
|
64
70
|
|
65
|
-
|
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
|
71
|
+
Coinbase::Balance.from_model_and_asset_id(response, asset_id).amount
|
77
72
|
end
|
78
73
|
|
79
74
|
# Transfers the given amount of the given Asset to the given address. Only same-Network Transfers are supported.
|
@@ -83,36 +78,34 @@ module Coinbase
|
|
83
78
|
# default address. If a String, interprets it as the address ID.
|
84
79
|
# @return [String] The hash of the Transfer transaction.
|
85
80
|
def transfer(amount, asset_id, destination)
|
86
|
-
raise
|
81
|
+
raise 'Cannot transfer from address without private key loaded' if @key.nil?
|
82
|
+
|
83
|
+
raise ArgumentError, "Unsupported asset: #{asset_id}" unless Coinbase::Asset.supported?(asset_id)
|
87
84
|
|
88
85
|
if destination.is_a?(Wallet)
|
89
86
|
raise ArgumentError, 'Transfer must be on the same Network' if destination.network_id != network_id
|
90
87
|
|
91
|
-
destination = destination.default_address.
|
88
|
+
destination = destination.default_address.id
|
92
89
|
elsif destination.is_a?(Address)
|
93
90
|
raise ArgumentError, 'Transfer must be on the same Network' if destination.network_id != network_id
|
94
91
|
|
95
|
-
destination = destination.
|
92
|
+
destination = destination.id
|
96
93
|
end
|
97
94
|
|
98
|
-
current_balance =
|
95
|
+
current_balance = balance(asset_id)
|
99
96
|
if current_balance < amount
|
100
97
|
raise ArgumentError, "Insufficient funds: #{amount} requested, but only #{current_balance} available"
|
101
98
|
end
|
102
99
|
|
103
|
-
normalized_amount = normalize_asset_amount(amount, asset_id)
|
104
|
-
|
105
|
-
normalized_asset_id = normalize_asset_id(asset_id)
|
106
|
-
|
107
100
|
create_transfer_request = {
|
108
|
-
amount:
|
101
|
+
amount: Coinbase::Asset.to_atomic_amount(amount, asset_id).to_i.to_s,
|
109
102
|
network_id: network_id,
|
110
|
-
asset_id:
|
103
|
+
asset_id: Coinbase::Asset.primary_denomination(asset_id).to_s,
|
111
104
|
destination: destination
|
112
105
|
}
|
113
106
|
|
114
107
|
transfer_model = Coinbase.call_api do
|
115
|
-
transfers_api.create_transfer(wallet_id,
|
108
|
+
transfers_api.create_transfer(wallet_id, id, create_transfer_request)
|
116
109
|
end
|
117
110
|
|
118
111
|
transfer = Coinbase::Transfer.new(transfer_model)
|
@@ -127,16 +120,22 @@ module Coinbase
|
|
127
120
|
}
|
128
121
|
|
129
122
|
transfer_model = Coinbase.call_api do
|
130
|
-
transfers_api.broadcast_transfer(wallet_id,
|
123
|
+
transfers_api.broadcast_transfer(wallet_id, id, transfer.id, broadcast_transfer_request)
|
131
124
|
end
|
132
125
|
|
133
126
|
Coinbase::Transfer.new(transfer_model)
|
134
127
|
end
|
135
128
|
|
129
|
+
# Returns whether the Address has a private key backing it to sign transactions.
|
130
|
+
# @return [Boolean] Whether the Address has a private key backing it to sign transactions.
|
131
|
+
def can_sign?
|
132
|
+
!@key.nil?
|
133
|
+
end
|
134
|
+
|
136
135
|
# Returns a String representation of the Address.
|
137
136
|
# @return [String] a String representation of the Address
|
138
137
|
def to_s
|
139
|
-
"Coinbase::Address{
|
138
|
+
"Coinbase::Address{id: '#{id}', network_id: '#{network_id}', wallet_id: '#{wallet_id}'}"
|
140
139
|
end
|
141
140
|
|
142
141
|
# Same as to_s.
|
@@ -148,75 +147,46 @@ module Coinbase
|
|
148
147
|
# Requests funds for the address from the faucet and returns the faucet transaction.
|
149
148
|
# This is only supported on testnet networks.
|
150
149
|
# @return [Coinbase::FaucetTransaction] The successful faucet transaction
|
151
|
-
# @raise [Coinbase::
|
150
|
+
# @raise [Coinbase::FaucetLimitReachedError] If the faucet limit has been reached for the address or user.
|
152
151
|
# @raise [Coinbase::Client::ApiError] If an unexpected error occurs while requesting faucet funds.
|
153
152
|
def faucet
|
154
153
|
Coinbase.call_api do
|
155
|
-
Coinbase::FaucetTransaction.new(addresses_api.request_faucet_funds(wallet_id,
|
154
|
+
Coinbase::FaucetTransaction.new(addresses_api.request_faucet_funds(wallet_id, id))
|
156
155
|
end
|
157
156
|
end
|
158
157
|
|
159
158
|
# Exports the Address's private key to a hex string.
|
160
159
|
# @return [String] The Address's private key as a hex String
|
161
160
|
def export
|
161
|
+
raise 'Cannot export key without private key loaded' if @key.nil?
|
162
|
+
|
162
163
|
@key.private_hex
|
163
164
|
end
|
164
165
|
|
165
|
-
#
|
166
|
-
# @return [Array<
|
167
|
-
def
|
168
|
-
|
166
|
+
# Returns all of the transfers associated with the address.
|
167
|
+
# @return [Array<Coinbase::Transfer>] The transfers associated with the address
|
168
|
+
def transfers
|
169
|
+
transfers = []
|
169
170
|
page = nil
|
170
171
|
|
171
172
|
loop do
|
173
|
+
puts "fetch transfers page: #{page}"
|
172
174
|
response = Coinbase.call_api do
|
173
|
-
transfers_api.list_transfers(wallet_id,
|
175
|
+
transfers_api.list_transfers(wallet_id, id, { limit: 100, page: page })
|
174
176
|
end
|
175
177
|
|
176
|
-
|
178
|
+
transfers.concat(response.data.map { |transfer| Coinbase::Transfer.new(transfer) }) if response.data
|
177
179
|
|
178
180
|
break unless response.has_more
|
179
181
|
|
180
182
|
page = response.next_page
|
181
183
|
end
|
182
184
|
|
183
|
-
|
185
|
+
transfers
|
184
186
|
end
|
185
187
|
|
186
188
|
private
|
187
189
|
|
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
190
|
def addresses_api
|
221
191
|
@addresses_api ||= Coinbase::Client::AddressesApi.new(Coinbase.configuration.api_client)
|
222
192
|
end
|
data/lib/coinbase/asset.rb
CHANGED
@@ -3,7 +3,63 @@
|
|
3
3
|
module Coinbase
|
4
4
|
# A representation of an Asset.
|
5
5
|
class Asset
|
6
|
-
|
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,51 @@
|
|
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 Balance object. Do not use this method. Instead, use Balance.from_model or
|
29
|
+
# Balance.from_model_and_asset_id.
|
30
|
+
# @param amount [BigDecimal] The amount of the Asset
|
31
|
+
# @param asset_id [Symbol] The Asset ID
|
32
|
+
def initialize(amount:, asset_id:)
|
33
|
+
@amount = amount
|
34
|
+
@asset_id = asset_id
|
35
|
+
end
|
36
|
+
|
37
|
+
attr_reader :amount, :asset_id
|
38
|
+
|
39
|
+
# Returns a string representation of the Balance.
|
40
|
+
# @return [String] a string representation of the Balance
|
41
|
+
def to_s
|
42
|
+
"Coinbase::Balance{amount: '#{amount.to_i}', asset_id: '#{asset_id}'}"
|
43
|
+
end
|
44
|
+
|
45
|
+
# Same as to_s.
|
46
|
+
# @return [String] a string representation of the Balance
|
47
|
+
def inspect
|
48
|
+
to_s
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/coinbase/balance_map.rb
CHANGED
@@ -5,31 +5,43 @@ 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
|
-
#
|
9
|
-
# @param
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
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
|
-
# @return [String] The string representation of the balance
|
30
|
+
# @return [String] The string representation of the balance map
|
19
31
|
def to_s
|
20
32
|
to_string
|
21
33
|
end
|
22
34
|
|
23
35
|
# Returns a string representation of the balance map.
|
24
|
-
# @return [String] The string representation of the balance
|
36
|
+
# @return [String] The string representation of the balance map
|
25
37
|
def inspect
|
26
38
|
to_string
|
27
39
|
end
|
28
40
|
|
29
41
|
private
|
30
42
|
|
31
|
-
# Returns a string representation of the balance.
|
32
|
-
# @return [String] The string representation of the balance
|
43
|
+
# Returns a string representation of the balance map.
|
44
|
+
# @return [String] The string representation of the balance map
|
33
45
|
def to_string
|
34
46
|
result = {}
|
35
47
|
|
data/lib/coinbase/middleware.rb
CHANGED
@@ -12,8 +12,11 @@ module Coinbase
|
|
12
12
|
# Returns the default middleware configuration for the Coinbase SDK.
|
13
13
|
def self.config
|
14
14
|
Coinbase::Client::Configuration.default.tap do |config|
|
15
|
+
uri = URI(Coinbase.configuration.api_url)
|
16
|
+
|
15
17
|
config.debugging = Coinbase.configuration.debug_api
|
16
|
-
config.host =
|
18
|
+
config.host = uri.host + (uri.port ? ":#{uri.port}" : '')
|
19
|
+
config.scheme = uri.scheme if uri.scheme
|
17
20
|
config.request(:authenticator)
|
18
21
|
end
|
19
22
|
end
|
data/lib/coinbase/transfer.rb
CHANGED
@@ -37,7 +37,7 @@ module Coinbase
|
|
37
37
|
|
38
38
|
# Returns the Transfer ID.
|
39
39
|
# @return [String] The Transfer ID
|
40
|
-
def
|
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: '#{
|
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,57 +15,63 @@ module Coinbase
|
|
15
15
|
|
16
16
|
# Returns the User ID.
|
17
17
|
# @return [String] the User ID
|
18
|
-
def
|
18
|
+
def id
|
19
19
|
@model.id
|
20
20
|
end
|
21
21
|
|
22
22
|
# Creates a new Wallet belonging to the User.
|
23
|
+
# @param network_id [String] (Optional) the ID of the blockchain network. Defaults to 'base-sepolia'.
|
23
24
|
# @return [Coinbase::Wallet] the new Wallet
|
24
|
-
def create_wallet
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
network_id: 'base-sepolia'
|
29
|
-
}
|
30
|
-
}
|
31
|
-
opts = { create_wallet_request: create_wallet_request }
|
32
|
-
|
33
|
-
model = Coinbase.call_api do
|
34
|
-
wallets_api.create_wallet(opts)
|
35
|
-
end
|
25
|
+
def create_wallet(create_wallet_options = {})
|
26
|
+
# For ruby 2.7 compatibility we cannot pass in keyword args when the create wallet
|
27
|
+
# options is empty
|
28
|
+
return Wallet.create if create_wallet_options.empty?
|
36
29
|
|
37
|
-
Wallet.
|
30
|
+
Wallet.create(**create_wallet_options)
|
38
31
|
end
|
39
32
|
|
40
33
|
# Imports a Wallet belonging to the User.
|
41
34
|
# @param data [Coinbase::Wallet::Data] the Wallet data to import
|
42
35
|
# @return [Coinbase::Wallet] the imported Wallet
|
43
36
|
def import_wallet(data)
|
44
|
-
|
45
|
-
|
46
|
-
|
37
|
+
Wallet.import(data)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Lists the Wallets belonging to the User.
|
41
|
+
# @param page_size [Integer] (Optional) the number of Wallets to return per page. Defaults to 10
|
42
|
+
# @param next_page_token [String] (Optional) the token for the next page of Wallets
|
43
|
+
# @return [Coinbase::Wallet] the Wallets belonging to the User
|
44
|
+
def wallets(page_size: 10, next_page_token: nil)
|
45
|
+
opts = {
|
46
|
+
limit: page_size
|
47
|
+
}
|
48
|
+
|
49
|
+
opts[:page] = next_page_token unless next_page_token.nil?
|
47
50
|
|
48
|
-
|
49
|
-
|
51
|
+
wallet_list = Coinbase.call_api do
|
52
|
+
wallets_api.list_wallets(opts)
|
50
53
|
end
|
51
54
|
|
52
|
-
|
53
|
-
|
55
|
+
# A map from wallet_id to address models.
|
56
|
+
address_model_map = {}
|
54
57
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
58
|
+
wallet_list.data.each do |wallet_model|
|
59
|
+
addresses_list = Coinbase.call_api do
|
60
|
+
addresses_api.list_addresses(wallet_model.id, { limit: Coinbase::Wallet::MAX_ADDRESSES })
|
61
|
+
end
|
62
|
+
|
63
|
+
address_model_map[wallet_model.id] = addresses_list.data
|
60
64
|
end
|
61
65
|
|
62
|
-
|
66
|
+
wallet_list.data.map do |wallet_model|
|
67
|
+
Wallet.new(wallet_model, seed: '', address_models: address_model_map[wallet_model.id])
|
68
|
+
end
|
63
69
|
end
|
64
70
|
|
65
|
-
# Saves a wallet to local file system. Wallet saved this way can be re-instantiated with
|
66
|
-
# provided the backup_file is available. This is an insecure method of storing wallet seeds and should
|
67
|
-
# for development purposes. If you call
|
68
|
-
# will be overwritten during the second attempt.
|
71
|
+
# Saves a wallet to local file system. Wallet saved this way can be re-instantiated with load_wallets_from_local
|
72
|
+
# function, provided the backup_file is available. This is an insecure method of storing wallet seeds and should
|
73
|
+
# only be used for development purposes. If you call save_wallet_locally! twice with wallets containing the same
|
74
|
+
# wallet_id, the backup will be overwritten during the second attempt.
|
69
75
|
# The default backup_file is `seeds.json` in the root folder. It can be configured by changing
|
70
76
|
# Coinbase.configuration.backup_file_path.
|
71
77
|
#
|
@@ -73,7 +79,7 @@ module Coinbase
|
|
73
79
|
# @param encrypt [bool] (Optional) Boolean representing whether the backup persisted to local file system should be
|
74
80
|
# encrypted or not. Data is unencrypted by default.
|
75
81
|
# @return [Coinbase::Wallet] the saved wallet.
|
76
|
-
def
|
82
|
+
def save_wallet_locally!(wallet, encrypt: false)
|
77
83
|
existing_seeds_in_store = existing_seeds
|
78
84
|
data = wallet.export
|
79
85
|
seed_to_store = data.seed
|
@@ -107,7 +113,7 @@ module Coinbase
|
|
107
113
|
|
108
114
|
# Loads all wallets belonging to the User with backup persisted to the local file system.
|
109
115
|
# @return [Map<String>Coinbase::Wallet] the map of wallet_ids to the wallets.
|
110
|
-
def
|
116
|
+
def load_wallets_from_local
|
111
117
|
existing_seeds_in_store = existing_seeds
|
112
118
|
raise ArgumentError, 'Backup file not found' if existing_seeds_in_store == {}
|
113
119
|
|
@@ -141,7 +147,7 @@ module Coinbase
|
|
141
147
|
# Returns a string representation of the User.
|
142
148
|
# @return [String] a string representation of the User
|
143
149
|
def to_s
|
144
|
-
"Coinbase::User{user_id: '#{
|
150
|
+
"Coinbase::User{user_id: '#{id}'}"
|
145
151
|
end
|
146
152
|
|
147
153
|
# Same as to_s.
|
data/lib/coinbase/wallet.rb
CHANGED
@@ -12,40 +12,85 @@ 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, :model
|
16
|
+
|
17
|
+
# The maximum number of addresses in a Wallet.
|
18
|
+
MAX_ADDRESSES = 20
|
19
|
+
|
20
|
+
class << self
|
21
|
+
# Imports a Wallet from previously exported wallet data.
|
22
|
+
# @param data [Coinbase::Wallet::Data] the Wallet data to import
|
23
|
+
# @return [Coinbase::Wallet] the imported Wallet
|
24
|
+
def import(data)
|
25
|
+
raise ArgumentError, 'data must be a Coinbase::Wallet::Data object' unless data.is_a?(Data)
|
26
|
+
|
27
|
+
model = Coinbase.call_api do
|
28
|
+
wallets_api.get_wallet(data.wallet_id)
|
29
|
+
end
|
30
|
+
|
31
|
+
address_list = Coinbase.call_api do
|
32
|
+
addresses_api.list_addresses(model.id, { limit: MAX_ADDRESSES })
|
33
|
+
end
|
34
|
+
|
35
|
+
new(model, seed: data.seed, address_models: address_list.data)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Creates a new Wallet on the specified Network and generate a default address for it.
|
39
|
+
# @param network_id [String] (Optional) the ID of the blockchain network. Defaults to 'base-sepolia'.
|
40
|
+
# @return [Coinbase::Wallet] the new Wallet
|
41
|
+
def create(network_id: 'base-sepolia')
|
42
|
+
model = Coinbase.call_api do
|
43
|
+
wallets_api.create_wallet(
|
44
|
+
create_wallet_request: {
|
45
|
+
wallet: {
|
46
|
+
network_id: network_id
|
47
|
+
}
|
48
|
+
}
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
wallet = new(model)
|
53
|
+
|
54
|
+
wallet.create_address
|
55
|
+
|
56
|
+
wallet
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
# TODO: Memoize these objects in a thread-safe way at the top-level.
|
62
|
+
def addresses_api
|
63
|
+
Coinbase::Client::AddressesApi.new(Coinbase.configuration.api_client)
|
64
|
+
end
|
65
|
+
|
66
|
+
def wallets_api
|
67
|
+
Coinbase::Client::WalletsApi.new(Coinbase.configuration.api_client)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
15
71
|
# Returns a new Wallet object. Do not use this method directly. Instead, use User#create_wallet or
|
16
72
|
# User#import_wallet.
|
17
73
|
# @param model [Coinbase::Client::Wallet] The underlying Wallet object
|
18
74
|
# @param seed [String] (Optional) The seed to use for the Wallet. Expects a 32-byte hexadecimal with no 0x prefix.
|
19
|
-
# If
|
20
|
-
#
|
75
|
+
# If nil, a new seed will be generated. If the empty string, no seed is generated, and the Wallet will be
|
76
|
+
# instantiated without a seed and its corresponding private keys.
|
77
|
+
# @param address_models [Array<Coinbase::Client::Address>] (Optional) The models of the addresses already registered
|
78
|
+
# with the Wallet. If not provided, the Wallet will derive the first default address.
|
21
79
|
# @param client [Jimson::Client] (Optional) The JSON RPC client to use for interacting with the Network
|
22
|
-
def initialize(model, seed: nil,
|
23
|
-
|
80
|
+
def initialize(model, seed: nil, address_models: [])
|
81
|
+
validate_seed_and_address_models(seed, address_models)
|
24
82
|
|
25
83
|
@model = model
|
26
|
-
|
27
|
-
@master = seed.nil? ? MoneyTree::Master.new : MoneyTree::Master.new(seed_hex: seed)
|
28
|
-
|
29
|
-
# TODO: Make Network an argument to the constructor.
|
30
|
-
@network_id = :base_sepolia
|
84
|
+
@master = master_node(seed)
|
31
85
|
@addresses = []
|
86
|
+
@private_key_index = 0
|
32
87
|
|
33
|
-
|
34
|
-
@address_path_prefix = "m/44'/60'/0'/0"
|
35
|
-
@address_index = 0
|
36
|
-
|
37
|
-
if address_count.positive?
|
38
|
-
address_count.times { derive_address }
|
39
|
-
else
|
40
|
-
create_address
|
41
|
-
# Update the model to reflect the new default address.
|
42
|
-
update_model
|
43
|
-
end
|
88
|
+
derive_addresses(address_models)
|
44
89
|
end
|
45
90
|
|
46
91
|
# Returns the Wallet ID.
|
47
92
|
# @return [String] The Wallet ID
|
48
|
-
def
|
93
|
+
def id
|
49
94
|
@model.id
|
50
95
|
end
|
51
96
|
|
@@ -55,6 +100,24 @@ module Coinbase
|
|
55
100
|
Coinbase.to_sym(@model.network_id)
|
56
101
|
end
|
57
102
|
|
103
|
+
# Sets the seed of the Wallet. This seed is used to derive keys and sign transactions.
|
104
|
+
# @param seed [String] The seed to set. Expects a 32-byte hexadecimal with no 0x prefix.
|
105
|
+
def seed=(seed)
|
106
|
+
raise ArgumentError, 'Seed must be 32 bytes' if seed.length != 64
|
107
|
+
raise 'Seed is already set' unless @master.nil?
|
108
|
+
raise 'Cannot set seed for Wallet with non-zero private key index' if @private_key_index.positive?
|
109
|
+
|
110
|
+
@master = MoneyTree::Master.new(seed_hex: seed)
|
111
|
+
|
112
|
+
@addresses.each do
|
113
|
+
key = derive_key
|
114
|
+
a = address(key.address.to_s)
|
115
|
+
raise "Seed does not match wallet; cannot find address #{key.address}" if a.nil?
|
116
|
+
|
117
|
+
a.key = key
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
58
121
|
# Creates a new Address in the Wallet.
|
59
122
|
# @return [Address] The new Address
|
60
123
|
def create_address
|
@@ -69,69 +132,49 @@ module Coinbase
|
|
69
132
|
}
|
70
133
|
}
|
71
134
|
address_model = Coinbase.call_api do
|
72
|
-
addresses_api.create_address(
|
135
|
+
addresses_api.create_address(id, opts)
|
73
136
|
end
|
74
137
|
|
138
|
+
# Auto-reload wallet to set default address on first address creation.
|
139
|
+
reload if addresses.empty?
|
140
|
+
|
75
141
|
cache_address(address_model, key)
|
76
142
|
end
|
77
143
|
|
78
144
|
# Returns the default address of the Wallet.
|
79
145
|
# @return [Address] The default address
|
80
146
|
def default_address
|
81
|
-
|
147
|
+
address(@model.default_address&.address_id)
|
82
148
|
end
|
83
149
|
|
84
150
|
# Returns the Address with the given ID.
|
85
151
|
# @param address_id [String] The ID of the Address to retrieve
|
86
152
|
# @return [Address] The Address
|
87
|
-
def
|
88
|
-
@addresses.find { |address| address.
|
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
|
153
|
+
def address(address_id)
|
154
|
+
@addresses.find { |address| address.id == address_id }
|
95
155
|
end
|
96
156
|
|
97
157
|
# Returns the list of balances of this Wallet. Balances are aggregated across all Addresses in the Wallet.
|
98
158
|
# @return [BalanceMap] The list of balances. The key is the Asset ID, and the value is the balance.
|
99
|
-
def
|
159
|
+
def balances
|
100
160
|
response = Coinbase.call_api do
|
101
|
-
wallets_api.list_wallet_balances(
|
161
|
+
wallets_api.list_wallet_balances(id)
|
102
162
|
end
|
103
163
|
|
104
|
-
Coinbase.
|
164
|
+
Coinbase::BalanceMap.from_balances(response.data)
|
105
165
|
end
|
106
166
|
|
107
167
|
# Returns the balance of the provided Asset. Balances are aggregated across all Addresses in the Wallet.
|
108
168
|
# @param asset_id [Symbol] The ID of the Asset to retrieve the balance for
|
109
169
|
# @return [BigDecimal] The balance of the Asset
|
110
|
-
def
|
111
|
-
normalized_asset_id = if %i[wei gwei].include?(asset_id)
|
112
|
-
:eth
|
113
|
-
else
|
114
|
-
asset_id
|
115
|
-
end
|
116
|
-
|
170
|
+
def balance(asset_id)
|
117
171
|
response = Coinbase.call_api do
|
118
|
-
wallets_api.get_wallet_balance(
|
172
|
+
wallets_api.get_wallet_balance(id, Coinbase::Asset.primary_denomination(asset_id).to_s)
|
119
173
|
end
|
120
174
|
|
121
175
|
return BigDecimal('0') if response.nil?
|
122
176
|
|
123
|
-
|
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
|
177
|
+
Coinbase::Balance.from_model_and_asset_id(response, asset_id).amount
|
135
178
|
end
|
136
179
|
|
137
180
|
# Transfers the given amount of the given Asset to the given address. Only same-Network Transfers are supported.
|
@@ -143,13 +186,13 @@ module Coinbase
|
|
143
186
|
# @return [Transfer] The hash of the Transfer transaction.
|
144
187
|
def transfer(amount, asset_id, destination)
|
145
188
|
if destination.is_a?(Wallet)
|
146
|
-
raise ArgumentError, 'Transfer must be on the same Network' if destination.network_id !=
|
189
|
+
raise ArgumentError, 'Transfer must be on the same Network' if destination.network_id != network_id
|
147
190
|
|
148
|
-
destination = destination.default_address.
|
191
|
+
destination = destination.default_address.id
|
149
192
|
elsif destination.is_a?(Address)
|
150
|
-
raise ArgumentError, 'Transfer must be on the same Network' if destination.network_id !=
|
193
|
+
raise ArgumentError, 'Transfer must be on the same Network' if destination.network_id != network_id
|
151
194
|
|
152
|
-
destination = destination.
|
195
|
+
destination = destination.id
|
153
196
|
end
|
154
197
|
|
155
198
|
default_address.transfer(amount, asset_id, destination)
|
@@ -158,14 +201,33 @@ module Coinbase
|
|
158
201
|
# Exports the Wallet's data to a Data object.
|
159
202
|
# @return [Data] The Wallet data
|
160
203
|
def export
|
161
|
-
|
204
|
+
raise 'Cannot export Wallet without loaded seed' if @master.nil?
|
205
|
+
|
206
|
+
Data.new(wallet_id: id, seed: @master.seed_hex)
|
207
|
+
end
|
208
|
+
|
209
|
+
# Requests funds from the faucet for the Wallet's default address and returns the faucet transaction.
|
210
|
+
# This is only supported on testnet networks.
|
211
|
+
# @return [Coinbase::FaucetTransaction] The successful faucet transaction
|
212
|
+
# @raise [Coinbase::FaucetLimitReachedError] If the faucet limit has been reached for the address or user.
|
213
|
+
# @raise [Coinbase::Client::ApiError] If an unexpected error occurs while requesting faucet funds.
|
214
|
+
def faucet
|
215
|
+
Coinbase.call_api do
|
216
|
+
Coinbase::FaucetTransaction.new(addresses_api.request_faucet_funds(id, default_address.id))
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
# Returns whether the Wallet has a seed with which to derive keys and sign transactions.
|
221
|
+
# @return [Boolean] Whether the Wallet has a seed with which to derive keys and sign transactions.
|
222
|
+
def can_sign?
|
223
|
+
!@master.nil?
|
162
224
|
end
|
163
225
|
|
164
226
|
# Returns a String representation of the Wallet.
|
165
227
|
# @return [String] a String representation of the Wallet
|
166
228
|
def to_s
|
167
|
-
"Coinbase::Wallet{wallet_id: '#{
|
168
|
-
"default_address: '#{default_address
|
229
|
+
"Coinbase::Wallet{wallet_id: '#{id}', network_id: '#{network_id}', " \
|
230
|
+
"default_address: '#{@model.default_address&.address_id}'}"
|
169
231
|
end
|
170
232
|
|
171
233
|
# Same as to_s.
|
@@ -202,14 +264,55 @@ module Coinbase
|
|
202
264
|
|
203
265
|
private
|
204
266
|
|
267
|
+
# Reloads the Wallet with the latest data.
|
268
|
+
def reload
|
269
|
+
@model = Coinbase.call_api do
|
270
|
+
wallets_api.get_wallet(id)
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
def master_node(seed)
|
275
|
+
return MoneyTree::Master.new if seed.nil?
|
276
|
+
return nil if seed.empty?
|
277
|
+
|
278
|
+
MoneyTree::Master.new(seed_hex: seed)
|
279
|
+
end
|
280
|
+
|
281
|
+
def address_path_prefix
|
282
|
+
# TODO: Add support for other networks.
|
283
|
+
@address_path_prefix ||= case network_id.to_s.split('_').first
|
284
|
+
when 'base'
|
285
|
+
"m/44'/60'/0'/0"
|
286
|
+
else
|
287
|
+
raise ArgumentError, "Unsupported network ID: #{network_id}"
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
# Derives the registered Addresses in the Wallet.
|
292
|
+
# @param address_models [Array<Coinbase::Client::Address>] The models of the addresses already registered with the
|
293
|
+
# Wallet
|
294
|
+
def derive_addresses(address_models)
|
295
|
+
return unless address_models.any?
|
296
|
+
|
297
|
+
# Create a map tracking which addresses are already registered with the Wallet.
|
298
|
+
address_map = build_address_map(address_models)
|
299
|
+
|
300
|
+
address_models.each do |address_model|
|
301
|
+
# Derive the addresses using the provided models.
|
302
|
+
derive_address(address_map, address_model)
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
205
306
|
# Derives an already registered Address in the Wallet.
|
307
|
+
# @param address_map [Hash<String, Boolean>] The map of registered Address IDs
|
308
|
+
# @param address_model [Coinbase::Client::Address] The Address model
|
206
309
|
# @return [Address] The new Address
|
207
|
-
def derive_address
|
208
|
-
key = derive_key
|
310
|
+
def derive_address(address_map, address_model)
|
311
|
+
key = @master.nil? ? nil : derive_key
|
209
312
|
|
210
|
-
|
211
|
-
|
212
|
-
|
313
|
+
unless key.nil?
|
314
|
+
address_from_key = key.address.to_s
|
315
|
+
raise 'Invalid address' if address_map[address_from_key].nil?
|
213
316
|
end
|
214
317
|
|
215
318
|
cache_address(address_model, key)
|
@@ -218,8 +321,11 @@ module Coinbase
|
|
218
321
|
# Derives a key for an already registered Address in the Wallet.
|
219
322
|
# @return [Eth::Key] The new key
|
220
323
|
def derive_key
|
221
|
-
|
324
|
+
raise 'Cannot derive key for Wallet without seed loaded' if @master.nil?
|
325
|
+
|
326
|
+
path = "#{address_path_prefix}/#{@private_key_index}"
|
222
327
|
private_key = @master.node_for_path(path).private_key.to_hex
|
328
|
+
@private_key_index += 1
|
223
329
|
Eth::Key.new(priv: private_key)
|
224
330
|
end
|
225
331
|
|
@@ -230,17 +336,29 @@ module Coinbase
|
|
230
336
|
def cache_address(address_model, key)
|
231
337
|
address = Address.new(address_model, key)
|
232
338
|
@addresses << address
|
233
|
-
@address_index += 1
|
234
339
|
address
|
235
340
|
end
|
236
341
|
|
342
|
+
# Builds a Hash of the registered Addresses.
|
343
|
+
# @param address_models [Array<Coinbase::Client::Address>] The models of the addresses already registered with the
|
344
|
+
# Wallet
|
345
|
+
# @return [Hash<String, Boolean>] The Hash of registered Addresses
|
346
|
+
def build_address_map(address_models)
|
347
|
+
address_map = {}
|
348
|
+
address_models.each do |address_model|
|
349
|
+
address_map[address_model.address_id] = true
|
350
|
+
end
|
351
|
+
|
352
|
+
address_map
|
353
|
+
end
|
354
|
+
|
237
355
|
# Creates an attestation for the Address currently being created.
|
238
356
|
# @param key [Eth::Key] The private key of the Address
|
239
357
|
# @return [String] The attestation
|
240
358
|
def create_attestation(key)
|
241
359
|
public_key = key.public_key.compressed.unpack1('H*')
|
242
360
|
payload = {
|
243
|
-
wallet_id:
|
361
|
+
wallet_id: id,
|
244
362
|
public_key: public_key
|
245
363
|
}.to_json
|
246
364
|
hashed_payload = Digest::SHA256.digest(payload)
|
@@ -258,11 +376,18 @@ module Coinbase
|
|
258
376
|
new_signature_bytes.pack('C*').unpack1('H*')
|
259
377
|
end
|
260
378
|
|
261
|
-
#
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
379
|
+
# Validates the seed and address models passed to the constructor.
|
380
|
+
# @param seed [String] The seed to use for the Wallet
|
381
|
+
# @param address_models [Array<Coinbase::Client::Address>] The models of the addresses already registered with the
|
382
|
+
# Wallet
|
383
|
+
def validate_seed_and_address_models(seed, address_models)
|
384
|
+
raise ArgumentError, 'Seed must be 32 bytes' if !seed.nil? && !seed.empty? && seed.length != 64
|
385
|
+
|
386
|
+
raise ArgumentError, 'Seed must be present if address_models are provided' if seed.nil? && address_models.any?
|
387
|
+
|
388
|
+
return unless !seed.nil? && seed.empty? && address_models.empty?
|
389
|
+
|
390
|
+
raise ArgumentError, 'Seed must be empty if address_models are not provided'
|
266
391
|
end
|
267
392
|
|
268
393
|
def addresses_api
|
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,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: coinbase-sdk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
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-
|
11
|
+
date: 2024-05-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bigdecimal
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: eth
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -216,6 +230,7 @@ files:
|
|
216
230
|
- lib/coinbase/address.rb
|
217
231
|
- lib/coinbase/asset.rb
|
218
232
|
- lib/coinbase/authenticator.rb
|
233
|
+
- lib/coinbase/balance.rb
|
219
234
|
- lib/coinbase/balance_map.rb
|
220
235
|
- lib/coinbase/client.rb
|
221
236
|
- lib/coinbase/client/api/addresses_api.rb
|