glueby 1.1.2 → 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.
@@ -48,9 +48,6 @@ module Glueby
48
48
  # token.metadata
49
49
  # => "metadata"
50
50
  class Token
51
- include Glueby::Contract::TxBuilder
52
- extend Glueby::Contract::TxBuilder
53
-
54
51
  class << self
55
52
  # Issue new token with specified amount and token type.
56
53
  # REISSUABLE token can be reissued with #reissue! method, and
@@ -112,92 +109,132 @@ module Glueby
112
109
  end
113
110
 
114
111
  def issue_reissuable_token(issuer:, amount:, split: 1, fee_estimator:, metadata: nil)
115
- script, p2c_address, payment_base = create_p2c_address(issuer, metadata) if metadata
112
+ txb = Internal::ContractBuilder.new(
113
+ sender_wallet: issuer.internal_wallet,
114
+ fee_estimator: fee_estimator,
115
+ use_auto_fulfill_inputs: true
116
+ )
117
+
118
+ if metadata
119
+ txb.add_p2c_utxo_to!(
120
+ metadata: metadata,
121
+ amount: FeeEstimator::Fixed.new.fixed_fee,
122
+ only_finalized: only_finalized?,
123
+ fee_estimator: Contract::FeeEstimator::Fixed.new
124
+ )
125
+ else
126
+ txb.add_utxo_to!(
127
+ address: issuer.internal_wallet.receive_address,
128
+ amount: FeeEstimator::Fixed.new.fixed_fee,
129
+ only_finalized: only_finalized?,
130
+ fee_estimator: Contract::FeeEstimator::Fixed.new
131
+ )
132
+ end
116
133
 
117
- # For reissuable token, we need funding transaction for every issuance.
118
- # To make it easier for API users to understand whether a transaction is a new issue or a reissue,
119
- # when Token.issue! is executed, a new address is created and tpc is sent to it to ensure that it is a new issue,
120
- # and a transaction is created using that UTXO as input to create a new color_id.
121
- funding_tx = create_funding_tx(wallet: issuer, script: script, only_finalized: only_finalized?)
134
+ funding_tx = txb.prev_txs.first
122
135
  script_pubkey = funding_tx.outputs.first.script_pubkey
123
136
  color_id = Tapyrus::Color::ColorIdentifier.reissuable(script_pubkey)
124
137
 
125
- ActiveRecord::Base.transaction(joinable: false, requires_new: true) do
126
- funding_tx = issuer.internal_wallet.broadcast(funding_tx)
127
- end
128
-
129
138
  ActiveRecord::Base.transaction(joinable: false, requires_new: true) do
130
139
  # Store the script_pubkey for reissue the token.
131
- Glueby::Contract::AR::ReissuableToken.create!(color_id: color_id.to_hex, script_pubkey: script_pubkey.to_hex)
140
+ Glueby::Contract::AR::ReissuableToken.create!(
141
+ color_id: color_id.to_hex,
142
+ script_pubkey: script_pubkey.to_hex
143
+ )
132
144
 
133
- tx = create_issue_tx_for_reissuable_token(funding_tx: funding_tx, issuer: issuer, amount: amount, split: split, fee_estimator: fee_estimator)
134
145
  if metadata
146
+ p2c_utxo = txb.p2c_utxos.first
135
147
  Glueby::Contract::AR::TokenMetadata.create!(
136
148
  color_id: color_id.to_hex,
137
149
  metadata: metadata,
138
- p2c_address: p2c_address,
139
- payment_base: payment_base
150
+ p2c_address: p2c_utxo[:p2c_address],
151
+ payment_base: p2c_utxo[:payment_base]
140
152
  )
141
- tx = sign_to_p2c_output(issuer, tx, funding_tx, payment_base, metadata)
142
153
  end
154
+
155
+ tx = txb.reissuable_split(script_pubkey, issuer.internal_wallet.receive_address, amount, split)
156
+ .build
143
157
  tx = issuer.internal_wallet.broadcast(tx)
144
158
  [[funding_tx, tx], color_id]
145
159
  end
146
160
  end
147
161
 
148
162
  def issue_non_reissuable_token(issuer:, amount:, split: 1, fee_estimator:, metadata: nil)
149
- script, p2c_address, payment_base = create_p2c_address(issuer, metadata) if metadata
150
- funding_tx = create_funding_tx(wallet: issuer, script: script, only_finalized: only_finalized?) if Glueby.configuration.use_utxo_provider? || script
151
- if funding_tx
152
- ActiveRecord::Base.transaction(joinable: false, requires_new: true) do
153
- funding_tx = issuer.internal_wallet.broadcast(funding_tx)
154
- end
155
- end
163
+ issue_token_from_out_point(
164
+ Tapyrus::Color::TokenTypes::NON_REISSUABLE,
165
+ issuer: issuer,
166
+ amount: amount,
167
+ split: split,
168
+ fee_estimator: fee_estimator,
169
+ metadata: metadata
170
+ )
171
+ end
156
172
 
157
- ActiveRecord::Base.transaction(joinable: false, requires_new: true) do
158
- tx = create_issue_tx_for_non_reissuable_token(funding_tx: funding_tx, issuer: issuer, amount: amount, split: split, fee_estimator: fee_estimator)
159
- out_point = tx.inputs.first.out_point
160
- color_id = Tapyrus::Color::ColorIdentifier.non_reissuable(out_point)
161
- if metadata
162
- Glueby::Contract::AR::TokenMetadata.create!(
163
- color_id: color_id.to_hex,
164
- metadata: metadata,
165
- p2c_address: p2c_address,
166
- payment_base: payment_base
167
- )
168
- tx = sign_to_p2c_output(issuer, tx, funding_tx, payment_base, metadata)
169
- end
170
- tx = issuer.internal_wallet.broadcast(tx)
173
+ def issue_nft_token(issuer:, metadata: nil)
174
+ issue_token_from_out_point(
175
+ Tapyrus::Color::TokenTypes::NFT,
176
+ issuer: issuer,
177
+ amount: 1,
178
+ split: 1,
179
+ fee_estimator: Contract::FeeEstimator::Fixed.new,
180
+ metadata: metadata
181
+ )
182
+ end
171
183
 
172
- if funding_tx
173
- [[funding_tx, tx], color_id]
174
- else
175
- [[tx], color_id]
176
- end
184
+ def issue_token_from_out_point(token_type, issuer:, amount:, split: 1, fee_estimator: , metadata: nil)
185
+ txb = Internal::ContractBuilder.new(
186
+ sender_wallet: issuer.internal_wallet,
187
+ fee_estimator: fee_estimator,
188
+ use_auto_fulfill_inputs: true
189
+ )
190
+
191
+ funding_tx = nil
192
+
193
+ if metadata
194
+ txb.add_p2c_utxo_to!(
195
+ metadata: metadata,
196
+ amount: FeeEstimator::Fixed.new.fixed_fee,
197
+ only_finalized: only_finalized?,
198
+ fee_estimator: Contract::FeeEstimator::Fixed.new
199
+ )
200
+ funding_tx = txb.prev_txs.first
201
+ elsif Glueby.configuration.use_utxo_provider?
202
+ txb.add_utxo_to!(
203
+ address: issuer.internal_wallet.receive_address,
204
+ amount: FeeEstimator::Fixed.new.fixed_fee,
205
+ only_finalized: only_finalized?,
206
+ fee_estimator: Contract::FeeEstimator::Fixed.new
207
+ )
208
+ funding_tx = txb.prev_txs.first
209
+ else
210
+ # Here need to add just one UTXO to derive color_id from the UTXO out-point.
211
+ _, outputs = issuer.internal_wallet.collect_uncolored_outputs(1, nil, true)
212
+ txb.add_utxo(outputs.first)
177
213
  end
178
- end
179
214
 
180
- def issue_nft_token(issuer:, metadata: nil)
181
- script, p2c_address, payment_base = create_p2c_address(issuer, metadata) if metadata
182
- funding_tx = create_funding_tx(wallet: issuer, script: script, only_finalized: only_finalized?) if Glueby.configuration.use_utxo_provider? || script
183
- if funding_tx
184
- ActiveRecord::Base.transaction(joinable: false, requires_new: true) do
185
- funding_tx = issuer.internal_wallet.broadcast(funding_tx)
186
- end
215
+ utxo = txb.utxos.first
216
+ out_point = Tapyrus::OutPoint.from_txid(utxo[:txid], utxo[:index])
217
+
218
+ case token_type
219
+ when Tapyrus::Color::TokenTypes::NON_REISSUABLE
220
+ color_id = Tapyrus::Color::ColorIdentifier.non_reissuable(out_point)
221
+ tx = txb.non_reissuable_split(out_point, issuer.internal_wallet.receive_address, amount, split)
222
+ .build
223
+ when Tapyrus::Color::TokenTypes::NFT
224
+ color_id = Tapyrus::Color::ColorIdentifier.nft(out_point)
225
+ tx = txb.nft(out_point, issuer.internal_wallet.receive_address)
226
+ .build
187
227
  end
188
228
 
189
229
  ActiveRecord::Base.transaction(joinable: false, requires_new: true) do
190
- tx = create_issue_tx_for_nft_token(funding_tx: funding_tx, issuer: issuer)
191
- out_point = tx.inputs.first.out_point
192
- color_id = Tapyrus::Color::ColorIdentifier.nft(out_point)
193
230
  if metadata
231
+ p2c_utxo = txb.p2c_utxos.first
194
232
  Glueby::Contract::AR::TokenMetadata.create!(
195
233
  color_id: color_id.to_hex,
196
234
  metadata: metadata,
197
- p2c_address: p2c_address,
198
- payment_base: payment_base
235
+ p2c_address: p2c_utxo[:p2c_address],
236
+ payment_base: p2c_utxo[:payment_base]
199
237
  )
200
- tx = sign_to_p2c_output(issuer, tx, funding_tx, payment_base, metadata)
201
238
  end
202
239
  tx = issuer.internal_wallet.broadcast(tx)
203
240
 
@@ -208,6 +245,14 @@ module Glueby
208
245
  end
209
246
  end
210
247
  end
248
+
249
+ # Add dummy inputs and outputs to tx for issue non-reissuable transaction and nft transaction
250
+ def dummy_issue_tx_from_out_point
251
+ tx = Tapyrus::Tx.new
252
+ receiver_colored_script = Tapyrus::Script.parse_from_payload('21c20000000000000000000000000000000000000000000000000000000000000000bc76a914000000000000000000000000000000000000000088ac'.htb)
253
+ tx.outputs << Tapyrus::TxOut.new(value: 0, script_pubkey: receiver_colored_script)
254
+ FeeEstimator.dummy_tx(tx)
255
+ end
211
256
  end
212
257
 
213
258
  attr_reader :color_id
@@ -230,12 +275,33 @@ module Glueby
230
275
  token_metadata = Glueby::Contract::AR::TokenMetadata.find_by(color_id: color_id.to_hex)
231
276
  raise Glueby::Contract::Errors::UnknownScriptPubkey unless valid_reissuer?(wallet: issuer, token_metadata: token_metadata)
232
277
 
233
- funding_tx = create_funding_tx(wallet: issuer, script: @script_pubkey, only_finalized: only_finalized?)
234
- funding_tx = issuer.internal_wallet.broadcast(funding_tx)
235
- tx = create_reissue_tx(funding_tx: funding_tx, issuer: issuer, amount: amount, color_id: color_id, split: split, fee_estimator: fee_estimator)
278
+ txb = Internal::ContractBuilder.new(
279
+ sender_wallet: issuer.internal_wallet,
280
+ fee_estimator: fee_estimator,
281
+ use_auto_fulfill_inputs: true
282
+ )
283
+
236
284
  if token_metadata
237
- tx = Token.sign_to_p2c_output(issuer, tx, funding_tx, token_metadata.payment_base, token_metadata.metadata)
285
+ txb.add_p2c_utxo_to!(
286
+ metadata: metadata,
287
+ amount: FeeEstimator::Fixed.new.fixed_fee,
288
+ p2c_address: token_metadata.p2c_address,
289
+ payment_base: token_metadata.payment_base,
290
+ only_finalized: only_finalized?,
291
+ fee_estimator: Contract::FeeEstimator::Fixed.new
292
+ )
293
+ else
294
+ txb.add_utxo_to!(
295
+ address: @script_pubkey.to_addr,
296
+ amount: FeeEstimator::Fixed.new.fixed_fee,
297
+ only_finalized: only_finalized?,
298
+ fee_estimator: Contract::FeeEstimator::Fixed.new
299
+ )
238
300
  end
301
+
302
+ tx = txb.reissuable_split(@script_pubkey, issuer.internal_wallet.receive_address, amount, split)
303
+ .build
304
+
239
305
  tx = issuer.internal_wallet.broadcast(tx)
240
306
 
241
307
  [color_id, tx]
@@ -252,18 +318,13 @@ module Glueby
252
318
  # @raise [InsufficientTokens] if wallet does not have enough token to send.
253
319
  # @raise [InvalidAmount] if amount is not positive integer.
254
320
  def transfer!(sender:, receiver_address:, amount: 1, fee_estimator: FeeEstimator::Fixed.new)
255
- raise Glueby::Contract::Errors::InvalidAmount unless amount.positive?
256
-
257
- tx = create_transfer_tx(
258
- color_id: color_id,
321
+ multi_transfer!(
259
322
  sender: sender,
260
- receiver_address: receiver_address,
261
- amount: amount,
262
- only_finalized: only_finalized?,
263
- fee_estimator: fee_estimator
264
- )
265
- sender.internal_wallet.broadcast(tx)
266
- [color_id, tx]
323
+ receivers: [{
324
+ address: receiver_address,
325
+ amount: amount
326
+ }],
327
+ fee_estimator: fee_estimator)
267
328
  end
268
329
 
269
330
  # Send the tokens to multiple wallets
@@ -280,14 +341,20 @@ module Glueby
280
341
  raise Glueby::Contract::Errors::InvalidAmount unless r[:amount].positive?
281
342
  end
282
343
 
283
- tx = create_multi_transfer_tx(
284
- color_id: color_id,
285
- sender: sender,
286
- receivers: receivers,
287
- only_finalized: only_finalized?,
288
- fee_estimator: fee_estimator
289
- )
290
- sender.internal_wallet.broadcast(tx)
344
+ txb = Internal::ContractBuilder
345
+ .new(
346
+ sender_wallet: sender.internal_wallet,
347
+ fee_estimator: fee_estimator,
348
+ use_unfinalized_utxo: !only_finalized?,
349
+ use_auto_fulfill_inputs: true
350
+ )
351
+ .change_address(sender.internal_wallet.receive_address, color_id)
352
+
353
+ receivers.each do |r|
354
+ txb.pay(r[:address], r[:amount].to_i, color_id)
355
+ end
356
+
357
+ tx = sender.internal_wallet.broadcast(txb.build)
291
358
  [color_id, tx]
292
359
  end
293
360
 
@@ -306,7 +373,17 @@ module Glueby
306
373
  raise Glueby::Contract::Errors::InsufficientTokens unless balance
307
374
  raise Glueby::Contract::Errors::InsufficientTokens if balance < amount
308
375
 
309
- tx = create_burn_tx(color_id: color_id, sender: sender, amount: amount, only_finalized: only_finalized?, fee_estimator: fee_estimator)
376
+ tx = Internal::ContractBuilder
377
+ .new(
378
+ sender_wallet: sender.internal_wallet,
379
+ fee_estimator: fee_estimator,
380
+ use_unfinalized_utxo: !only_finalized?,
381
+ use_auto_fulfill_inputs: true
382
+ )
383
+ .burn(amount, color_id)
384
+ .change_address(sender.internal_wallet.receive_address, color_id)
385
+ .build
386
+
310
387
  sender.internal_wallet.broadcast(tx)
311
388
  end
312
389
 
@@ -314,10 +391,10 @@ module Glueby
314
391
  # @param wallet [Glueby::Wallet]
315
392
  # @return [Integer] amount of utxo value associated with this token.
316
393
  def amount(wallet:)
317
- # collect utxo associated with this address
318
- utxos = wallet.internal_wallet.list_unspent(only_finalized?)
319
- _, results = collect_colored_outputs(utxos, color_id)
320
- results.sum { |result| result[:amount] }
394
+ amount, _utxos = wallet
395
+ .internal_wallet
396
+ .collect_colored_outputs(color_id, nil, nil, only_finalized?)
397
+ amount
321
398
  end
322
399
 
323
400
  # Return metadata for this token
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Glueby
4
4
  module Contract
5
+ # @deprecated Use Glueby::Internal::ContractBuilder instead. This class will be removed in the future.
5
6
  module TxBuilder
6
7
  def receive_address(wallet:)
7
8
  wallet.receive_address