coinbase-sdk 0.0.2 → 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 +75 -61
- data/lib/coinbase/asset.rb +72 -1
- data/lib/coinbase/balance.rb +53 -0
- data/lib/coinbase/balance_map.rb +19 -7
- data/lib/coinbase/client/api/addresses_api.rb +69 -0
- data/lib/coinbase/client/api/transfers_api.rb +86 -0
- data/lib/coinbase/client/models/broadcast_transfer_request.rb +222 -0
- data/lib/coinbase/client/models/faucet_transaction.rb +222 -0
- data/lib/coinbase/client/models/transfer.rb +21 -1
- data/lib/coinbase/client.rb +2 -0
- data/lib/coinbase/constants.rb +4 -2
- data/lib/coinbase/errors.rb +120 -0
- data/lib/coinbase/faucet_transaction.rb +42 -0
- data/lib/coinbase/middleware.rb +1 -1
- data/lib/coinbase/transfer.rb +42 -16
- data/lib/coinbase/user.rb +115 -7
- data/lib/coinbase/wallet.rb +85 -40
- data/lib/coinbase.rb +53 -23
- metadata +21 -2
data/lib/coinbase/middleware.rb
CHANGED
@@ -12,7 +12,7 @@ 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
|
-
config.debugging =
|
15
|
+
config.debugging = Coinbase.configuration.debug_api
|
16
16
|
config.host = Coinbase.configuration.api_url
|
17
17
|
config.request(:authenticator)
|
18
18
|
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
|
|
@@ -72,9 +72,21 @@ module Coinbase
|
|
72
72
|
end
|
73
73
|
|
74
74
|
# Returns the amount of the asset for the Transfer.
|
75
|
-
# @return [BigDecimal] The amount
|
75
|
+
# @return [BigDecimal] The amount of the asset
|
76
76
|
def amount
|
77
|
-
|
77
|
+
case asset_id
|
78
|
+
when :eth
|
79
|
+
BigDecimal(@model.amount) / BigDecimal(Coinbase::WEI_PER_ETHER.to_s)
|
80
|
+
else
|
81
|
+
BigDecimal(@model.amount)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Returns the link to the transaction on the blockchain explorer.
|
86
|
+
# @return [String] The link to the transaction on the blockchain explorer
|
87
|
+
def transaction_link
|
88
|
+
# TODO: Parameterize this by Network.
|
89
|
+
"https://sepolia.basescan.org/tx/#{transaction_hash}"
|
78
90
|
end
|
79
91
|
|
80
92
|
# Returns the Unsigned Payload of the Transfer.
|
@@ -83,6 +95,18 @@ module Coinbase
|
|
83
95
|
@model.unsigned_payload
|
84
96
|
end
|
85
97
|
|
98
|
+
# Returns the Signed Payload of the Transfer.
|
99
|
+
# @return [String] The Signed Payload
|
100
|
+
def signed_payload
|
101
|
+
@model.signed_payload
|
102
|
+
end
|
103
|
+
|
104
|
+
# Returns the Transaction Hash of the Transfer.
|
105
|
+
# @return [String] The Transaction Hash
|
106
|
+
def transaction_hash
|
107
|
+
@model.transaction_hash
|
108
|
+
end
|
109
|
+
|
86
110
|
# Returns the underlying Transfer transaction, creating it if it has not been yet.
|
87
111
|
# @return [Eth::Tx::Eip1559] The Transfer transaction
|
88
112
|
def transaction
|
@@ -110,13 +134,8 @@ module Coinbase
|
|
110
134
|
# Returns the status of the Transfer.
|
111
135
|
# @return [Symbol] The status
|
112
136
|
def status
|
113
|
-
|
114
|
-
|
115
|
-
transaction.hash
|
116
|
-
rescue Eth::Signature::SignatureError
|
117
|
-
# If the transaction has not been signed, it is still pending.
|
118
|
-
return Status::PENDING
|
119
|
-
end
|
137
|
+
# Check if the transfer has been signed yet.
|
138
|
+
return Status::PENDING if transaction_hash.nil?
|
120
139
|
|
121
140
|
onchain_transaction = Coinbase.configuration.base_sepolia_client.eth_getTransactionByHash(transaction_hash)
|
122
141
|
|
@@ -157,12 +176,19 @@ module Coinbase
|
|
157
176
|
self
|
158
177
|
end
|
159
178
|
|
160
|
-
# Returns
|
161
|
-
# @return [String]
|
162
|
-
def
|
163
|
-
"
|
164
|
-
|
165
|
-
|
179
|
+
# Returns a String representation of the Transfer.
|
180
|
+
# @return [String] a String representation of the Transfer
|
181
|
+
def to_s
|
182
|
+
"Coinbase::Transfer{transfer_id: '#{id}', network_id: '#{network_id}', " \
|
183
|
+
"from_address_id: '#{from_address_id}', destination_address_id: '#{destination_address_id}', " \
|
184
|
+
"asset_id: '#{asset_id}', amount: '#{amount}', transaction_hash: '#{transaction_hash}', " \
|
185
|
+
"transaction_link: '#{transaction_link}', status: '#{status}'}"
|
186
|
+
end
|
187
|
+
|
188
|
+
# Same as to_s.
|
189
|
+
# @return [String] a String representation of the Transfer
|
190
|
+
def inspect
|
191
|
+
to_s
|
166
192
|
end
|
167
193
|
end
|
168
194
|
end
|
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
|
|
@@ -30,7 +30,9 @@ module Coinbase
|
|
30
30
|
}
|
31
31
|
opts = { create_wallet_request: create_wallet_request }
|
32
32
|
|
33
|
-
model =
|
33
|
+
model = Coinbase.call_api do
|
34
|
+
wallets_api.create_wallet(opts)
|
35
|
+
end
|
34
36
|
|
35
37
|
Wallet.new(model)
|
36
38
|
end
|
@@ -39,18 +41,107 @@ module Coinbase
|
|
39
41
|
# @param data [Coinbase::Wallet::Data] the Wallet data to import
|
40
42
|
# @return [Coinbase::Wallet] the imported Wallet
|
41
43
|
def import_wallet(data)
|
42
|
-
|
43
|
-
address_count = addresses_api.list_addresses(model.id).total_count
|
44
|
-
Wallet.new(model, seed: data.seed, address_count: address_count)
|
44
|
+
Wallet.import(data)
|
45
45
|
end
|
46
46
|
|
47
47
|
# Lists the IDs of the Wallets belonging to the User.
|
48
48
|
# @return [Array<String>] the IDs of the Wallets belonging to the User
|
49
|
-
def
|
50
|
-
wallets =
|
49
|
+
def wallet_ids
|
50
|
+
wallets = Coinbase.call_api do
|
51
|
+
wallets_api.list_wallets
|
52
|
+
end
|
53
|
+
|
51
54
|
wallets.data.map(&:id)
|
52
55
|
end
|
53
56
|
|
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.
|
61
|
+
# The default backup_file is `seeds.json` in the root folder. It can be configured by changing
|
62
|
+
# Coinbase.configuration.backup_file_path.
|
63
|
+
#
|
64
|
+
# @param wallet [Coinbase::Wallet] The wallet model to save.
|
65
|
+
# @param encrypt [bool] (Optional) Boolean representing whether the backup persisted to local file system should be
|
66
|
+
# encrypted or not. Data is unencrypted by default.
|
67
|
+
# @return [Coinbase::Wallet] the saved wallet.
|
68
|
+
def save_wallet_locally!(wallet, encrypt: false)
|
69
|
+
existing_seeds_in_store = existing_seeds
|
70
|
+
data = wallet.export
|
71
|
+
seed_to_store = data.seed
|
72
|
+
auth_tag = ''
|
73
|
+
iv = ''
|
74
|
+
if encrypt
|
75
|
+
shared_secret = store_encryption_key
|
76
|
+
cipher = OpenSSL::Cipher.new('aes-256-gcm').encrypt
|
77
|
+
cipher.key = OpenSSL::Digest.digest('SHA256', shared_secret)
|
78
|
+
iv = cipher.random_iv
|
79
|
+
cipher.iv = iv
|
80
|
+
cipher.auth_data = ''
|
81
|
+
encrypted_data = cipher.update(data.seed) + cipher.final
|
82
|
+
auth_tag = cipher.auth_tag.unpack1('H*')
|
83
|
+
iv = iv.unpack1('H*')
|
84
|
+
seed_to_store = encrypted_data.unpack1('H*')
|
85
|
+
end
|
86
|
+
|
87
|
+
existing_seeds_in_store[data.wallet_id] = {
|
88
|
+
seed: seed_to_store,
|
89
|
+
encrypted: encrypt,
|
90
|
+
auth_tag: auth_tag,
|
91
|
+
iv: iv
|
92
|
+
}
|
93
|
+
|
94
|
+
File.open(Coinbase.configuration.backup_file_path, 'w') do |file|
|
95
|
+
file.write(JSON.pretty_generate(existing_seeds_in_store))
|
96
|
+
end
|
97
|
+
wallet
|
98
|
+
end
|
99
|
+
|
100
|
+
# Loads all wallets belonging to the User with backup persisted to the local file system.
|
101
|
+
# @return [Map<String>Coinbase::Wallet] the map of wallet_ids to the wallets.
|
102
|
+
def load_wallets_from_local
|
103
|
+
existing_seeds_in_store = existing_seeds
|
104
|
+
raise ArgumentError, 'Backup file not found' if existing_seeds_in_store == {}
|
105
|
+
|
106
|
+
wallets = {}
|
107
|
+
existing_seeds_in_store.each do |wallet_id, seed_data|
|
108
|
+
seed = seed_data['seed']
|
109
|
+
raise ArgumentError, 'Malformed backup data' if seed.nil? || seed == ''
|
110
|
+
|
111
|
+
if seed_data['encrypted']
|
112
|
+
shared_secret = store_encryption_key
|
113
|
+
raise ArgumentError, 'Malformed encrypted seed data' if seed_data['iv'] == '' ||
|
114
|
+
seed_data['auth_tag'] == ''
|
115
|
+
|
116
|
+
cipher = OpenSSL::Cipher.new('aes-256-gcm').decrypt
|
117
|
+
cipher.key = OpenSSL::Digest.digest('SHA256', shared_secret)
|
118
|
+
iv = [seed_data['iv']].pack('H*')
|
119
|
+
cipher.iv = iv
|
120
|
+
auth_tag = [seed_data['auth_tag']].pack('H*')
|
121
|
+
cipher.auth_tag = auth_tag
|
122
|
+
cipher.auth_data = ''
|
123
|
+
hex_decoded_data = [seed_data['seed']].pack('H*')
|
124
|
+
seed = cipher.update(hex_decoded_data) + cipher.final
|
125
|
+
end
|
126
|
+
|
127
|
+
data = Coinbase::Wallet::Data.new(wallet_id: wallet_id, seed: seed)
|
128
|
+
wallets[wallet_id] = import_wallet(data)
|
129
|
+
end
|
130
|
+
wallets
|
131
|
+
end
|
132
|
+
|
133
|
+
# Returns a string representation of the User.
|
134
|
+
# @return [String] a string representation of the User
|
135
|
+
def to_s
|
136
|
+
"Coinbase::User{user_id: '#{id}'}"
|
137
|
+
end
|
138
|
+
|
139
|
+
# Same as to_s.
|
140
|
+
# @return [String] a string representation of the User
|
141
|
+
def inspect
|
142
|
+
to_s
|
143
|
+
end
|
144
|
+
|
54
145
|
private
|
55
146
|
|
56
147
|
def addresses_api
|
@@ -60,5 +151,22 @@ module Coinbase
|
|
60
151
|
def wallets_api
|
61
152
|
@wallets_api ||= Coinbase::Client::WalletsApi.new(Coinbase.configuration.api_client)
|
62
153
|
end
|
154
|
+
|
155
|
+
def existing_seeds
|
156
|
+
existing_seed_data = '{}'
|
157
|
+
file_path = Coinbase.configuration.backup_file_path
|
158
|
+
existing_seed_data = File.read(file_path) if File.exist?(file_path)
|
159
|
+
output = JSON.parse(existing_seed_data)
|
160
|
+
|
161
|
+
raise ArgumentError, 'Malformed backup data' unless output.is_a?(Hash)
|
162
|
+
|
163
|
+
output
|
164
|
+
end
|
165
|
+
|
166
|
+
def store_encryption_key
|
167
|
+
pk = OpenSSL::PKey.read(Coinbase.configuration.api_key_private_key)
|
168
|
+
public_key = pk.public_key # use own public key to generate the shared secret.
|
169
|
+
pk.dh_compute_key(public_key)
|
170
|
+
end
|
63
171
|
end
|
64
172
|
end
|
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
|
|
@@ -68,7 +101,9 @@ module Coinbase
|
|
68
101
|
attestation: attestation
|
69
102
|
}
|
70
103
|
}
|
71
|
-
address_model =
|
104
|
+
address_model = Coinbase.call_api do
|
105
|
+
addresses_api.create_address(id, opts)
|
106
|
+
end
|
72
107
|
|
73
108
|
cache_address(address_model, key)
|
74
109
|
end
|
@@ -76,55 +111,37 @@ module Coinbase
|
|
76
111
|
# Returns the default address of the Wallet.
|
77
112
|
# @return [Address] The default address
|
78
113
|
def default_address
|
79
|
-
|
114
|
+
address(@model.default_address.address_id)
|
80
115
|
end
|
81
116
|
|
82
117
|
# Returns the Address with the given ID.
|
83
118
|
# @param address_id [String] The ID of the Address to retrieve
|
84
119
|
# @return [Address] The Address
|
85
|
-
def
|
86
|
-
@addresses.find { |address| address.
|
87
|
-
end
|
88
|
-
|
89
|
-
# Returns the list of Addresses in the Wallet.
|
90
|
-
# @return [Array<Address>] The list of Addresses
|
91
|
-
def list_addresses
|
92
|
-
@addresses
|
120
|
+
def address(address_id)
|
121
|
+
@addresses.find { |address| address.id == address_id }
|
93
122
|
end
|
94
123
|
|
95
124
|
# Returns the list of balances of this Wallet. Balances are aggregated across all Addresses in the Wallet.
|
96
125
|
# @return [BalanceMap] The list of balances. The key is the Asset ID, and the value is the balance.
|
97
|
-
def
|
98
|
-
response =
|
99
|
-
|
126
|
+
def balances
|
127
|
+
response = Coinbase.call_api do
|
128
|
+
wallets_api.list_wallet_balances(id)
|
129
|
+
end
|
130
|
+
|
131
|
+
Coinbase::BalanceMap.from_balances(response.data)
|
100
132
|
end
|
101
133
|
|
102
134
|
# Returns the balance of the provided Asset. Balances are aggregated across all Addresses in the Wallet.
|
103
135
|
# @param asset_id [Symbol] The ID of the Asset to retrieve the balance for
|
104
136
|
# @return [BigDecimal] The balance of the Asset
|
105
|
-
def
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
asset_id
|
110
|
-
end
|
111
|
-
|
112
|
-
response = wallets_api.get_wallet_balance(wallet_id, normalized_asset_id.to_s)
|
137
|
+
def balance(asset_id)
|
138
|
+
response = Coinbase.call_api do
|
139
|
+
wallets_api.get_wallet_balance(id, Coinbase::Asset.primary_denomination(asset_id).to_s)
|
140
|
+
end
|
113
141
|
|
114
142
|
return BigDecimal('0') if response.nil?
|
115
143
|
|
116
|
-
|
117
|
-
|
118
|
-
case asset_id
|
119
|
-
when :eth
|
120
|
-
amount / BigDecimal(Coinbase::WEI_PER_ETHER.to_s)
|
121
|
-
when :gwei
|
122
|
-
amount / BigDecimal(Coinbase::GWEI_PER_ETHER.to_s)
|
123
|
-
when :usdc
|
124
|
-
amount / BigDecimal(Coinbase::ATOMIC_UNITS_PER_USDC.to_s)
|
125
|
-
else
|
126
|
-
amount
|
127
|
-
end
|
144
|
+
Coinbase::Balance.from_model_and_asset_id(response, asset_id).amount
|
128
145
|
end
|
129
146
|
|
130
147
|
# Transfers the given amount of the given Asset to the given address. Only same-Network Transfers are supported.
|
@@ -138,11 +155,11 @@ module Coinbase
|
|
138
155
|
if destination.is_a?(Wallet)
|
139
156
|
raise ArgumentError, 'Transfer must be on the same Network' if destination.network_id != @network_id
|
140
157
|
|
141
|
-
destination = destination.default_address.
|
158
|
+
destination = destination.default_address.id
|
142
159
|
elsif destination.is_a?(Address)
|
143
160
|
raise ArgumentError, 'Transfer must be on the same Network' if destination.network_id != @network_id
|
144
161
|
|
145
|
-
destination = destination.
|
162
|
+
destination = destination.id
|
146
163
|
end
|
147
164
|
|
148
165
|
default_address.transfer(amount, asset_id, destination)
|
@@ -151,7 +168,31 @@ module Coinbase
|
|
151
168
|
# Exports the Wallet's data to a Data object.
|
152
169
|
# @return [Data] The Wallet data
|
153
170
|
def export
|
154
|
-
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
|
183
|
+
end
|
184
|
+
|
185
|
+
# Returns a String representation of the Wallet.
|
186
|
+
# @return [String] a String representation of the Wallet
|
187
|
+
def to_s
|
188
|
+
"Coinbase::Wallet{wallet_id: '#{id}', network_id: '#{network_id}', " \
|
189
|
+
"default_address: '#{default_address.id}'}"
|
190
|
+
end
|
191
|
+
|
192
|
+
# Same as to_s.
|
193
|
+
# @return [String] a String representation of the Wallet
|
194
|
+
def inspect
|
195
|
+
to_s
|
155
196
|
end
|
156
197
|
|
157
198
|
# The data required to recreate a Wallet.
|
@@ -188,7 +229,9 @@ module Coinbase
|
|
188
229
|
key = derive_key
|
189
230
|
|
190
231
|
address_id = key.address.to_s
|
191
|
-
address_model =
|
232
|
+
address_model = Coinbase.call_api do
|
233
|
+
addresses_api.get_address(id, address_id)
|
234
|
+
end
|
192
235
|
|
193
236
|
cache_address(address_model, key)
|
194
237
|
end
|
@@ -218,7 +261,7 @@ module Coinbase
|
|
218
261
|
def create_attestation(key)
|
219
262
|
public_key = key.public_key.compressed.unpack1('H*')
|
220
263
|
payload = {
|
221
|
-
wallet_id:
|
264
|
+
wallet_id: id,
|
222
265
|
public_key: public_key
|
223
266
|
}.to_json
|
224
267
|
hashed_payload = Digest::SHA256.digest(payload)
|
@@ -238,7 +281,9 @@ module Coinbase
|
|
238
281
|
|
239
282
|
# Updates the Wallet model with the latest data.
|
240
283
|
def update_model
|
241
|
-
@model =
|
284
|
+
@model = Coinbase.call_api do
|
285
|
+
wallets_api.get_wallet(id)
|
286
|
+
end
|
242
287
|
end
|
243
288
|
|
244
289
|
def addresses_api
|
data/lib/coinbase.rb
CHANGED
@@ -3,23 +3,30 @@
|
|
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'
|
10
|
+
require_relative 'coinbase/errors'
|
11
|
+
require_relative 'coinbase/faucet_transaction'
|
9
12
|
require_relative 'coinbase/middleware'
|
10
13
|
require_relative 'coinbase/network'
|
11
14
|
require_relative 'coinbase/transfer'
|
12
15
|
require_relative 'coinbase/user'
|
13
16
|
require_relative 'coinbase/wallet'
|
17
|
+
require 'json'
|
14
18
|
|
15
19
|
# The Coinbase SDK.
|
16
20
|
module Coinbase
|
17
21
|
class InvalidConfiguration < StandardError; end
|
18
22
|
|
23
|
+
# Returns the configuration object.
|
24
|
+
# @return [Configuration] the configuration object
|
19
25
|
def self.configuration
|
20
26
|
@configuration ||= Configuration.new
|
21
27
|
end
|
22
28
|
|
29
|
+
# Configures the Coinbase SDK.
|
23
30
|
def self.configure
|
24
31
|
yield(configuration)
|
25
32
|
|
@@ -27,22 +34,54 @@ module Coinbase
|
|
27
34
|
raise InvalidConfiguration, 'API key name is not set' unless configuration.api_key_name
|
28
35
|
end
|
29
36
|
|
30
|
-
#
|
37
|
+
# Configures the Coinbase SDK from the given CDP API Key JSON file.
|
38
|
+
# @param file_path [String] (Optional) the path to the CDP API Key JSON file
|
39
|
+
# file in the root directory by default.
|
40
|
+
def self.configure_from_json(file_path = 'coinbase_cloud_api_key.json')
|
41
|
+
configuration.from_json(file_path)
|
42
|
+
|
43
|
+
raise InvalidConfiguration, 'API key private key is not set' unless configuration.api_key_private_key
|
44
|
+
raise InvalidConfiguration, 'API key name is not set' unless configuration.api_key_name
|
45
|
+
end
|
46
|
+
|
47
|
+
# Configuration object for the Coinbase SDK.
|
31
48
|
class Configuration
|
32
49
|
attr_reader :base_sepolia_rpc_url, :base_sepolia_client
|
33
|
-
attr_accessor :api_url, :api_key_name, :api_key_private_key
|
50
|
+
attr_accessor :api_url, :api_key_name, :api_key_private_key, :debug_api, :backup_file_path
|
34
51
|
|
52
|
+
# Initializes the configuration object.
|
35
53
|
def initialize
|
36
54
|
@base_sepolia_rpc_url = 'https://sepolia.base.org'
|
37
55
|
@base_sepolia_client = Jimson::Client.new(@base_sepolia_rpc_url)
|
38
56
|
@api_url = 'https://api.cdp.coinbase.com'
|
57
|
+
@debug_api = false
|
58
|
+
@backup_file_path = 'seeds.json'
|
59
|
+
end
|
60
|
+
|
61
|
+
# Sets configuration values based on the provided CDP API Key JSON file.
|
62
|
+
# @param file_path [String] (Optional) the path to the CDP API Key JSON file
|
63
|
+
# file in the root directory by default.
|
64
|
+
def from_json(file_path = 'coinbase_cloud_api_key.json')
|
65
|
+
# Expand paths to respect shortcuts like ~.
|
66
|
+
file_path = File.expand_path(file_path)
|
67
|
+
|
68
|
+
raise InvalidConfiguration, 'Invalid configuration file type' unless file_path.end_with?('.json')
|
69
|
+
|
70
|
+
file = File.read(file_path)
|
71
|
+
data = JSON.parse(file)
|
72
|
+
@api_key_name = data['name']
|
73
|
+
@api_key_private_key = data['privateKey']
|
39
74
|
end
|
40
75
|
|
76
|
+
# Sets the Base Sepolia RPC URL.
|
77
|
+
# @param new_base_sepolia_rpc_url [String] the new Base Sepolia RPC URL
|
41
78
|
def base_sepolia_rpc_url=(new_base_sepolia_rpc_url)
|
42
79
|
@base_sepolia_rpc_url = new_base_sepolia_rpc_url
|
43
80
|
@base_sepolia_client = Jimson::Client.new(@base_sepolia_rpc_url)
|
44
81
|
end
|
45
82
|
|
83
|
+
# Returns the API client.
|
84
|
+
# @return [Coinbase::Client::ApiClient] the API client
|
46
85
|
def api_client
|
47
86
|
@api_client ||= Coinbase::Client::ApiClient.new(Middleware.config)
|
48
87
|
end
|
@@ -61,30 +100,21 @@ module Coinbase
|
|
61
100
|
value.to_s.gsub('-', '_').to_sym
|
62
101
|
end
|
63
102
|
|
64
|
-
#
|
65
|
-
# @
|
66
|
-
# @return [BalanceMap] The converted BalanceMap
|
67
|
-
def self.to_balance_map(address_balance_list)
|
68
|
-
balances = {}
|
69
|
-
|
70
|
-
address_balance_list.data.each do |balance|
|
71
|
-
asset_id = Coinbase.to_sym(balance.asset.asset_id.downcase)
|
72
|
-
amount = if asset_id == :eth
|
73
|
-
BigDecimal(balance.amount) / BigDecimal(Coinbase::WEI_PER_ETHER)
|
74
|
-
elsif asset_id == :usdc
|
75
|
-
BigDecimal(balance.amount) / BigDecimal(Coinbase::ATOMIC_UNITS_PER_USDC)
|
76
|
-
else
|
77
|
-
BigDecimal(balance.amount)
|
78
|
-
end
|
79
|
-
balances[asset_id] = amount
|
80
|
-
end
|
81
|
-
|
82
|
-
BalanceMap.new(balances)
|
83
|
-
end
|
84
|
-
|
103
|
+
# Loads the default user.
|
104
|
+
# @return [Coinbase::User] the default user
|
85
105
|
def self.load_default_user
|
86
106
|
users_api = Coinbase::Client::UsersApi.new(configuration.api_client)
|
87
107
|
user_model = users_api.get_current_user
|
88
108
|
Coinbase::User.new(user_model)
|
89
109
|
end
|
110
|
+
|
111
|
+
# Wraps a call to the Platform API to ensure that the error is caught and
|
112
|
+
# wrapped as an APIError.
|
113
|
+
def self.call_api
|
114
|
+
yield
|
115
|
+
rescue Coinbase::Client::ApiError => e
|
116
|
+
raise Coinbase::APIError.from_error(e)
|
117
|
+
rescue StandardError => e
|
118
|
+
raise e
|
119
|
+
end
|
90
120
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: coinbase-sdk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
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-
|
11
|
+
date: 2024-05-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: eth
|
@@ -192,6 +192,20 @@ dependencies:
|
|
192
192
|
- - '='
|
193
193
|
- !ruby/object:Gem::Version
|
194
194
|
version: 0.9.36
|
195
|
+
- !ruby/object:Gem::Dependency
|
196
|
+
name: yard-markdown
|
197
|
+
requirement: !ruby/object:Gem::Requirement
|
198
|
+
requirements:
|
199
|
+
- - ">="
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
version: '0'
|
202
|
+
type: :development
|
203
|
+
prerelease: false
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - ">="
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: '0'
|
195
209
|
description: Coinbase Ruby SDK for accessing Coinbase Platform APIs
|
196
210
|
email: yuga.cohler@coinbase.com
|
197
211
|
executables: []
|
@@ -202,6 +216,7 @@ files:
|
|
202
216
|
- lib/coinbase/address.rb
|
203
217
|
- lib/coinbase/asset.rb
|
204
218
|
- lib/coinbase/authenticator.rb
|
219
|
+
- lib/coinbase/balance.rb
|
205
220
|
- lib/coinbase/balance_map.rb
|
206
221
|
- lib/coinbase/client.rb
|
207
222
|
- lib/coinbase/client/api/addresses_api.rb
|
@@ -216,10 +231,12 @@ files:
|
|
216
231
|
- lib/coinbase/client/models/address_list.rb
|
217
232
|
- lib/coinbase/client/models/asset.rb
|
218
233
|
- lib/coinbase/client/models/balance.rb
|
234
|
+
- lib/coinbase/client/models/broadcast_transfer_request.rb
|
219
235
|
- lib/coinbase/client/models/create_address_request.rb
|
220
236
|
- lib/coinbase/client/models/create_transfer_request.rb
|
221
237
|
- lib/coinbase/client/models/create_wallet_request.rb
|
222
238
|
- lib/coinbase/client/models/error.rb
|
239
|
+
- lib/coinbase/client/models/faucet_transaction.rb
|
223
240
|
- lib/coinbase/client/models/transfer.rb
|
224
241
|
- lib/coinbase/client/models/transfer_list.rb
|
225
242
|
- lib/coinbase/client/models/user.rb
|
@@ -227,6 +244,8 @@ files:
|
|
227
244
|
- lib/coinbase/client/models/wallet_list.rb
|
228
245
|
- lib/coinbase/client/version.rb
|
229
246
|
- lib/coinbase/constants.rb
|
247
|
+
- lib/coinbase/errors.rb
|
248
|
+
- lib/coinbase/faucet_transaction.rb
|
230
249
|
- lib/coinbase/middleware.rb
|
231
250
|
- lib/coinbase/network.rb
|
232
251
|
- lib/coinbase/transfer.rb
|