glueby 1.1.1 → 1.2.0.beta.1
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/.github/workflows/ruby.yml +4 -4
- data/.ruby-version +1 -1
- data/README.md +1 -1
- data/glueby.gemspec +3 -3
- data/lib/generators/glueby/contract/templates/initializer.rb.erb +8 -8
- data/lib/generators/glueby/contract/templates/key_table.rb.erb +16 -16
- data/lib/glueby/block_syncer.rb +97 -97
- data/lib/glueby/contract/active_record/timestamp.rb +0 -3
- data/lib/glueby/contract/payment.rb +10 -15
- data/lib/glueby/contract/timestamp/tx_builder/simple.rb +19 -57
- data/lib/glueby/contract/timestamp/tx_builder/trackable.rb +6 -0
- data/lib/glueby/contract/timestamp/tx_builder/updating_trackable.rb +3 -2
- data/lib/glueby/contract/token.rb +163 -86
- data/lib/glueby/contract/tx_builder.rb +1 -0
- data/lib/glueby/internal/contract_builder.rb +462 -0
- data/lib/glueby/internal/wallet/abstract_wallet_adapter.rb +11 -0
- data/lib/glueby/internal/wallet/active_record/utxo.rb +3 -2
- data/lib/glueby/internal/wallet/active_record_wallet_adapter.rb +30 -0
- data/lib/glueby/internal/wallet.rb +151 -10
- data/lib/glueby/internal.rb +1 -0
- data/lib/glueby/utxo_provider/tasks.rb +0 -2
- data/lib/glueby/utxo_provider.rb +15 -34
- data/lib/glueby/version.rb +1 -1
- data/lib/tasks/glueby/contract/timestamp.rake +0 -1
- metadata +14 -13
@@ -0,0 +1,462 @@
|
|
1
|
+
module Glueby
|
2
|
+
module Internal
|
3
|
+
class ContractBuilder < Tapyrus::TxBuilder
|
4
|
+
attr_reader :fee_estimator, :sender_wallet, :prev_txs, :p2c_utxos, :use_unfinalized_utxo, :use_auto_fulfill_inputs
|
5
|
+
|
6
|
+
# @param [Glueby::Internal::Wallet] sender_wallet The wallet that is an user's wallet who send the transaction
|
7
|
+
# to a blockchain.
|
8
|
+
# @param [Symbol|Glueby::Contract::FeeEstimator] fee_estimator :auto or :fixed
|
9
|
+
# @param [Boolean] use_auto_fulfill_inputs
|
10
|
+
# If it's true, inputs are automatically added up to fulfill the TPC and tokens requirement that is added by
|
11
|
+
# #pay and #burn. The option also support to fill adding TPC inputs for paying fee.
|
12
|
+
# If Glueby.configuration.use_utxo_provider? is true, All the TPC inputs are added from the UtxoProvider's
|
13
|
+
# wallet. It it's false, all the TPC inputs are from sender_wallet.
|
14
|
+
# If Glueby.configuration.fee_provider_bears? is true, it won't add TPC amount for fee.
|
15
|
+
# @param [Boolean] use_unfinalized_utxo If it's true, The ContractBuilder use unfinalized UTXO that is not
|
16
|
+
# included in the block in its inputs.
|
17
|
+
# @raise [Glueby::ArgumentError] If the fee_estimator is not :auto or :fixed
|
18
|
+
def initialize(
|
19
|
+
sender_wallet:,
|
20
|
+
fee_estimator: :auto,
|
21
|
+
use_auto_fulfill_inputs: false,
|
22
|
+
use_unfinalized_utxo: false
|
23
|
+
)
|
24
|
+
@sender_wallet = sender_wallet
|
25
|
+
set_fee_estimator(fee_estimator)
|
26
|
+
@use_auto_fulfill_inputs = use_auto_fulfill_inputs
|
27
|
+
@use_unfinalized_utxo = use_unfinalized_utxo
|
28
|
+
@p2c_utxos = []
|
29
|
+
@prev_txs = []
|
30
|
+
@change_script_pubkeys = {}
|
31
|
+
@burn_contract = false
|
32
|
+
@issues = Hash.new(0)
|
33
|
+
super()
|
34
|
+
end
|
35
|
+
|
36
|
+
# Issue reissuable token
|
37
|
+
# @param script_pubkey [Tapyrus::Script] the script pubkey in the issue input.
|
38
|
+
# @param address [String] p2pkh or p2sh address.
|
39
|
+
# @param value [Integer] issued amount.
|
40
|
+
def reissuable(script_pubkey, address, value)
|
41
|
+
color_id = Tapyrus::Color::ColorIdentifier.reissuable(script_pubkey)
|
42
|
+
@issues[color_id] += value
|
43
|
+
super
|
44
|
+
end
|
45
|
+
|
46
|
+
# Issue reissuable token to the split outputs
|
47
|
+
# @param [Tapyrus::Script] script_pubkey The color id is generate from this script pubkey
|
48
|
+
# @param [String] address The address that is the token is sent to
|
49
|
+
# @param [Integer] value The issue amount of the token
|
50
|
+
# @param [Integer] split The number of the split outputs
|
51
|
+
def reissuable_split(script_pubkey, address, value, split)
|
52
|
+
split_value(value, split) do |value|
|
53
|
+
reissuable(script_pubkey, address, value)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Issue non reissuable token
|
58
|
+
# @param out_point [Tapyrus::OutPoint] the out point at issue input.
|
59
|
+
# @param address [String] p2pkh or p2sh address.
|
60
|
+
# @param value [Integer] issued amount.
|
61
|
+
def non_reissuable(out_point, address, value)
|
62
|
+
color_id = Tapyrus::Color::ColorIdentifier.non_reissuable(out_point)
|
63
|
+
@issues[color_id] += value
|
64
|
+
super
|
65
|
+
end
|
66
|
+
|
67
|
+
# Issue non-reissuable token to the split outputs
|
68
|
+
# @param [Tapyrus::OutPoint] out_point The outpoint of the reissuable token
|
69
|
+
# @param [String] address The address that is the token is sent to
|
70
|
+
# @param [Integer] value The issue amount of the token
|
71
|
+
# @param [Integer] split The number of the split outputs
|
72
|
+
def non_reissuable_split(out_point, address, value, split)
|
73
|
+
split_value(value, split) do |value|
|
74
|
+
non_reissuable(out_point, address, value)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Issue NFT
|
79
|
+
# @param out_point [Tapyrus::OutPoint] the out point at issue input.
|
80
|
+
# @param address [String] p2pkh or p2sh address.
|
81
|
+
# @raise [Glueby::ArgumentError] If the NFT is already issued in this contract builder.
|
82
|
+
def nft(out_point, address)
|
83
|
+
color_id = Tapyrus::Color::ColorIdentifier.nft(out_point)
|
84
|
+
raise Glueby::ArgumentError, 'NFT is already issued.' if @issues[color_id] == 1
|
85
|
+
@issues[color_id] = 1
|
86
|
+
super
|
87
|
+
end
|
88
|
+
|
89
|
+
# Burn token
|
90
|
+
# @param [Integer] value The burn amount of the token
|
91
|
+
# @param [Tapyrus::Color::ColorIdentifier] color_id The color id of the token
|
92
|
+
# @raise [Glueby::ArgumentError] If the color_id is default color id
|
93
|
+
def burn(value, color_id)
|
94
|
+
raise Glueby::ArgumentError, 'Burn TPC is not supported.' if color_id.default?
|
95
|
+
|
96
|
+
@burn_contract = true
|
97
|
+
@outgoings[color_id] ||= 0
|
98
|
+
@outgoings[color_id] += value
|
99
|
+
self
|
100
|
+
end
|
101
|
+
|
102
|
+
# Add utxo to the transaction
|
103
|
+
# @param [Hash] utxo The utxo to add
|
104
|
+
# @option utxo [String] :txid The txid
|
105
|
+
# @option utxo [Integer] :vout The index of the output in the tx
|
106
|
+
# @option utxo [Integer] :amount The value of the output
|
107
|
+
# @option utxo [String] :script_pubkey The hex string of the script pubkey
|
108
|
+
# @option utxo [String] :color_id The color id hex string of the output
|
109
|
+
def add_utxo(utxo)
|
110
|
+
super(to_tapyrusrb_utxo_hash(utxo))
|
111
|
+
self
|
112
|
+
end
|
113
|
+
|
114
|
+
# Add an UTXO which is sent to the address
|
115
|
+
# If the configuration is set to use UTXO provider, the UTXO is provided by the UTXO provider.
|
116
|
+
# Otherwise, the UTXO is provided by the wallet. In this case, the address parameter is ignored.
|
117
|
+
# This method creates and broadcasts a transaction that sends the amount to the address and add the UTXO
|
118
|
+
# to the transaction.
|
119
|
+
# @param [String] address The address that is the UTXO is sent to
|
120
|
+
# @param [Integer] amount The amount of the UTXO
|
121
|
+
# @param [Glueby::Internal::UtxoProvider] utxo_provider The UTXO provider
|
122
|
+
# @param [Boolean] only_finalized If true, the UTXO is provided from the finalized UTXO set. It is ignored if the configuration is set to use UTXO provider.
|
123
|
+
# @param [Glueby::Contract::FeeEstimator] fee_estimator It estimate fee for prev tx. It is ignored if the configuration is set to use UTXO provider.
|
124
|
+
def add_utxo_to!(
|
125
|
+
address:,
|
126
|
+
amount:,
|
127
|
+
utxo_provider: nil,
|
128
|
+
only_finalized: use_only_finalized_utxo,
|
129
|
+
fee_estimator: nil
|
130
|
+
)
|
131
|
+
tx, index = nil
|
132
|
+
|
133
|
+
if Glueby.configuration.use_utxo_provider? || utxo_provider
|
134
|
+
utxo_provider ||= UtxoProvider.instance
|
135
|
+
script_pubkey = Tapyrus::Script.parse_from_addr(address)
|
136
|
+
tx, index = utxo_provider.get_utxo(script_pubkey, amount)
|
137
|
+
else
|
138
|
+
fee_estimator ||= @fee_estimator
|
139
|
+
txb = Tapyrus::TxBuilder.new
|
140
|
+
fee = fee_estimator.fee(Contract::FeeEstimator.dummy_tx(txb.build))
|
141
|
+
_sum, utxos = sender_wallet
|
142
|
+
.collect_uncolored_outputs(fee + amount, nil, only_finalized)
|
143
|
+
utxos.each { |utxo| txb.add_utxo(to_tapyrusrb_utxo_hash(utxo)) }
|
144
|
+
tx = txb.pay(address, amount)
|
145
|
+
.change_address(sender_wallet.change_address)
|
146
|
+
.fee(fee)
|
147
|
+
.build
|
148
|
+
sender_wallet.sign_tx(tx)
|
149
|
+
index = 0
|
150
|
+
end
|
151
|
+
|
152
|
+
ActiveRecord::Base.transaction(joinable: false, requires_new: true) do
|
153
|
+
# Here needs to use the return tx from Internal::Wallet#broadcast because the txid
|
154
|
+
# is changed if you enable FeeProvider.
|
155
|
+
tx = sender_wallet.broadcast(tx)
|
156
|
+
end
|
157
|
+
|
158
|
+
@prev_txs << tx
|
159
|
+
|
160
|
+
add_utxo({
|
161
|
+
script_pubkey: tx.outputs[index].script_pubkey.to_hex,
|
162
|
+
txid: tx.txid,
|
163
|
+
vout: index,
|
164
|
+
amount: tx.outputs[index].value
|
165
|
+
})
|
166
|
+
self
|
167
|
+
end
|
168
|
+
|
169
|
+
# Add an UTXO which is sent to the pay-to-contract address which is generated from the metadata
|
170
|
+
# @param [String] metadata The metadata of the pay-to-contract address
|
171
|
+
# @param [Integer] amount The amount of the UTXO
|
172
|
+
# @param [String] p2c_address The pay-to-contract address. You can use this parameter if you want to create an
|
173
|
+
# UTXO to before created address. It must be use with payment_base parameter.
|
174
|
+
# @param [String] payment_base The payment base of the pay-to-contract address. It should be compressed public
|
175
|
+
# key format. It must be use with p2c_address parameter.
|
176
|
+
# @param [Boolean] only_finalized If true, the UTXO is provided from the finalized UTXO set. It is ignored if the configuration is set to use UTXO provider.
|
177
|
+
# @param [Glueby::Contract::FeeEstimator] fee_estimator It estimate fee for prev tx. It is ignored if the configuration is set to use UTXO provider.
|
178
|
+
def add_p2c_utxo_to!(
|
179
|
+
metadata:,
|
180
|
+
amount:,
|
181
|
+
p2c_address: nil,
|
182
|
+
payment_base: nil,
|
183
|
+
only_finalized: use_only_finalized_utxo,
|
184
|
+
fee_estimator: nil
|
185
|
+
)
|
186
|
+
if p2c_address.nil? || payment_base.nil?
|
187
|
+
p2c_address, payment_base = sender_wallet
|
188
|
+
.create_pay_to_contract_address(metadata)
|
189
|
+
end
|
190
|
+
|
191
|
+
add_utxo_to!(
|
192
|
+
address: p2c_address,
|
193
|
+
amount: amount,
|
194
|
+
only_finalized: only_finalized,
|
195
|
+
fee_estimator: fee_estimator
|
196
|
+
)
|
197
|
+
@p2c_utxos << to_p2c_sign_tx_utxo_hash(@utxos.last)
|
198
|
+
.merge({
|
199
|
+
p2c_address: p2c_address,
|
200
|
+
payment_base: payment_base,
|
201
|
+
metadata: metadata
|
202
|
+
})
|
203
|
+
self
|
204
|
+
end
|
205
|
+
|
206
|
+
alias :original_build :build
|
207
|
+
def build
|
208
|
+
auto_fulfill_inputs_utxos_for_color if use_auto_fulfill_inputs
|
209
|
+
|
210
|
+
tx = Tapyrus::Tx.new
|
211
|
+
set_tpc_change_address
|
212
|
+
expand_input(tx)
|
213
|
+
@outputs.each { |output| tx.outputs << output }
|
214
|
+
add_change_for_colored_coin(tx)
|
215
|
+
|
216
|
+
|
217
|
+
change, provided_utxos = auto_fulfill_inputs_utxos_for_tpc(tx) if use_auto_fulfill_inputs
|
218
|
+
add_change_for_tpc(tx, change)
|
219
|
+
|
220
|
+
add_dummy_output(tx)
|
221
|
+
sign(tx, provided_utxos)
|
222
|
+
end
|
223
|
+
|
224
|
+
def change_address(address, color_id = Tapyrus::Color::ColorIdentifier.default)
|
225
|
+
if color_id.default?
|
226
|
+
super(address)
|
227
|
+
else
|
228
|
+
script_pubkey = Tapyrus::Script.parse_from_addr(address)
|
229
|
+
raise ArgumentError, 'invalid address' if !script_pubkey.p2pkh? && !script_pubkey.p2sh?
|
230
|
+
@change_script_pubkeys[color_id] = script_pubkey.add_color(color_id)
|
231
|
+
end
|
232
|
+
self
|
233
|
+
end
|
234
|
+
|
235
|
+
private :fee
|
236
|
+
|
237
|
+
def dummy_fee
|
238
|
+
fee_estimator.fee(Contract::FeeEstimator.dummy_tx(original_build))
|
239
|
+
end
|
240
|
+
|
241
|
+
private
|
242
|
+
|
243
|
+
def estimated_fee
|
244
|
+
@fee ||= estimate_fee
|
245
|
+
end
|
246
|
+
|
247
|
+
def estimate_fee
|
248
|
+
tx = Tapyrus::Tx.new
|
249
|
+
expand_input(tx)
|
250
|
+
@outputs.each { |output| tx.outputs << output }
|
251
|
+
add_change_for_colored_coin(tx)
|
252
|
+
fee_estimator.fee(Contract::FeeEstimator.dummy_tx(tx))
|
253
|
+
end
|
254
|
+
|
255
|
+
def sign(tx, extra_utxos)
|
256
|
+
utxos = @utxos.map { |u| to_sign_tx_utxo_hash(u) } + (extra_utxos || [])
|
257
|
+
|
258
|
+
# Sign inputs from sender_wallet
|
259
|
+
tx = sender_wallet.sign_tx(tx, utxos)
|
260
|
+
|
261
|
+
# Sign inputs which is pay to contract output
|
262
|
+
@p2c_utxos.each do |utxo|
|
263
|
+
tx = sender_wallet
|
264
|
+
.sign_to_pay_to_contract_address(tx, utxo, utxo[:payment_base], utxo[:metadata])
|
265
|
+
end
|
266
|
+
|
267
|
+
# Sign inputs from UtxoProvider
|
268
|
+
Glueby::UtxoProvider.instance.wallet.sign_tx(tx, utxos) if Glueby.configuration.use_utxo_provider?
|
269
|
+
|
270
|
+
tx
|
271
|
+
end
|
272
|
+
|
273
|
+
def set_tpc_change_address
|
274
|
+
if Glueby.configuration.use_utxo_provider?
|
275
|
+
change_address(UtxoProvider.instance.wallet.change_address)
|
276
|
+
else
|
277
|
+
change_address(@sender_wallet.change_address)
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
def add_change_for_colored_coin(tx)
|
282
|
+
@incomings.each do |color_id, in_amount|
|
283
|
+
next if color_id.default?
|
284
|
+
|
285
|
+
out_amount = @outgoings[color_id] || 0
|
286
|
+
change = in_amount - out_amount
|
287
|
+
next if change <= 0
|
288
|
+
|
289
|
+
unless @change_script_pubkeys[color_id]
|
290
|
+
raise Glueby::ArgumentError, "The change address for color_id #{color_id.to_hex} must be set."
|
291
|
+
end
|
292
|
+
tx.outputs << Tapyrus::TxOut.new(script_pubkey: @change_script_pubkeys[color_id], value: change)
|
293
|
+
end
|
294
|
+
tx
|
295
|
+
end
|
296
|
+
|
297
|
+
def add_change_for_tpc(tx, change = nil)
|
298
|
+
raise Glueby::ArgumentError, "The change address for TPC must be set." unless @change_script_pubkey
|
299
|
+
change ||= begin
|
300
|
+
in_amount = @incomings[Tapyrus::Color::ColorIdentifier.default] || 0
|
301
|
+
out_amount = @outgoings[Tapyrus::Color::ColorIdentifier.default] || 0
|
302
|
+
|
303
|
+
in_amount - out_amount - estimated_fee
|
304
|
+
end
|
305
|
+
|
306
|
+
raise Contract::Errors::InsufficientFunds if change < 0
|
307
|
+
|
308
|
+
change_output = Tapyrus::TxOut.new(script_pubkey: @change_script_pubkey, value: change)
|
309
|
+
return tx if change_output.dust?
|
310
|
+
|
311
|
+
tx.outputs << change_output
|
312
|
+
|
313
|
+
tx
|
314
|
+
end
|
315
|
+
|
316
|
+
# @return [Integer] The TPC change amount
|
317
|
+
# @return [Array<Hash>] The provided UTXOs
|
318
|
+
def auto_fulfill_inputs_utxos_for_tpc(tx)
|
319
|
+
target_amount = @outgoings[Tapyrus::Color::ColorIdentifier.default] || 0
|
320
|
+
|
321
|
+
provider = if Glueby.configuration.use_utxo_provider?
|
322
|
+
UtxoProvider.instance
|
323
|
+
else
|
324
|
+
sender_wallet
|
325
|
+
end
|
326
|
+
|
327
|
+
_tx, fee, tpc_amount, provided_utxos = provider.fill_uncolored_inputs(
|
328
|
+
tx,
|
329
|
+
target_amount: target_amount,
|
330
|
+
current_amount: @incomings[Tapyrus::Color::ColorIdentifier.default] || 0,
|
331
|
+
fee_estimator: fee_estimator
|
332
|
+
)
|
333
|
+
|
334
|
+
change = tpc_amount - target_amount - fee
|
335
|
+
[change, provided_utxos]
|
336
|
+
end
|
337
|
+
|
338
|
+
def auto_fulfill_inputs_utxos_for_color
|
339
|
+
# fulfill colored inputs
|
340
|
+
@outgoings.each do |color_id, outgoing_amount|
|
341
|
+
next if color_id.default?
|
342
|
+
|
343
|
+
target_amount = outgoing_amount - (@incomings[color_id] || 0) - @issues[color_id]
|
344
|
+
next if target_amount <= 0
|
345
|
+
|
346
|
+
@sender_wallet.collect_colored_outputs(
|
347
|
+
color_id,
|
348
|
+
target_amount,
|
349
|
+
nil,
|
350
|
+
use_only_finalized_utxo,
|
351
|
+
true
|
352
|
+
)[1]
|
353
|
+
.each { |utxo| add_utxo(utxo) }
|
354
|
+
end
|
355
|
+
|
356
|
+
end
|
357
|
+
|
358
|
+
def get_fee_estimator(fee_estimator_name)
|
359
|
+
Glueby::Contract::FeeEstimator.get_const("#{fee_estimator_name.capitalize}", false).new
|
360
|
+
end
|
361
|
+
|
362
|
+
def valid_fee_estimator?(fee_estimator)
|
363
|
+
[:fixed, :auto].include?(fee_estimator)
|
364
|
+
end
|
365
|
+
|
366
|
+
def use_only_finalized_utxo
|
367
|
+
!use_unfinalized_utxo
|
368
|
+
end
|
369
|
+
|
370
|
+
# Set fee estimator
|
371
|
+
# @param [Symbol|Glueby::Contract::FeeEstimator] fee_estimator :auto or :fixed
|
372
|
+
def set_fee_estimator(fee_estimator)
|
373
|
+
if fee_estimator.is_a?(Symbol)
|
374
|
+
raise Glueby::ArgumentError, 'fee_estiamtor can be :fixed or :auto' unless valid_fee_estimator?(fee_estimator)
|
375
|
+
@fee_estimator = get_fee_estimator(fee_estimator)
|
376
|
+
else
|
377
|
+
@fee_estimator = fee_estimator
|
378
|
+
end
|
379
|
+
self
|
380
|
+
end
|
381
|
+
|
382
|
+
# Split the value into the number of split. The last value is added the remainder of the division.
|
383
|
+
# It call the block with the value of each split.
|
384
|
+
def split_value(value, split)
|
385
|
+
if value < split
|
386
|
+
split = value
|
387
|
+
split_value = 1
|
388
|
+
else
|
389
|
+
split_value = (value / split).to_i
|
390
|
+
end
|
391
|
+
(split - 1).times { yield(split_value) }
|
392
|
+
yield(value - split_value * (split - 1))
|
393
|
+
self
|
394
|
+
end
|
395
|
+
|
396
|
+
# If the tx has no output due to the contract creating a burn token, a dummy output should be added to make
|
397
|
+
# the transaction valid.
|
398
|
+
def add_dummy_output(tx)
|
399
|
+
if @burn_contract && tx.outputs.size == 0
|
400
|
+
|
401
|
+
tx.outputs << Tapyrus::TxOut.new(
|
402
|
+
value: 0,
|
403
|
+
script_pubkey: Tapyrus::Script.new << Tapyrus::Opcodes::OP_RETURN
|
404
|
+
)
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
408
|
+
# The UTXO format that is used in Tapyrus::TxBuilder
|
409
|
+
# @param utxo
|
410
|
+
# @option utxo [String] :txid The txid
|
411
|
+
# @option utxo [Integer] :vout The index of the output in the tx
|
412
|
+
# @option utxo [Integer] :amount The value of the output
|
413
|
+
# @option utxo [String] :script_pubkey The hex string of the script pubkey
|
414
|
+
# @option utxo [String] :color_id The hex string of the color id
|
415
|
+
def to_tapyrusrb_utxo_hash(utxo)
|
416
|
+
color_id = if utxo[:color_id]
|
417
|
+
Tapyrus::Color::ColorIdentifier.parse_from_payload(utxo[:color_id].htb)
|
418
|
+
else
|
419
|
+
Tapyrus::Color::ColorIdentifier.default
|
420
|
+
end
|
421
|
+
{
|
422
|
+
script_pubkey: Tapyrus::Script.parse_from_payload(utxo[:script_pubkey].htb),
|
423
|
+
txid: utxo[:txid],
|
424
|
+
index: utxo[:vout],
|
425
|
+
value: utxo[:amount],
|
426
|
+
color_id: color_id
|
427
|
+
}
|
428
|
+
end
|
429
|
+
|
430
|
+
# The UTXO format that is used in AbstractWalletAdapter#sign_tx
|
431
|
+
# @param utxo The return value of #to_tapyrusrb_utxo_hash
|
432
|
+
# @option utxo [String] :txid The txid
|
433
|
+
# @option utxo [Integer] :index The index of the output in the tx
|
434
|
+
# @option utxo [Integer] :amount The value of the output
|
435
|
+
# @option utxo [String] :script_pubkey The hex string of the script pubkey
|
436
|
+
def to_sign_tx_utxo_hash(utxo)
|
437
|
+
{
|
438
|
+
scriptPubKey: utxo[:script_pubkey].to_hex,
|
439
|
+
txid: utxo[:txid],
|
440
|
+
vout: utxo[:index],
|
441
|
+
amount: utxo[:value]
|
442
|
+
}
|
443
|
+
end
|
444
|
+
|
445
|
+
# The UTXO format that is used in AbstractWalletAdapter#sign_to_pay_to_contract_address
|
446
|
+
# @param utxo The return value of #to_tapyrusrb_utxo_hash
|
447
|
+
# @option utxo [String] :txid The txid
|
448
|
+
# @option utxo [Integer] :index The index of the output in the tx
|
449
|
+
# @option utxo [Integer] :amount The value of the output
|
450
|
+
# @option utxo [String] :script_pubkey The hex string of the script pubkey
|
451
|
+
def to_p2c_sign_tx_utxo_hash(utxo)
|
452
|
+
{
|
453
|
+
script_pubkey: utxo[:script_pubkey].to_hex,
|
454
|
+
txid: utxo[:txid],
|
455
|
+
vout: utxo[:index],
|
456
|
+
amount: utxo[:value]
|
457
|
+
}
|
458
|
+
end
|
459
|
+
end
|
460
|
+
end
|
461
|
+
end
|
462
|
+
|
@@ -82,6 +82,8 @@ module Glueby
|
|
82
82
|
# - vout: [Integer] Output index
|
83
83
|
# - amount: [Integer] Amount of the UTXO as tapyrus unit
|
84
84
|
# - finalized: [Boolean] Whether the UTXO is finalized
|
85
|
+
# - color_id: [String] Color id of the UTXO. If it is TPC UTXO, color_id is nil.
|
86
|
+
# - script_pubkey: [String] Script pubkey of the UTXO
|
85
87
|
def list_unspent(wallet_id, only_finalized = true, label = nil)
|
86
88
|
raise NotImplementedError, "You must implement #{self.class}##{__method__}"
|
87
89
|
end
|
@@ -135,6 +137,15 @@ module Glueby
|
|
135
137
|
raise NotImplementedError, "You must implement #{self.class}##{__method__}"
|
136
138
|
end
|
137
139
|
|
140
|
+
# Returns information for the addresses
|
141
|
+
#
|
142
|
+
# @param [String] address - The p2pkh address to get information about
|
143
|
+
# @return [Array<Hash>] The array of hash instance which has keys wallet_id, label and purpose.
|
144
|
+
# Returns blank array if the key correspond with the address is not exist.
|
145
|
+
def get_addresses_info(addresses)
|
146
|
+
raise NotImplementedError, "You must implement #{self.class}##{__method__}"
|
147
|
+
end
|
148
|
+
|
138
149
|
# Returns a new public key.
|
139
150
|
#
|
140
151
|
# This method is expected to returns a new public key. The key would generate internally. This key is provided
|
@@ -49,8 +49,9 @@ module Glueby
|
|
49
49
|
private
|
50
50
|
|
51
51
|
def check_dust_output
|
52
|
-
|
53
|
-
|
52
|
+
output = Tapyrus::TxOut.new(value: value, script_pubkey: Tapyrus::Script.parse_from_payload(script_pubkey.htb))
|
53
|
+
if !color_id && output.dust?
|
54
|
+
errors.add(:value, "is less than dust limit(#{output.send(:dust_threshold)})")
|
54
55
|
end
|
55
56
|
end
|
56
57
|
end
|
@@ -153,6 +153,36 @@ module Glueby
|
|
153
153
|
keys.map(&:address)
|
154
154
|
end
|
155
155
|
|
156
|
+
def get_addresses_info(addresses)
|
157
|
+
unless addresses.is_a?(Array)
|
158
|
+
addresses = [addresses]
|
159
|
+
end
|
160
|
+
|
161
|
+
script_pubkeys = addresses.map do |address|
|
162
|
+
Tapyrus::Script.parse_from_addr(address).to_hex
|
163
|
+
rescue ::ArgumentError => e
|
164
|
+
raise Glueby::ArgumentError, "\"#{address}\" is invalid address. #{e.message}"
|
165
|
+
rescue RuntimeError => e
|
166
|
+
if e.message == 'Invalid version bytes.' || e.message == 'Invalid address.'
|
167
|
+
raise Glueby::ArgumentError, "\"#{address}\" is invalid address. #{e.message}"
|
168
|
+
else
|
169
|
+
raise e
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
keys = AR::Key.where(script_pubkey: script_pubkeys)
|
174
|
+
keys.map do |key|
|
175
|
+
{
|
176
|
+
address: key.address,
|
177
|
+
public_key: key.public_key,
|
178
|
+
wallet_id: key.wallet.wallet_id,
|
179
|
+
label: key.label,
|
180
|
+
purpose: key.purpose,
|
181
|
+
script_pubkey: key.script_pubkey
|
182
|
+
}
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
156
186
|
def create_pay_to_contract_address(wallet_id, contents)
|
157
187
|
pubkey = create_pubkey(wallet_id)
|
158
188
|
[pay_to_contract_key(wallet_id, pubkey, contents).to_p2pkh, pubkey.pubkey]
|