coinbase-sdk 0.0.10 → 0.0.13
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/wallet_address.rb +44 -115
- data/lib/coinbase/constants.rb +3 -0
- data/lib/coinbase/destination.rb +51 -0
- data/lib/coinbase/errors.rb +14 -0
- data/lib/coinbase/trade.rb +87 -5
- data/lib/coinbase/transaction.rb +13 -2
- data/lib/coinbase/transfer.rb +82 -2
- data/lib/coinbase/wallet.rb +1 -4
- data/lib/coinbase.rb +1 -0
- 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: 6ea6f3f49e4b03f6131d891a1e628b9bed3a60b40b0a640358b5cc85ff4075ab
|
4
|
+
data.tar.gz: 92d2b00b3dac22f12173f9b6a7860889b7d9e64966e55cf7ba175a3728f43be3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c4a96ebe5f58f569419d2911aab739706d4176fb403b2283d8b44d29f36768bcf2588088f1870cbabc7a7f4941d12a9d796565e60c126014c48b318725fb8d13
|
7
|
+
data.tar.gz: d97661b3ab9abb774561a307bb228c1d3795077777001ca5b6657f2205cf81f8674f68ef4bb9dff4b01623cfffa5c2835e26e58d26dbbf51a8bfcd70b13edc52
|
@@ -8,8 +8,6 @@ module Coinbase
|
|
8
8
|
# Addresses are used to send and receive Assets, and should be created using
|
9
9
|
# Wallet#create_address. Addresses require an Eth::Key to sign transaction data.
|
10
10
|
class WalletAddress < Address
|
11
|
-
PAGE_LIMIT = 100
|
12
|
-
|
13
11
|
# Returns a new Address object. Do not use this method directly. Instead, use Wallet#create_address, or use
|
14
12
|
# the Wallet's default_address.
|
15
13
|
# @param model [Coinbase::Client::Address] The underlying Address object
|
@@ -43,18 +41,25 @@ module Coinbase
|
|
43
41
|
# default address. If a String, interprets it as the address ID.
|
44
42
|
# @return [Coinbase::Transfer] The Transfer object.
|
45
43
|
def transfer(amount, asset_id, destination)
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
44
|
+
ensure_can_sign!
|
45
|
+
ensure_sufficient_balance!(amount, asset_id)
|
46
|
+
|
47
|
+
transfer = Transfer.create(
|
48
|
+
address_id: id,
|
49
|
+
amount: amount,
|
50
|
+
asset_id: asset_id,
|
51
|
+
destination: destination,
|
52
|
+
network_id: network_id,
|
53
|
+
wallet_id: wallet_id
|
54
|
+
)
|
53
55
|
|
54
56
|
# If a server signer is managing keys, it will sign and broadcast the underlying transfer transaction out of band.
|
55
57
|
return transfer if Coinbase.use_server_signer?
|
56
58
|
|
57
|
-
|
59
|
+
transfer.transaction.sign(@key)
|
60
|
+
|
61
|
+
transfer.broadcast!
|
62
|
+
transfer
|
58
63
|
end
|
59
64
|
|
60
65
|
# Trades the given amount of the given Asset for another Asset.
|
@@ -64,20 +69,27 @@ module Coinbase
|
|
64
69
|
# @param to_asset_id [Symbol] The ID of the Asset to trade to. For Ether, :eth, :gwei, and :wei are supported.
|
65
70
|
# @return [Coinbase::Trade] The Trade object.
|
66
71
|
def trade(amount, from_asset_id, to_asset_id)
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
72
|
+
ensure_can_sign!
|
73
|
+
ensure_sufficient_balance!(amount, from_asset_id)
|
74
|
+
|
75
|
+
trade = Trade.create(
|
76
|
+
address_id: id,
|
77
|
+
amount: amount,
|
78
|
+
from_asset_id: from_asset_id,
|
79
|
+
to_asset_id: to_asset_id,
|
80
|
+
network_id: network_id,
|
81
|
+
wallet_id: wallet_id
|
82
|
+
)
|
83
|
+
|
84
|
+
# If a server signer is managing keys, it will sign and broadcast the underlying trade transaction out of band.
|
85
|
+
return trade if Coinbase.use_server_signer?
|
86
|
+
|
87
|
+
trade.transactions.each do |tx|
|
88
|
+
tx.sign(@key)
|
89
|
+
end
|
79
90
|
|
80
|
-
|
91
|
+
trade.broadcast!
|
92
|
+
trade
|
81
93
|
end
|
82
94
|
|
83
95
|
# Returns whether the Address has a private key backing it to sign transactions.
|
@@ -99,9 +111,7 @@ module Coinbase
|
|
99
111
|
# converted to an array, etc...
|
100
112
|
# @return [Enumerable<Coinbase::Transfer>] Enumerator that returns the address's transfers
|
101
113
|
def transfers
|
102
|
-
|
103
|
-
Coinbase::Transfer.new(transfer)
|
104
|
-
end
|
114
|
+
Transfer.list(wallet_id: wallet_id, address_id: id)
|
105
115
|
end
|
106
116
|
|
107
117
|
# Enumerates the trades associated with the address.
|
@@ -109,9 +119,7 @@ module Coinbase
|
|
109
119
|
# converted to an array, etc...
|
110
120
|
# @return [Enumerable<Coinbase::Trade>] Enumerator that returns the address's trades
|
111
121
|
def trades
|
112
|
-
|
113
|
-
Coinbase::Trade.new(trade)
|
114
|
-
end
|
122
|
+
Trade.list(wallet_id: wallet_id, address_id: id)
|
115
123
|
end
|
116
124
|
|
117
125
|
# Returns a String representation of the WalletAddress.
|
@@ -122,98 +130,19 @@ module Coinbase
|
|
122
130
|
|
123
131
|
private
|
124
132
|
|
125
|
-
def
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
def fetch_trades_page(page)
|
130
|
-
trades_api.list_trades(wallet_id, id, { limit: PAGE_LIMIT, page: page })
|
131
|
-
end
|
132
|
-
|
133
|
-
def transfers_api
|
134
|
-
@transfers_api ||= Coinbase::Client::TransfersApi.new(Coinbase.configuration.api_client)
|
135
|
-
end
|
136
|
-
|
137
|
-
def trades_api
|
138
|
-
@trades_api ||= Coinbase::Client::TradesApi.new(Coinbase.configuration.api_client)
|
139
|
-
end
|
140
|
-
|
141
|
-
def destination_address_and_network(destination)
|
142
|
-
return [destination.default_address.id, destination.network_id] if destination.is_a?(Wallet)
|
143
|
-
return [destination.id, destination.network_id] if destination.is_a?(Address)
|
133
|
+
def ensure_can_sign!
|
134
|
+
return if Coinbase.use_server_signer?
|
135
|
+
return if can_sign?
|
144
136
|
|
145
|
-
|
137
|
+
raise AddressCannotSignError
|
146
138
|
end
|
147
139
|
|
148
|
-
def
|
149
|
-
|
150
|
-
|
151
|
-
raise ArgumentError, 'Transfer must be on the same Network' unless destination_network_id == network_id
|
152
|
-
|
153
|
-
current_balance = balance(asset.asset_id)
|
140
|
+
def ensure_sufficient_balance!(amount, asset_id)
|
141
|
+
current_balance = balance(asset_id)
|
154
142
|
|
155
143
|
return unless current_balance < amount
|
156
144
|
|
157
|
-
raise
|
158
|
-
end
|
159
|
-
|
160
|
-
def create_transfer(amount, asset, destination)
|
161
|
-
create_transfer_request = {
|
162
|
-
amount: asset.to_atomic_amount(amount).to_i.to_s,
|
163
|
-
network_id: Coinbase.normalize_network(network_id),
|
164
|
-
asset_id: asset.primary_denomination.to_s,
|
165
|
-
destination: destination
|
166
|
-
}
|
167
|
-
|
168
|
-
transfer_model = Coinbase.call_api do
|
169
|
-
transfers_api.create_transfer(wallet_id, id, create_transfer_request)
|
170
|
-
end
|
171
|
-
|
172
|
-
Coinbase::Transfer.new(transfer_model)
|
173
|
-
end
|
174
|
-
|
175
|
-
def broadcast_transfer(transfer, signed_payload)
|
176
|
-
transfer_model = Coinbase.call_api do
|
177
|
-
transfers_api.broadcast_transfer(wallet_id, id, transfer.id, { signed_payload: signed_payload })
|
178
|
-
end
|
179
|
-
|
180
|
-
Coinbase::Transfer.new(transfer_model)
|
181
|
-
end
|
182
|
-
|
183
|
-
def validate_can_trade!(amount, from_asset)
|
184
|
-
raise 'Cannot trade from address without private key loaded' unless can_sign?
|
185
|
-
|
186
|
-
current_balance = balance(from_asset.asset_id)
|
187
|
-
|
188
|
-
return unless current_balance < amount
|
189
|
-
|
190
|
-
raise ArgumentError, "Insufficient funds: #{amount} requested, but only #{current_balance} available"
|
191
|
-
end
|
192
|
-
|
193
|
-
def create_trade(amount, from_asset, to_asset)
|
194
|
-
create_trade_request = {
|
195
|
-
amount: from_asset.to_atomic_amount(amount).to_i.to_s,
|
196
|
-
from_asset_id: from_asset.primary_denomination.to_s,
|
197
|
-
to_asset_id: to_asset.primary_denomination.to_s
|
198
|
-
}
|
199
|
-
|
200
|
-
trade_model = Coinbase.call_api do
|
201
|
-
trades_api.create_trade(wallet_id, id, create_trade_request)
|
202
|
-
end
|
203
|
-
|
204
|
-
Coinbase::Trade.new(trade_model)
|
205
|
-
end
|
206
|
-
|
207
|
-
def broadcast_trade(trade, signed_payload:, approve_tx_signed_payload: nil)
|
208
|
-
req = { signed_payload: signed_payload }
|
209
|
-
|
210
|
-
req[:approve_transaction_signed_payload] = approve_tx_signed_payload unless approve_tx_signed_payload.nil?
|
211
|
-
|
212
|
-
trade_model = Coinbase.call_api do
|
213
|
-
trades_api.broadcast_trade(wallet_id, id, trade.id, req)
|
214
|
-
end
|
215
|
-
|
216
|
-
Coinbase::Trade.new(trade_model)
|
145
|
+
raise InsufficientFundsError.new(amount, current_balance)
|
217
146
|
end
|
218
147
|
end
|
219
148
|
end
|
data/lib/coinbase/constants.rb
CHANGED
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Coinbase
|
4
|
+
# A representation of the intended recipient of an onchain interaction. For example, a simple
|
5
|
+
# Transfer has a single destination, which is the address that will receive the transferred funds.
|
6
|
+
# This class is used to handle the several different types that we can use as a destination,
|
7
|
+
# namely a Coinbase::Wallet, a Coinbase::Address, a String.
|
8
|
+
# This also ensures that the destination is valid for the network that is being interacted with.
|
9
|
+
# If a Coinbase::Wallet is used, the default address of the wallet is used as the destination.
|
10
|
+
# If a Coinbase::Address is used, the address ID is used as the destination.
|
11
|
+
# If a String is used, the string is used as the destination.
|
12
|
+
# If an existing Coinbase::Destination is used, the same address ID is used as the destination.
|
13
|
+
class Destination
|
14
|
+
# Returns a new Destination object.
|
15
|
+
# @param model [Coinbase::Destination, Coinbase::Wallet, Coinbase::Address, String]
|
16
|
+
# The object which the `address_id` will be derived from.
|
17
|
+
# If the destination is a Destination, it uses the same address ID.
|
18
|
+
# If the destination is a Wallet, it uses the default Address of the Wallet.
|
19
|
+
# If the destination is an Address, it uses the Address's ID.
|
20
|
+
# If the destination is a String, it uses it as the Address ID.
|
21
|
+
# @param network_id [Symbol] The ID of the Network to which the Destination belongs
|
22
|
+
# @return [Destination] The Destination object
|
23
|
+
def initialize(model, network_id: nil)
|
24
|
+
case model
|
25
|
+
when Coinbase::Destination
|
26
|
+
raise ArgumentError, 'destination network must match destination' unless model.network_id == network_id
|
27
|
+
|
28
|
+
@address_id = model.address_id
|
29
|
+
@network_id = model.network_id
|
30
|
+
when Coinbase::Wallet
|
31
|
+
raise ArgumentError, 'destination network must match wallet' unless model.network_id == network_id
|
32
|
+
raise ArgumentError, 'destination wallet must have default address' if model.default_address.nil?
|
33
|
+
|
34
|
+
@address_id = model.default_address.id
|
35
|
+
@network_id = model.network_id
|
36
|
+
when Coinbase::Address
|
37
|
+
raise ArgumentError, 'destination network must match address' unless model.network_id == network_id
|
38
|
+
|
39
|
+
@address_id = model.id
|
40
|
+
@network_id = model.network_id
|
41
|
+
when String
|
42
|
+
@address_id = model
|
43
|
+
@network_id = network_id
|
44
|
+
else
|
45
|
+
raise ArgumentError, "unsupported destination type: #{model.class}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
attr_reader :address_id, :network_id
|
50
|
+
end
|
51
|
+
end
|
data/lib/coinbase/errors.rb
CHANGED
@@ -63,6 +63,20 @@ module Coinbase
|
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
66
|
+
# An error raised when a transaction is not signed.
|
67
|
+
class TransactionNotSignedError < StandardError
|
68
|
+
def initialize(msg = 'Transaction must be signed')
|
69
|
+
super(msg)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# An error raised when an address attempts to sign a transaction without a private key.
|
74
|
+
class AddressCannotSignError < StandardError
|
75
|
+
def initialize(msg = 'Address cannot sign transaction without private key loaded')
|
76
|
+
super(msg)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
66
80
|
class UnimplementedError < APIError; end
|
67
81
|
class UnauthorizedError < APIError; end
|
68
82
|
class InternalError < APIError; end
|
data/lib/coinbase/trade.rb
CHANGED
@@ -9,6 +9,57 @@ module Coinbase
|
|
9
9
|
# The fee is assumed to be paid in the native Asset of the Network.
|
10
10
|
# Trades should be created through Wallet#trade or # Address#trade.
|
11
11
|
class Trade
|
12
|
+
class << self
|
13
|
+
# Creates a new Trade object.
|
14
|
+
# @param address_id [String] The Address ID of the sending Address
|
15
|
+
# @param from_asset_id [Symbol] The Asset ID of the Asset to trade from
|
16
|
+
# @param to_asset_id [Symbol] The Asset ID of the Asset to trade to
|
17
|
+
# @param amount [BigDecimal] The amount of the Asset to send
|
18
|
+
# @param network_id [Symbol] The Network ID of the Asset
|
19
|
+
# @param wallet_id [String] The Wallet ID of the sending Wallet
|
20
|
+
# @return [Send] The new pending Send object
|
21
|
+
def create(address_id:, from_asset_id:, to_asset_id:, amount:, network_id:, wallet_id:)
|
22
|
+
from_asset = Asset.fetch(network_id, from_asset_id)
|
23
|
+
to_asset = Asset.fetch(network_id, to_asset_id)
|
24
|
+
|
25
|
+
model = Coinbase.call_api do
|
26
|
+
trades_api.create_trade(
|
27
|
+
wallet_id,
|
28
|
+
address_id,
|
29
|
+
{
|
30
|
+
amount: from_asset.to_atomic_amount(amount).to_i.to_s,
|
31
|
+
from_asset_id: from_asset.primary_denomination.to_s,
|
32
|
+
to_asset_id: to_asset.primary_denomination.to_s
|
33
|
+
}
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
new(model)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Enumerates the trades for a given address belonging to a wallet.
|
41
|
+
# The result is an enumerator that lazily fetches from the server, and can be iterated over,
|
42
|
+
# converted to an array, etc...
|
43
|
+
# @return [Enumerable<Coinbase::Trade>] Enumerator that returns trades
|
44
|
+
def list(wallet_id:, address_id:)
|
45
|
+
Coinbase::Pagination.enumerate(
|
46
|
+
->(page) { fetch_page(wallet_id, address_id, page) }
|
47
|
+
) do |trade|
|
48
|
+
new(trade)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def trades_api
|
55
|
+
Coinbase::Client::TradesApi.new(Coinbase.configuration.api_client)
|
56
|
+
end
|
57
|
+
|
58
|
+
def fetch_page(wallet_id, address_id, page)
|
59
|
+
trades_api.list_trades(wallet_id, address_id, { limit: DEFAULT_PAGE_LIMIT, page: page })
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
12
63
|
# Returns a new Trade object. Do not use this method directly. Instead, use Wallet#trade or
|
13
64
|
# Address#trade.
|
14
65
|
# @param model [Coinbase::Client::Trade] The underlying Trade object
|
@@ -76,12 +127,37 @@ module Coinbase
|
|
76
127
|
@approve_transaction ||= @model.approve_transaction ? Coinbase::Transaction.new(@model.approve_transaction) : nil
|
77
128
|
end
|
78
129
|
|
130
|
+
# Returns the list of Transactions for the Trade.
|
131
|
+
def transactions
|
132
|
+
[approve_transaction, transaction].compact
|
133
|
+
end
|
134
|
+
|
79
135
|
# Returns the status of the Trade.
|
80
136
|
# @return [Symbol] The status
|
81
137
|
def status
|
82
138
|
transaction.status
|
83
139
|
end
|
84
140
|
|
141
|
+
# Broadcasts the Trade to the Network.
|
142
|
+
# This raises an error if the Trade is not signed.
|
143
|
+
# @raise [RuntimeError] If the Trade is not signed
|
144
|
+
# @return [Trade] The Trade object
|
145
|
+
def broadcast!
|
146
|
+
raise TransactionNotSignedError unless transactions.all?(&:signed?)
|
147
|
+
|
148
|
+
payloads = { signed_payload: transaction.raw.hex }
|
149
|
+
|
150
|
+
payloads[:approve_tx_signed_payload] = approve_transaction.raw.hex unless approve_transaction.nil?
|
151
|
+
|
152
|
+
@model = Coinbase.call_api do
|
153
|
+
trades_api.broadcast_trade(wallet_id, address_id, id, payloads)
|
154
|
+
end
|
155
|
+
|
156
|
+
update_transactions(@model)
|
157
|
+
|
158
|
+
self
|
159
|
+
end
|
160
|
+
|
85
161
|
# Waits until the Trade is completed or failed by polling the Network at the given interval. Raises a
|
86
162
|
# Timeout::Error if the Trade takes longer than the given timeout.
|
87
163
|
# @param interval_seconds [Integer] The interval at which to poll the Network, in seconds
|
@@ -114,11 +190,7 @@ module Coinbase
|
|
114
190
|
trades_api.get_trade(wallet_id, address_id, id)
|
115
191
|
end
|
116
192
|
|
117
|
-
|
118
|
-
@transaction = Coinbase::Transaction.new(@model.transaction)
|
119
|
-
|
120
|
-
# Update the memoized approve transaction if it exists.
|
121
|
-
@approve_transaction = @model.approve_transaction ? Coinbase::Transaction.new(@model.approve_transaction) : nil
|
193
|
+
update_transactions(@model)
|
122
194
|
|
123
195
|
self
|
124
196
|
end
|
@@ -140,6 +212,16 @@ module Coinbase
|
|
140
212
|
|
141
213
|
private
|
142
214
|
|
215
|
+
def update_transactions(model)
|
216
|
+
# Update the memoized transaction.
|
217
|
+
@transaction = Coinbase::Transaction.new(model.transaction)
|
218
|
+
|
219
|
+
return if model.approve_transaction.nil?
|
220
|
+
|
221
|
+
# Update the memoized approve transaction if it exists.
|
222
|
+
@approve_transaction = Coinbase::Transaction.new(model.approve_transaction)
|
223
|
+
end
|
224
|
+
|
143
225
|
def trades_api
|
144
226
|
@trades_api ||= Coinbase::Client::TradesApi.new(Coinbase.configuration.api_client)
|
145
227
|
end
|
data/lib/coinbase/transaction.rb
CHANGED
@@ -15,6 +15,9 @@ module Coinbase
|
|
15
15
|
# At this point, transaction hashes may not yet be assigned.
|
16
16
|
PENDING = 'pending'
|
17
17
|
|
18
|
+
# The Transaction has been signed, but has not been successfully broadcast yet.
|
19
|
+
SIGNED = 'signed'
|
20
|
+
|
18
21
|
# The Transaction has been broadcast to the Network.
|
19
22
|
# At this point, at least the transaction hash should be assigned.
|
20
23
|
BROADCAST = 'broadcast'
|
@@ -84,6 +87,14 @@ module Coinbase
|
|
84
87
|
def raw
|
85
88
|
return @raw unless @raw.nil?
|
86
89
|
|
90
|
+
# If the transaction is signed, decode the signed payload.
|
91
|
+
unless signed_payload.nil?
|
92
|
+
@raw = Eth::Tx::Eip1559.decode(signed_payload)
|
93
|
+
|
94
|
+
return @raw
|
95
|
+
end
|
96
|
+
|
97
|
+
# If the transaction is unsigned, parse the unsigned payload into an EIP-1559 transaction.
|
87
98
|
raw_payload = [unsigned_payload].pack('H*')
|
88
99
|
parsed_payload = JSON.parse(raw_payload)
|
89
100
|
|
@@ -93,8 +104,8 @@ module Coinbase
|
|
93
104
|
priority_fee: parsed_payload['maxPriorityFeePerGas'].to_i(16),
|
94
105
|
max_gas_fee: parsed_payload['maxFeePerGas'].to_i(16),
|
95
106
|
gas_limit: parsed_payload['gas'].to_i(16), # TODO: Handle multiple currencies.
|
96
|
-
from:
|
97
|
-
to:
|
107
|
+
from: from_address_id,
|
108
|
+
to: parsed_payload['to'],
|
98
109
|
value: parsed_payload['value'].to_i(16),
|
99
110
|
data: parsed_payload['input'] || ''
|
100
111
|
}
|
data/lib/coinbase/transfer.rb
CHANGED
@@ -11,6 +11,62 @@ module Coinbase
|
|
11
11
|
# in the native Asset of the Network. Transfers should be created through Wallet#transfer or
|
12
12
|
# Address#transfer.
|
13
13
|
class Transfer
|
14
|
+
class << self
|
15
|
+
# Creates a new Transfer object.
|
16
|
+
# @param address_id [String] The Address ID of the sending Address
|
17
|
+
# @param amount [BigDecimal] The amount of the Asset to send
|
18
|
+
# @param asset_id [Symbol] The Asset ID of the Asset to send
|
19
|
+
# @param destination [Coinbase::Destination, Coinbase::Wallet, Coinbase::Address, String]
|
20
|
+
# The destination of the transfer.
|
21
|
+
# If the destination is a Wallet, it uses the default Address of the Wallet.
|
22
|
+
# If the destination is an Address, it uses the Address's ID.
|
23
|
+
# If the destination is a String, it uses it as the Address ID.
|
24
|
+
# @param network_id [Symbol] The Network ID of the Asset
|
25
|
+
# @param wallet_id [String] The Wallet ID of the sending Wallet
|
26
|
+
# @return [Transfer] The new pending Transfer object
|
27
|
+
# @raise [Coinbase::ApiError] If the Transfer fails
|
28
|
+
def create(address_id:, amount:, asset_id:, destination:, network_id:, wallet_id:)
|
29
|
+
asset = Asset.fetch(network_id, asset_id)
|
30
|
+
|
31
|
+
model = Coinbase.call_api do
|
32
|
+
transfers_api.create_transfer(
|
33
|
+
wallet_id,
|
34
|
+
address_id,
|
35
|
+
{
|
36
|
+
amount: asset.to_atomic_amount(amount).to_i.to_s,
|
37
|
+
asset_id: asset.primary_denomination.to_s,
|
38
|
+
destination: Coinbase::Destination.new(destination, network_id: network_id).address_id,
|
39
|
+
network_id: Coinbase.normalize_network(network_id)
|
40
|
+
}
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
new(model)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Enumerates the transfers for a given address belonging to a wallet.
|
48
|
+
# The result is an enumerator that lazily fetches from the server, and can be iterated over,
|
49
|
+
# converted to an array, etc...
|
50
|
+
# @return [Enumerable<Coinbase::Transfer>] Enumerator that returns transfers
|
51
|
+
def list(wallet_id:, address_id:)
|
52
|
+
Coinbase::Pagination.enumerate(
|
53
|
+
->(page) { fetch_page(wallet_id, address_id, page) }
|
54
|
+
) do |transfer|
|
55
|
+
new(transfer)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def transfers_api
|
62
|
+
Coinbase::Client::TransfersApi.new(Coinbase.configuration.api_client)
|
63
|
+
end
|
64
|
+
|
65
|
+
def fetch_page(wallet_id, address_id, page)
|
66
|
+
transfers_api.list_transfers(wallet_id, address_id, { limit: DEFAULT_PAGE_LIMIT, page: page })
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
14
70
|
# Returns a new Transfer object. Do not use this method directly. Instead, use Wallet#transfer or
|
15
71
|
# Address#transfer.
|
16
72
|
# @param model [Coinbase::Client::Transfer] The underlying Transfer object
|
@@ -103,6 +159,27 @@ module Coinbase
|
|
103
159
|
transaction.status
|
104
160
|
end
|
105
161
|
|
162
|
+
# Broadcasts the Transfer to the Network.
|
163
|
+
# This raises an error if the Transfer is not signed.
|
164
|
+
# @raise [RuntimeError] If the Transfer is not signed
|
165
|
+
# @return [Transfer] The Transfer object
|
166
|
+
def broadcast!
|
167
|
+
raise TransactionNotSignedError unless transaction.signed?
|
168
|
+
|
169
|
+
@model = Coinbase.call_api do
|
170
|
+
transfers_api.broadcast_transfer(
|
171
|
+
wallet_id,
|
172
|
+
from_address_id,
|
173
|
+
id,
|
174
|
+
{ signed_payload: transaction.raw.hex }
|
175
|
+
)
|
176
|
+
end
|
177
|
+
|
178
|
+
update_transaction(@model)
|
179
|
+
|
180
|
+
self
|
181
|
+
end
|
182
|
+
|
106
183
|
# Reload reloads the Transfer model with the latest version from the server side.
|
107
184
|
# @return [Transfer] The most recent version of Transfer from the server.
|
108
185
|
def reload
|
@@ -110,8 +187,7 @@ module Coinbase
|
|
110
187
|
transfers_api.get_transfer(wallet_id, from_address_id, id)
|
111
188
|
end
|
112
189
|
|
113
|
-
|
114
|
-
@transaction = Coinbase::Transaction.new(@model.transaction)
|
190
|
+
update_transaction(@model)
|
115
191
|
|
116
192
|
self
|
117
193
|
end
|
@@ -157,5 +233,9 @@ module Coinbase
|
|
157
233
|
def transfers_api
|
158
234
|
@transfers_api ||= Coinbase::Client::TransfersApi.new(Coinbase.configuration.api_client)
|
159
235
|
end
|
236
|
+
|
237
|
+
def update_transaction(model)
|
238
|
+
@transaction = Coinbase::Transaction.new(model.transaction)
|
239
|
+
end
|
160
240
|
end
|
161
241
|
end
|
data/lib/coinbase/wallet.rb
CHANGED
@@ -13,9 +13,6 @@ module Coinbase
|
|
13
13
|
# The maximum number of addresses in a Wallet.
|
14
14
|
MAX_ADDRESSES = 20
|
15
15
|
|
16
|
-
# The maximum number of wallets to fetch in a single page.
|
17
|
-
PAGE_LIMIT = 100
|
18
|
-
|
19
16
|
# A representation of ServerSigner status in a Wallet.
|
20
17
|
module ServerSignerStatus
|
21
18
|
# The Wallet is awaiting seed creation by the ServerSigner. At this point,
|
@@ -131,7 +128,7 @@ module Coinbase
|
|
131
128
|
end
|
132
129
|
|
133
130
|
def fetch_wallets_page(page)
|
134
|
-
wallets_api.list_wallets({ limit:
|
131
|
+
wallets_api.list_wallets({ limit: DEFAULT_PAGE_LIMIT, page: page })
|
135
132
|
end
|
136
133
|
end
|
137
134
|
|
data/lib/coinbase.rb
CHANGED
@@ -9,6 +9,7 @@ require_relative 'coinbase/balance'
|
|
9
9
|
require_relative 'coinbase/balance_map'
|
10
10
|
require_relative 'coinbase/client'
|
11
11
|
require_relative 'coinbase/constants'
|
12
|
+
require_relative 'coinbase/destination'
|
12
13
|
require_relative 'coinbase/errors'
|
13
14
|
require_relative 'coinbase/faucet_transaction'
|
14
15
|
require_relative 'coinbase/middleware'
|
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.13
|
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-07-
|
11
|
+
date: 2024-07-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bigdecimal
|
@@ -301,6 +301,7 @@ files:
|
|
301
301
|
- lib/coinbase/client/models/wallet_list.rb
|
302
302
|
- lib/coinbase/client/version.rb
|
303
303
|
- lib/coinbase/constants.rb
|
304
|
+
- lib/coinbase/destination.rb
|
304
305
|
- lib/coinbase/errors.rb
|
305
306
|
- lib/coinbase/faucet_transaction.rb
|
306
307
|
- lib/coinbase/middleware.rb
|