glueby 1.1.2 → 1.2.0.beta.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +2 -2
- 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 +2 -0
- data/lib/glueby/internal/wallet/active_record/utxo.rb +3 -2
- data/lib/glueby/internal/wallet.rb +149 -12
- 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
@@ -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
|
-
|
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
|
-
|
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!(
|
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
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
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
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
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
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
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
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
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
|
-
|
234
|
-
|
235
|
-
|
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
|
-
|
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
|
-
|
256
|
-
|
257
|
-
tx = create_transfer_tx(
|
258
|
-
color_id: color_id,
|
321
|
+
multi_transfer!(
|
259
322
|
sender: sender,
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
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
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
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 =
|
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
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
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
|