Module: Glueby::Contract::TxBuilder Deprecated

Defined in:
lib/glueby/contract/tx_builder.rb

Overview

Deprecated.

Use Glueby::Internal::ContractBuilder instead. This class will be removed in the future.

Instance Method Summary collapse

Instance Method Details

#add_split_output(tx, amount, split, script_pubkey) ⇒ Object



281
282
283
284
285
286
287
288
289
290
# File 'lib/glueby/contract/tx_builder.rb', line 281

def add_split_output(tx, amount, split, script_pubkey)
  if amount < split
    split = amount
    value = 1
  else
    value = (amount/split).to_i
  end
  (split - 1).times { tx.outputs << Tapyrus::TxOut.new(value: value, script_pubkey: script_pubkey) }
  tx.outputs << Tapyrus::TxOut.new(value: amount - value * (split - 1), script_pubkey: script_pubkey)
end

#collect_colored_outputs(results, amount = 0) ⇒ Object

Returns the set of utxos that satisfies the specified amount and has the specified color_id. if amount is not specified or 0, return all utxos with color_id

Parameters:

  • results (Array)

    response of Glueby::Internal::Wallet#list_unspent

  • amount (Integer) (defaults to: 0)

Raises:



323
324
325
326
327
328
329
330
331
332
333
334
# File 'lib/glueby/contract/tx_builder.rb', line 323

def collect_colored_outputs(results, amount = 0)
  results = results.inject([0, []]) do |sum, output|
    new_sum = sum[0] + output[:amount]
    new_outputs = sum[1] << output
    return [new_sum, new_outputs] if new_sum >= amount && amount.positive?

    [new_sum, new_outputs]
  end
  raise Glueby::Contract::Errors::InsufficientTokens if amount.positive?

  results
end

#create_burn_tx(color_id:, sender:, amount: 0, fee_estimator: FeeEstimator::Fixed.new, only_finalized: true) ⇒ Object



247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
# File 'lib/glueby/contract/tx_builder.rb', line 247

def create_burn_tx(color_id:, sender:, amount: 0, fee_estimator: FeeEstimator::Fixed.new, only_finalized: true)
  tx = Tapyrus::Tx.new

  utxos = sender.internal_wallet.list_unspent(only_finalized, color_id: color_id)
  sum_token, outputs = collect_colored_outputs(utxos, amount)
  fill_input(tx, outputs)

  fill_change_token(tx, sender, sum_token - amount, color_id) if amount.positive?
  fee = fee_estimator.fee(FeeEstimator.dummy_tx(tx))

  provided_utxos = []
  utxo_provider = nil

  if Glueby.configuration.use_utxo_provider?
    utxo_provider = UtxoProvider.new
    # When it burns all the amount of the color id, burn tx is not going to have any output
    # because change outputs are not necessary, though such a transaction is not 'standard' and would be rejected by the Tapyrus node.
    # UtxoProvider#fill_inputs method provides an extra output with a DUST_LIMIT value in this case
    # , so that it created at least one output to the burn tx.
    tx, fee, sum_tpc, provided_utxos = utxo_provider.fill_inputs(
      tx,
      target_amount: 0,
      current_amount: 0,
      fee_estimator: fee_estimator
    )
  else
    sum_tpc, outputs = sender.internal_wallet.collect_uncolored_outputs(fee + DUST_LIMIT, nil, only_finalized)
    fill_input(tx, outputs)
  end
  fill_change_tpc(tx, sender, sum_tpc - fee)
  utxo_provider.wallet.sign_tx(tx, provided_utxos) if Glueby.configuration.use_utxo_provider?
  sender.internal_wallet.sign_tx(tx, provided_utxos)
end

#create_funding_tx(wallet:, script: nil, fee_estimator: FeeEstimator::Fixed.new, only_finalized: true) ⇒ Object

Create new public key, and new transaction that sends TPC to it



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/glueby/contract/tx_builder.rb', line 12

def create_funding_tx(wallet:, script: nil, fee_estimator: FeeEstimator::Fixed.new, only_finalized: true)
  if Glueby.configuration.use_utxo_provider?
    utxo_provider = UtxoProvider.new
    script_pubkey = script ? script : Tapyrus::Script.parse_from_addr(wallet.internal_wallet.receive_address)
    funding_tx, _index = utxo_provider.get_utxo(script_pubkey, funding_tx_amount)
    utxo_provider.wallet.sign_tx(funding_tx)
  else
    txb = Tapyrus::TxBuilder.new
    fee = fee_estimator.fee(FeeEstimator.dummy_tx(txb.build))
    amount = fee + funding_tx_amount
    sum, outputs = wallet.internal_wallet.collect_uncolored_outputs(amount, nil, only_finalized)
    outputs.each do |utxo|
      txb.add_utxo({
        script_pubkey: Tapyrus::Script.parse_from_payload(utxo[:script_pubkey].htb),
        txid: utxo[:txid],
        index: utxo[:vout],
        value: utxo[:amount]
      })
    end
  
    receiver_address = script ? script.addresses.first : wallet.internal_wallet.receive_address
    tx = txb.pay(receiver_address, funding_tx_amount)
      .change_address(wallet.internal_wallet.change_address)
      .fee(fee)
      .build
    wallet.internal_wallet.sign_tx(tx)
  end
end

#create_issue_tx_for_nft_token(funding_tx: nil, issuer:, fee_estimator: FeeEstimator::Fixed.new, only_finalized: true) ⇒ Object



90
91
92
# File 'lib/glueby/contract/tx_builder.rb', line 90

def create_issue_tx_for_nft_token(funding_tx: nil, issuer:, fee_estimator: FeeEstimator::Fixed.new, only_finalized: true)
  create_issue_tx_from_out_point(funding_tx: funding_tx, token_type: Tapyrus::Color::TokenTypes::NFT, issuer: issuer, amount: 1, fee_estimator: fee_estimator, only_finalized: only_finalized)
end

#create_issue_tx_for_non_reissuable_token(funding_tx: nil, issuer:, amount:, split: 1, fee_estimator: FeeEstimator::Fixed.new, only_finalized: true) ⇒ Object



86
87
88
# File 'lib/glueby/contract/tx_builder.rb', line 86

def create_issue_tx_for_non_reissuable_token(funding_tx: nil, issuer:, amount:, split: 1, fee_estimator: FeeEstimator::Fixed.new, only_finalized: true)
  create_issue_tx_from_out_point(funding_tx: funding_tx, token_type: Tapyrus::Color::TokenTypes::NON_REISSUABLE, issuer: issuer, amount: amount, split: split, fee_estimator: fee_estimator, only_finalized: only_finalized)
end

#create_issue_tx_for_reissuable_token(funding_tx:, issuer:, amount:, split: 1, fee_estimator: FeeEstimator::Fixed.new) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/glueby/contract/tx_builder.rb', line 41

def create_issue_tx_for_reissuable_token(funding_tx:, issuer:, amount:, split: 1, fee_estimator: FeeEstimator::Fixed.new)
  tx = Tapyrus::Tx.new

  out_point = Tapyrus::OutPoint.from_txid(funding_tx.txid, 0)
  tx.inputs << Tapyrus::TxIn.new(out_point: out_point)
  output = funding_tx.outputs.first

  receiver_script = Tapyrus::Script.parse_from_addr(issuer.internal_wallet.receive_address)
  funding_script = Tapyrus::Script.parse_from_payload(output.script_pubkey.to_payload)
  color_id = Tapyrus::Color::ColorIdentifier.reissuable(funding_script)
  receiver_colored_script = receiver_script.add_color(color_id)

  add_split_output(tx, amount, split, receiver_colored_script)

  fee = fee_estimator.fee(FeeEstimator.dummy_tx(tx))

  prev_txs = [{
    txid: funding_tx.txid,
    vout: 0,
    scriptPubKey: output.script_pubkey.to_hex,
    amount: output.value
  }]

  utxo_provider = nil

  if Glueby.configuration.use_utxo_provider?
    utxo_provider = UtxoProvider.new
    tx, fee, input_amount, provided_utxos = utxo_provider.fill_inputs(
      tx,
      target_amount: 0,
      current_amount: output.value,
      fee_estimator: fee_estimator
    )
    prev_txs.concat(provided_utxos)
  else
    # TODO: Support the case of providing UTXOs from sender's wallet.
    input_amount = output.value
  end

  fill_change_tpc(tx, issuer, input_amount - fee)

  utxo_provider.wallet.sign_tx(tx, prev_txs) if Glueby.configuration.use_utxo_provider?
  issuer.internal_wallet.sign_tx(tx, prev_txs)
end

#create_issue_tx_from_out_point(funding_tx: nil, token_type:, issuer:, amount:, split: 1, fee_estimator: FeeEstimator::Fixed.new, only_finalized: true) ⇒ Object



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/glueby/contract/tx_builder.rb', line 94

def create_issue_tx_from_out_point(funding_tx: nil, token_type:, issuer:, amount:, split: 1, fee_estimator: FeeEstimator::Fixed.new, only_finalized: true)
  tx = Tapyrus::Tx.new

  fee = fee_estimator.fee(dummy_issue_tx_from_out_point)
  sum = if funding_tx
    out_point = Tapyrus::OutPoint.from_txid(funding_tx.txid, 0)
    tx.inputs << Tapyrus::TxIn.new(out_point: out_point)
    funding_tx.outputs.first.value
  else
    sum, outputs = issuer.internal_wallet.collect_uncolored_outputs(fee, nil, only_finalized)
    fill_input(tx, outputs)
    sum
  end
  out_point = tx.inputs.first.out_point
  color_id = case token_type
  when Tapyrus::Color::TokenTypes::NON_REISSUABLE
    Tapyrus::Color::ColorIdentifier.non_reissuable(out_point)
  when Tapyrus::Color::TokenTypes::NFT
    Tapyrus::Color::ColorIdentifier.nft(out_point)
  else
    raise Glueby::Contract::Errors::UnsupportedTokenType  
  end

  receiver_script = Tapyrus::Script.parse_from_addr(issuer.internal_wallet.receive_address)
  receiver_colored_script = receiver_script.add_color(color_id)
  add_split_output(tx, amount, split, receiver_colored_script)

  prev_txs = if funding_tx
               output = funding_tx.outputs.first
               [{
                 txid: funding_tx.txid,
                 vout: 0,
                 scriptPubKey: output.script_pubkey.to_hex,
                 amount: output.value
               }]
             else
               []
             end

  utxo_provider = nil

  if Glueby.configuration.use_utxo_provider?
    utxo_provider = UtxoProvider.new
    tx, fee, sum, provided_utxos = utxo_provider.fill_inputs(
      tx,
      target_amount: 0,
      current_amount: sum,
      fee_estimator: fee_estimator
    )
    prev_txs.concat(provided_utxos)
  end

  fill_change_tpc(tx, issuer, sum - fee)

  utxo_provider.wallet.sign_tx(tx, prev_txs) if Glueby.configuration.use_utxo_provider?
  issuer.internal_wallet.sign_tx(tx, prev_txs)
end

#create_multi_transfer_tx(color_id:, sender:, receivers:, fee_estimator: FeeEstimator::Fixed.new, only_finalized: true) ⇒ Object



205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
# File 'lib/glueby/contract/tx_builder.rb', line 205

def create_multi_transfer_tx(color_id:, sender:, receivers:, fee_estimator: FeeEstimator::Fixed.new, only_finalized: true)
  tx = Tapyrus::Tx.new

  amount = receivers.reduce(0) { |sum, r| sum + r[:amount].to_i }
  utxos = sender.internal_wallet.list_unspent(only_finalized, color_id: color_id)
  sum_token, outputs = collect_colored_outputs(utxos, amount)
  fill_input(tx, outputs)

  receivers.each do |r|
    receiver_script = Tapyrus::Script.parse_from_addr(r[:address])
    receiver_colored_script = receiver_script.add_color(color_id)
    tx.outputs << Tapyrus::TxOut.new(value: r[:amount].to_i, script_pubkey: receiver_colored_script)
  end

  fill_change_token(tx, sender, sum_token - amount, color_id)

  fee = fee_estimator.fee(FeeEstimator.dummy_tx(tx))

  utxo_provider = nil

  # Fill inputs for paying fee
  prev_txs = []
  if Glueby.configuration.use_utxo_provider?
    utxo_provider = UtxoProvider.new
    tx, fee, sum_tpc, provided_utxos = utxo_provider.fill_inputs(
      tx,
      target_amount: 0,
      current_amount: 0,
      fee_estimator: fee_estimator
    )
    prev_txs.concat(provided_utxos)
  else
    # TODO: Support the case of increasing fee by adding multiple inputs
    sum_tpc, outputs = sender.internal_wallet.collect_uncolored_outputs(fee, nil, only_finalized)
    fill_input(tx, outputs)
  end

  fill_change_tpc(tx, sender, sum_tpc - fee)
  utxo_provider.wallet.sign_tx(tx, prev_txs) if Glueby.configuration.use_utxo_provider?
  sender.internal_wallet.sign_tx(tx, prev_txs)
end

#create_reissue_tx(funding_tx:, issuer:, amount:, color_id:, split: 1, fee_estimator: FeeEstimator::Fixed.new) ⇒ Object



152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/glueby/contract/tx_builder.rb', line 152

def create_reissue_tx(funding_tx:, issuer:, amount:, color_id:, split: 1, fee_estimator: FeeEstimator::Fixed.new)
  tx = Tapyrus::Tx.new

  out_point = Tapyrus::OutPoint.from_txid(funding_tx.txid, 0)
  tx.inputs << Tapyrus::TxIn.new(out_point: out_point)
  output = funding_tx.outputs.first

  receiver_script = Tapyrus::Script.parse_from_addr(issuer.internal_wallet.receive_address)
  receiver_colored_script = receiver_script.add_color(color_id)
  add_split_output(tx, amount, split, receiver_colored_script)

  fee = fee_estimator.fee(FeeEstimator.dummy_tx(tx))

  prev_txs = [{
    txid: funding_tx.txid,
    vout: 0,
    scriptPubKey: output.script_pubkey.to_hex,
    amount: output.value
  }]

  utxo_provider = nil

  if Glueby.configuration.use_utxo_provider?
    utxo_provider = UtxoProvider.new
    tx, fee, input_amount, provided_utxos = utxo_provider.fill_inputs(
      tx,
      target_amount: 0,
      current_amount: output.value,
      fee_estimator: fee_estimator
    )
    prev_txs.concat(provided_utxos)
  else
    # TODO: Support the case of providing UTXOs from sender's wallet.
    input_amount = output.value
  end

  fill_change_tpc(tx, issuer, input_amount - fee)

  utxo_provider.wallet.sign_tx(tx, prev_txs) if Glueby.configuration.use_utxo_provider?
  issuer.internal_wallet.sign_tx(tx, prev_txs)
end

#create_transfer_tx(color_id:, sender:, receiver_address:, amount:, fee_estimator: FeeEstimator::Fixed.new, only_finalized: true) ⇒ Object



194
195
196
197
198
199
200
201
202
203
# File 'lib/glueby/contract/tx_builder.rb', line 194

def create_transfer_tx(color_id:, sender:, receiver_address:, amount:, fee_estimator: FeeEstimator::Fixed.new, only_finalized: true)
  receivers = [{ address: receiver_address, amount: amount }]
  create_multi_transfer_tx(
    color_id: color_id,
    sender: sender,
    receivers: receivers,
    fee_estimator: fee_estimator,
    only_finalized: only_finalized
  )
end

#dummy_issue_tx_from_out_pointObject

Add dummy inputs and outputs to tx for issue non-reissuable transaction and nft transaction



337
338
339
340
341
342
# File 'lib/glueby/contract/tx_builder.rb', line 337

def dummy_issue_tx_from_out_point
  tx = Tapyrus::Tx.new
  receiver_colored_script = Tapyrus::Script.parse_from_payload('21c20000000000000000000000000000000000000000000000000000000000000000bc76a914000000000000000000000000000000000000000088ac'.htb)
  tx.outputs << Tapyrus::TxOut.new(value: 0, script_pubkey: receiver_colored_script)
  FeeEstimator.dummy_tx(tx)
end

#fill_change_token(tx, wallet, change, color_id) ⇒ Object



311
312
313
314
315
316
317
# File 'lib/glueby/contract/tx_builder.rb', line 311

def fill_change_token(tx, wallet, change, color_id)
  return unless change.positive?

  change_script = Tapyrus::Script.parse_from_addr(wallet.internal_wallet.change_address)
  change_colored_script = change_script.add_color(color_id)
  tx.outputs << Tapyrus::TxOut.new(value: change, script_pubkey: change_colored_script)
end

#fill_change_tpc(tx, wallet, change) ⇒ Object



299
300
301
302
303
304
305
306
307
308
309
# File 'lib/glueby/contract/tx_builder.rb', line 299

def fill_change_tpc(tx, wallet, change)
  return unless change.positive?

  if Glueby.configuration.use_utxo_provider?
    change_script = Tapyrus::Script.parse_from_addr(UtxoProvider.new.wallet.change_address)
  else
    change_script = Tapyrus::Script.parse_from_addr(wallet.internal_wallet.change_address)
  end

  tx.outputs << Tapyrus::TxOut.new(value: change, script_pubkey: change_script)
end

#fill_input(tx, outputs) ⇒ Object



292
293
294
295
296
297
# File 'lib/glueby/contract/tx_builder.rb', line 292

def fill_input(tx, outputs)
  outputs.each do |output|
    out_point = Tapyrus::OutPoint.new(output[:txid].rhex, output[:vout])
    tx.inputs << Tapyrus::TxIn.new(out_point: out_point)
  end
end

#receive_address(wallet:) ⇒ Object



7
8
9
# File 'lib/glueby/contract/tx_builder.rb', line 7

def receive_address(wallet:)
  wallet.receive_address
end