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 +4 -4
- data/lib/coinbase/address.rb +26 -74
- data/lib/coinbase/asset.rb +72 -1
- data/lib/coinbase/balance.rb +53 -0
- data/lib/coinbase/balance_map.rb +18 -6
- data/lib/coinbase/transfer.rb +2 -2
- data/lib/coinbase/user.rb +10 -18
- data/lib/coinbase/wallet.rb +63 -42
- data/lib/coinbase.rb +1 -25
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d4413913708fadc44dcbb49a00a72fe55382187c8084531b9cec43894e0ee9a0
|
4
|
+
data.tar.gz: e47f6295ce5f8bc1d8888b49ba71cdbc1558d606e708e66452f0ae6a76127249
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: acb6233add651f82063b7f2a73da8b7a8112687603d61fb77f3160713d813ea07447e25b5b69e83dd81c1852478c1b9999c1b207c9137ae08868db495721181b
|
7
|
+
data.tar.gz: 3b72b12e92386e7114e0146f257032b904a4f26a2a97369bff19c1bc722b195372c830a2bb405e1a2f2655c81608beeee8d601deab293f87c1adf5fb18ca64e9
|
data/lib/coinbase/address.rb
CHANGED
@@ -35,45 +35,32 @@ 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
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
|
45
|
+
def balances
|
46
46
|
response = Coinbase.call_api do
|
47
|
-
addresses_api.list_address_balances(wallet_id,
|
47
|
+
addresses_api.list_address_balances(wallet_id, id)
|
48
48
|
end
|
49
49
|
|
50
|
-
Coinbase.
|
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
|
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,
|
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
|
-
|
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::
|
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.
|
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.
|
82
|
+
destination = destination.id
|
96
83
|
end
|
97
84
|
|
98
|
-
current_balance =
|
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:
|
91
|
+
amount: Coinbase::Asset.to_atomic_amount(amount, asset_id).to_i.to_s,
|
109
92
|
network_id: network_id,
|
110
|
-
asset_id:
|
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,
|
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,
|
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{
|
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::
|
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,
|
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
|
-
#
|
166
|
-
# @return [Array<
|
167
|
-
def
|
168
|
-
|
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,
|
157
|
+
transfers_api.list_transfers(wallet_id, id, { limit: 100, page: page })
|
174
158
|
end
|
175
159
|
|
176
|
-
|
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
|
-
|
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
|
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,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
|
data/lib/coinbase/balance_map.rb
CHANGED
@@ -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
|
-
#
|
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
30
|
# @return [String] The string representation of the balance
|
19
31
|
def to_s
|
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,7 +15,7 @@ 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
|
|
@@ -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
|
-
|
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
|
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
|
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.
|
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
|
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
|
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: '#{
|
136
|
+
"Coinbase::User{user_id: '#{id}'}"
|
145
137
|
end
|
146
138
|
|
147
139
|
# Same as to_s.
|
data/lib/coinbase/wallet.rb
CHANGED
@@ -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
|
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(
|
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
|
-
|
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
|
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
|
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
|
126
|
+
def balances
|
100
127
|
response = Coinbase.call_api do
|
101
|
-
wallets_api.list_wallet_balances(
|
128
|
+
wallets_api.list_wallet_balances(id)
|
102
129
|
end
|
103
130
|
|
104
|
-
Coinbase.
|
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
|
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(
|
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
|
-
|
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.
|
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.
|
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:
|
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: '#{
|
168
|
-
"default_address: '#{default_address.
|
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(
|
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:
|
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(
|
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.
|
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-
|
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
|