glueby 0.4.2 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fbaba6627d1c34e6a2de2a3861016995481ad53163764a057c25fca123a8750b
4
- data.tar.gz: 209020a3b503ac44cc9d4ef51e95d7ce71f17af59b92ffe3bb4863b4ae750604
3
+ metadata.gz: 37c10a4359a509cd4f86c35726161717bde07bc1ce459e19b0ba4c053e8dba86
4
+ data.tar.gz: 3cd0124ed69e0f34d1adf4ff5ed26005979689befc163c970b104245f267a479
5
5
  SHA512:
6
- metadata.gz: 559e4f224359df179cafc4f20c19f3f7c9723f6411103532ad6fd7d9727b5063c369b44e4e6c7872bc49d9355ec0cedd4f720c195302546cab7a5e5b429f6676
7
- data.tar.gz: b4a4a1641820f23513ea56e1c240db966bcb9b0d62fd463d54f08e09f454125cdca4a087bc8db8c9b0181cd867ee667ec1b2bf5fbe1b95329541b3dd5fe2538b
6
+ metadata.gz: 68729802e9bcb1a51148c12daa1e1565180c300d43cc811c2c512056804ad2fb8cd0bd8dd0e0d915e19da2177b3a47a941a4911ce7f6376a47f598edade087fe
7
+ data.tar.gz: 902c5c0cf87cb940c9619e5f9af95367187a009ddc01d74a6604c22d8e9df9e50dec50df24455c6fb2f0a1a9020869e4d619bd879802739ba04118bf600fab6a
data/README.md CHANGED
@@ -27,6 +27,10 @@ Glueby has below features.
27
27
  FeeProvider module can bear payments of sender's fees. You should provide funds for fees to FeeProvider before use.
28
28
  See how to set up at [Use fee provider mode](#use-fee-provider-mode)
29
29
 
30
+ 5. Utxo Provider
31
+ The UtxoProvider allows users to create a variety of transactions without having to manage the TPCs they hold in their wallets.
32
+ See more details at [Use utxo provider](#use-utxo-provider)
33
+
30
34
  ## Installation
31
35
 
32
36
  Add this line to your application's Gemfile:
@@ -223,6 +227,9 @@ Glueby.configure do |config|
223
227
  config.wallet_adapter = :activerecord
224
228
  config.rpc_config = { schema: 'http', host: '127.0.0.1', port: 12381, user: 'user', password: 'pass' }
225
229
  end
230
+
231
+ # Uncomment next line when using timestamp feature
232
+ # Glueby::BlockSyncer.register_syncer(Glueby::Contract::Timestamp::Syncer)
226
233
  ```
227
234
 
228
235
  If you use timestamp feature, use `glueby:contract:timestamp` generator.
@@ -293,6 +300,7 @@ Glueby.configure do |config|
293
300
  # The fee that Fee Provider pays on each transaction.
294
301
  fixed_fee: 1000,
295
302
  # Fee Provider tries to keep the number of utxo in utxo pool as this size using `glueby:fee_provider:manage_utxo_pool` rake task
303
+ # This size should not be greater than 2000.
296
304
  utxo_pool_size: 20
297
305
  }
298
306
  end
@@ -365,6 +373,77 @@ Configuration:
365
373
  utxo_pool_size = 20
366
374
  ```
367
375
 
376
+ ## Use Utxo Provider
377
+
378
+ UtxoProvider will pay TPC on behalf of the user.
379
+
380
+ TPCs are required to create transactions in many cases where Glueby is used, such as issuing tokens or recording timestamps.
381
+ However, on the other hand, each user may not want to fund or manage TPCs.
382
+
383
+ The UtxoProvider allows users to create a variety of transactions without having to manage the TPCs they hold in their wallets.
384
+
385
+ ### Set up Utxo Provider
386
+
387
+ 1. Configure using Glueby.configure
388
+
389
+ ```ruby
390
+ Glueby.configure do |config|
391
+ # using Utxo Provider
392
+ config.enable_utxo_provider!
393
+
394
+ # If not using Utxo Provider and each wallet manages TPCs by itself (Default behavior)
395
+ # config.disable_utxo_provider!
396
+
397
+ config.utxo_provider_config = {
398
+ # The amount that each utxo in utxo pool posses.
399
+ default_value: 1_000,
400
+ # The number of utxos in utxo pool. This size should not be greater than 2000.
401
+ utxo_pool_size: 20
402
+ }
403
+ end
404
+ ```
405
+
406
+ 2. Deposit TPC into Utxo Provider's wallet
407
+
408
+ Get an address from the wallet, and send enough TPCs to the address.
409
+
410
+ ```
411
+ $ bundle exec rake glueby:utxo_provider:address
412
+ mqYTLdLCUCCZkTkcpbVx1GqpvV1gK4euRD
413
+ ```
414
+
415
+ 3. Manage UTXO pool
416
+
417
+ Run the rake task `glueby:utxo_provider:manage_utxo_pool`
418
+ This rake task tries to split UTOXs up to `utxo_pool_size`. If the pool has more than `utxo_pool_size` UTXOs, it does nothing
419
+
420
+ ```
421
+ $ bundle exec rake glueby:utxo_provider:manage_utxo_pool
422
+
423
+ Status: Ready
424
+ TPC amount: 4_999_990_000
425
+ UTXO pool size: 20
426
+
427
+ Configuration:
428
+ default_value = 1_000
429
+ utxo_pool_size = 20
430
+ ```
431
+
432
+ If you want to get the status information, you can use the `status` task.
433
+
434
+ ```
435
+ $ bundle exec rake glueby:utxo_provider:status
436
+ Status: Ready q
437
+ TPC amount: 4_999_990_000
438
+ UTXO pool size: 20
439
+
440
+ Configuration:
441
+ default_value = 1_000
442
+ utxo_pool_size = 20
443
+
444
+ ```
445
+
446
+
368
447
  ## Development
369
448
 
370
449
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
data/glueby.gemspec CHANGED
@@ -27,6 +27,7 @@ Gem::Specification.new do |spec|
27
27
  spec.require_paths = ["lib"]
28
28
 
29
29
  spec.add_runtime_dependency 'tapyrus', '>= 0.2.9'
30
- spec.add_runtime_dependency 'activerecord'
30
+ spec.add_runtime_dependency 'activerecord', '~> 6.1.3'
31
31
  spec.add_development_dependency 'sqlite3'
32
+ spec.add_development_dependency 'rails', '~> 6.1.3'
32
33
  end
@@ -3,3 +3,6 @@ Glueby.configure do |config|
3
3
  config.wallet_adapter = :activerecord
4
4
  config.rpc_config = { schema: 'http', host: '127.0.0.1', port: 12381, user: 'user', password: 'pass' }
5
5
  end
6
+
7
+ # Uncomment next line when using timestamp feature
8
+ # Glueby::BlockSyncer.register_syncer(Glueby::Contract::Timestamp::Syncer)
@@ -10,11 +10,17 @@ module Glueby
10
10
  # end
11
11
  class Configuration
12
12
 
13
- attr_reader :fee_provider_bears
13
+ attr_reader :fee_provider_bears, :use_utxo_provider
14
14
  alias_method :fee_provider_bears?, :fee_provider_bears
15
+ alias_method :use_utxo_provider?, :use_utxo_provider
16
+
17
+ module Errors
18
+ class InvalidConfiguration < StandardError; end
19
+ end
15
20
 
16
21
  def initialize
17
22
  @fee_provider_bears = false
23
+ @use_utxo_provider = false
18
24
  end
19
25
 
20
26
  # Specify wallet adapter.
@@ -54,9 +60,27 @@ module Glueby
54
60
  # Specify FeeProvider configuration.
55
61
  # @param [Hash] config
56
62
  # @option config [Integer] :fixed_fee - The fee that Fee Provider pays on each transaction.
57
- # @option config [Integer] :utxo_pool_size - Fee Provider tries to keep the number of utxo in utxo pool as this size using `glueby:fee_provider:manage_utxo_pool` rake task
63
+ # @option config [Integer] :utxo_pool_size - Fee Provider tries to keep the number of utxo in utxo pool as this size using `glueby:fee_provider:manage_utxo_pool` rake task. this size should not be greater than 2000.
58
64
  def fee_provider_config=(config)
59
65
  FeeProvider.configure(config)
60
66
  end
67
+
68
+ # Enable UtxoProvider feature
69
+ def enable_utxo_provider!
70
+ @use_utxo_provider = true
71
+ end
72
+
73
+ # Disable UtxoProvider feature
74
+ def disable_utxo_provider!
75
+ @use_utxo_provider = false
76
+ end
77
+
78
+ # Set UtxoProvider configuration
79
+ # @param [Hash] config
80
+ # @option config [Integer] :default_value - The fee that Fee Provider pays on each transaction.
81
+ # @option config [Integer] :utxo_pool_size - Utxo Provider tries to keep the number of utxo in utxo pool as this size using `glueby:utxo_provider:manage_utxo_pool` rake task. this size should not be greater than 2000.
82
+ def utxo_provider_config=(config)
83
+ UtxoProvider.configure(config)
84
+ end
61
85
  end
62
86
  end
@@ -16,30 +16,45 @@ module Glueby
16
16
  include Glueby::Internal::Wallet::TapyrusCoreWalletAdapter::Util
17
17
  module_function
18
18
 
19
- def create_tx(wallet, prefix, data, fee_estimator)
20
- tx = Tapyrus::Tx.new
21
- tx.outputs << Tapyrus::TxOut.new(value: 0, script_pubkey: create_script(prefix, data))
22
-
23
- fee = fee_estimator.fee(dummy_tx(tx))
24
- sum, outputs = wallet.internal_wallet.collect_uncolored_outputs(fee)
25
- fill_input(tx, outputs)
26
-
27
- fill_change_tpc(tx, wallet, sum - fee)
28
- wallet.internal_wallet.sign_tx(tx)
29
- end
30
-
31
- def create_payload(prefix, data)
32
- payload = +''
33
- payload << prefix
34
- payload << data
35
- payload
36
- end
19
+ def create_txs(wallet, prefix, data, fee_estimator, utxo_provider)
20
+ txb = Tapyrus::TxBuilder.new
21
+ txb.data(prefix + data)
22
+ fee = fee_estimator.fee(dummy_tx(txb.build))
23
+ if utxo_provider
24
+ script_pubkey = Tapyrus::Script.parse_from_addr(wallet.internal_wallet.receive_address)
25
+ funding_tx, index = utxo_provider.get_utxo(script_pubkey, fee)
26
+ txb.add_utxo({
27
+ script_pubkey: funding_tx.outputs[index].script_pubkey,
28
+ txid: funding_tx.txid,
29
+ index: index,
30
+ value: funding_tx.outputs[index].value
31
+ })
32
+ else
33
+ sum, outputs = wallet.internal_wallet.collect_uncolored_outputs(fee)
34
+ outputs.each do |utxo|
35
+ txb.add_utxo({
36
+ script_pubkey: Tapyrus::Script.parse_from_payload(utxo[:script_pubkey].htb),
37
+ txid: utxo[:txid],
38
+ index: utxo[:vout],
39
+ value: utxo[:amount]
40
+ })
41
+ end
42
+ end
43
+
44
+ prev_txs = if funding_tx
45
+ output = funding_tx.outputs.first
46
+ [{
47
+ txid: funding_tx.txid,
48
+ vout: 0,
49
+ scriptPubKey: output.script_pubkey.to_hex,
50
+ amount: output.value
51
+ }]
52
+ else
53
+ []
54
+ end
37
55
 
38
- def create_script(prefix, data)
39
- script = Tapyrus::Script.new
40
- script << Tapyrus::Script::OP_RETURN
41
- script << create_payload(prefix, data)
42
- script
56
+ txb.fee(fee).change_address(wallet.internal_wallet.change_address)
57
+ [funding_tx, wallet.internal_wallet.sign_tx(txb.build, prev_txs)]
43
58
  end
44
59
 
45
60
  def get_transaction(tx)
@@ -63,13 +78,15 @@ module Glueby
63
78
  content:,
64
79
  prefix: '',
65
80
  fee_estimator: Glueby::Contract::FixedFeeEstimator.new,
66
- digest: :sha256
81
+ digest: :sha256,
82
+ utxo_provider: nil
67
83
  )
68
84
  @wallet = wallet
69
85
  @content = content
70
86
  @prefix = prefix
71
87
  @fee_estimator = fee_estimator
72
88
  @digest = digest
89
+ @utxo_provider = utxo_provider
73
90
  end
74
91
 
75
92
  # broadcast to Tapyrus Core
@@ -79,7 +96,8 @@ module Glueby
79
96
  def save!
80
97
  raise Glueby::Contract::Errors::TxAlreadyBroadcasted if @txid
81
98
 
82
- @tx = create_tx(@wallet, @prefix, digest_content, @fee_estimator)
99
+ funding_tx, @tx = create_txs(@wallet, @prefix, digest_content, @fee_estimator, @utxo_provider)
100
+ @wallet.internal_wallet.broadcast(funding_tx) if funding_tx
83
101
  @txid = @wallet.internal_wallet.broadcast(@tx)
84
102
  end
85
103
 
@@ -80,7 +80,8 @@ module Glueby
80
80
  private
81
81
 
82
82
  def issue_reissuable_token(issuer:, amount:)
83
- funding_tx = create_funding_tx(wallet: issuer)
83
+ utxo_provider = Glueby::UtxoProvider.new if Glueby.configuration.use_utxo_provider?
84
+ funding_tx = create_funding_tx(wallet: issuer, utxo_provider: utxo_provider)
84
85
  script_pubkey = funding_tx.outputs.first.script_pubkey
85
86
  color_id = Tapyrus::Color::ColorIdentifier.reissuable(script_pubkey)
86
87
 
@@ -96,21 +97,37 @@ module Glueby
96
97
  end
97
98
 
98
99
  def issue_non_reissuable_token(issuer:, amount:)
99
- tx = create_issue_tx_for_non_reissuable_token(issuer: issuer, amount: amount)
100
+ utxo_provider = Glueby::UtxoProvider.new if Glueby.configuration.use_utxo_provider?
101
+ funding_tx = create_funding_tx(wallet: issuer, utxo_provider: utxo_provider) if utxo_provider
102
+ funding_tx = issuer.internal_wallet.broadcast(funding_tx) if funding_tx
103
+
104
+ tx = create_issue_tx_for_non_reissuable_token(funding_tx: funding_tx, issuer: issuer, amount: amount)
100
105
  tx = issuer.internal_wallet.broadcast(tx)
101
106
 
102
107
  out_point = tx.inputs.first.out_point
103
108
  color_id = Tapyrus::Color::ColorIdentifier.non_reissuable(out_point)
104
- [[tx], color_id]
109
+ if funding_tx
110
+ [[funding_tx, tx], color_id]
111
+ else
112
+ [[tx], color_id]
113
+ end
105
114
  end
106
115
 
107
116
  def issue_nft_token(issuer:)
108
- tx = create_issue_tx_for_nft_token(issuer: issuer)
117
+ utxo_provider = Glueby::UtxoProvider.new if Glueby.configuration.use_utxo_provider?
118
+ funding_tx = create_funding_tx(wallet: issuer, utxo_provider: utxo_provider) if utxo_provider
119
+ funding_tx = issuer.internal_wallet.broadcast(funding_tx) if funding_tx
120
+
121
+ tx = create_issue_tx_for_nft_token(funding_tx: funding_tx, issuer: issuer)
109
122
  tx = issuer.internal_wallet.broadcast(tx)
110
123
 
111
124
  out_point = tx.inputs.first.out_point
112
125
  color_id = Tapyrus::Color::ColorIdentifier.nft(out_point)
113
- [[tx], color_id]
126
+ if funding_tx
127
+ [[funding_tx, tx], color_id]
128
+ else
129
+ [[tx], color_id]
130
+ end
114
131
  end
115
132
  end
116
133
 
@@ -128,9 +145,10 @@ module Glueby
128
145
  def reissue!(issuer:, amount:)
129
146
  raise Glueby::Contract::Errors::InvalidAmount unless amount.positive?
130
147
  raise Glueby::Contract::Errors::InvalidTokenType unless token_type == Tapyrus::Color::TokenTypes::REISSUABLE
148
+ utxo_provider = Glueby::UtxoProvider.new if Glueby.configuration.use_utxo_provider?
131
149
 
132
150
  if validate_reissuer(wallet: issuer)
133
- funding_tx = create_funding_tx(wallet: issuer, script: @script_pubkey)
151
+ funding_tx = create_funding_tx(wallet: issuer, script: @script_pubkey, utxo_provider: utxo_provider)
134
152
  funding_tx = issuer.internal_wallet.broadcast(funding_tx)
135
153
  tx = create_reissue_tx(funding_tx: funding_tx, issuer: issuer, amount: amount, color_id: color_id)
136
154
  tx = issuer.internal_wallet.broadcast(tx)
@@ -153,7 +171,11 @@ module Glueby
153
171
  def transfer!(sender:, receiver_address:, amount: 1)
154
172
  raise Glueby::Contract::Errors::InvalidAmount unless amount.positive?
155
173
 
156
- tx = create_transfer_tx(color_id: color_id, sender: sender, receiver_address: receiver_address, amount: amount)
174
+ utxo_provider = Glueby::UtxoProvider.new if Glueby.configuration.use_utxo_provider?
175
+ funding_tx = create_funding_tx(wallet: sender, utxo_provider: utxo_provider) if utxo_provider
176
+ funding_tx = sender.internal_wallet.broadcast(funding_tx) if funding_tx
177
+
178
+ tx = create_transfer_tx(funding_tx: funding_tx, color_id: color_id, sender: sender, receiver_address: receiver_address, amount: amount)
157
179
  sender.internal_wallet.broadcast(tx)
158
180
  [color_id, tx]
159
181
  end
@@ -169,7 +191,11 @@ module Glueby
169
191
  def burn!(sender:, amount: 0)
170
192
  raise Glueby::Contract::Errors::InvalidAmount unless amount.positive?
171
193
 
172
- tx = create_burn_tx(color_id: color_id, sender: sender, amount: amount)
194
+ utxo_provider = Glueby::UtxoProvider.new if Glueby.configuration.use_utxo_provider?
195
+ funding_tx = create_funding_tx(wallet: sender, utxo_provider: utxo_provider) if utxo_provider
196
+ funding_tx = sender.internal_wallet.broadcast(funding_tx) if funding_tx
197
+
198
+ tx = create_burn_tx(funding_tx: funding_tx, color_id: color_id, sender: sender, amount: amount)
173
199
  sender.internal_wallet.broadcast(tx)
174
200
  end
175
201
 
@@ -11,18 +11,32 @@ module Glueby
11
11
  end
12
12
 
13
13
  # Create new public key, and new transaction that sends TPC to it
14
- def create_funding_tx(wallet:, script: nil, fee_estimator: FixedFeeEstimator.new)
15
- tx = Tapyrus::Tx.new
16
- fee = fee_estimator.fee(dummy_tx(tx))
17
-
18
- sum, outputs = wallet.internal_wallet.collect_uncolored_outputs(fee + FUNDING_TX_AMOUNT)
19
- fill_input(tx, outputs)
20
-
21
- receiver_script = script ? script : Tapyrus::Script.parse_from_addr(wallet.internal_wallet.receive_address)
22
- tx.outputs << Tapyrus::TxOut.new(value: FUNDING_TX_AMOUNT, script_pubkey: receiver_script)
23
-
24
- fill_change_tpc(tx, wallet, sum - fee - FUNDING_TX_AMOUNT)
25
- wallet.internal_wallet.sign_tx(tx)
14
+ def create_funding_tx(wallet:, script: nil, fee_estimator: FixedFeeEstimator.new, utxo_provider: nil)
15
+ if utxo_provider
16
+ script_pubkey = script ? script : Tapyrus::Script.parse_from_addr(wallet.internal_wallet.receive_address)
17
+ funding_tx, _index = utxo_provider.get_utxo(script_pubkey, FUNDING_TX_AMOUNT)
18
+ utxo_provider.wallet.sign_tx(funding_tx)
19
+ else
20
+ txb = Tapyrus::TxBuilder.new
21
+ fee = fee_estimator.fee(dummy_tx(txb.build))
22
+
23
+ sum, outputs = wallet.internal_wallet.collect_uncolored_outputs(fee + FUNDING_TX_AMOUNT)
24
+ outputs.each do |utxo|
25
+ txb.add_utxo({
26
+ script_pubkey: Tapyrus::Script.parse_from_payload(utxo[:script_pubkey].htb),
27
+ txid: utxo[:txid],
28
+ index: utxo[:vout],
29
+ value: utxo[:amount]
30
+ })
31
+ end
32
+
33
+ receiver_address = script ? script.addresses.first : wallet.internal_wallet.receive_address
34
+ tx = txb.pay(receiver_address, FUNDING_TX_AMOUNT)
35
+ .change_address(wallet.internal_wallet.change_address)
36
+ .fee(fee)
37
+ .build
38
+ wallet.internal_wallet.sign_tx(tx)
39
+ end
26
40
  end
27
41
 
28
42
  def create_issue_tx_for_reissuable_token(funding_tx:, issuer:, amount:, fee_estimator: FixedFeeEstimator.new)
@@ -48,21 +62,27 @@ module Glueby
48
62
  issuer.internal_wallet.sign_tx(tx, prev_txs)
49
63
  end
50
64
 
51
- def create_issue_tx_for_non_reissuable_token(issuer:, amount:, fee_estimator: FixedFeeEstimator.new)
52
- create_issue_tx_from_out_point(token_type: Tapyrus::Color::TokenTypes::NON_REISSUABLE, issuer: issuer, amount: amount, fee_estimator: fee_estimator)
65
+ def create_issue_tx_for_non_reissuable_token(funding_tx: nil, issuer:, amount:, fee_estimator: FixedFeeEstimator.new)
66
+ create_issue_tx_from_out_point(funding_tx: funding_tx, token_type: Tapyrus::Color::TokenTypes::NON_REISSUABLE, issuer: issuer, amount: amount, fee_estimator: fee_estimator)
53
67
  end
54
68
 
55
- def create_issue_tx_for_nft_token(issuer:, fee_estimator: FixedFeeEstimator.new)
56
- create_issue_tx_from_out_point(token_type: Tapyrus::Color::TokenTypes::NFT, issuer: issuer, amount: 1, fee_estimator: fee_estimator)
69
+ def create_issue_tx_for_nft_token(funding_tx: nil, issuer:, fee_estimator: FixedFeeEstimator.new)
70
+ create_issue_tx_from_out_point(funding_tx: funding_tx, token_type: Tapyrus::Color::TokenTypes::NFT, issuer: issuer, amount: 1, fee_estimator: fee_estimator)
57
71
  end
58
72
 
59
- def create_issue_tx_from_out_point(token_type:, issuer:, amount:, fee_estimator: FixedFeeEstimator.new)
73
+ def create_issue_tx_from_out_point(funding_tx: nil, token_type:, issuer:, amount:, fee_estimator: FixedFeeEstimator.new)
60
74
  tx = Tapyrus::Tx.new
61
75
 
62
76
  fee = fee_estimator.fee(dummy_issue_tx_from_out_point)
63
- sum, outputs = issuer.internal_wallet.collect_uncolored_outputs(fee)
64
- fill_input(tx, outputs)
65
-
77
+ sum = if funding_tx
78
+ out_point = Tapyrus::OutPoint.from_txid(funding_tx.txid, 0)
79
+ tx.inputs << Tapyrus::TxIn.new(out_point: out_point)
80
+ funding_tx.outputs.first.value
81
+ else
82
+ sum, outputs = issuer.internal_wallet.collect_uncolored_outputs(fee)
83
+ fill_input(tx, outputs)
84
+ sum
85
+ end
66
86
  out_point = tx.inputs.first.out_point
67
87
  color_id = case token_type
68
88
  when Tapyrus::Color::TokenTypes::NON_REISSUABLE
@@ -78,7 +98,18 @@ module Glueby
78
98
  tx.outputs << Tapyrus::TxOut.new(value: amount, script_pubkey: receiver_colored_script)
79
99
 
80
100
  fill_change_tpc(tx, issuer, sum - fee)
81
- issuer.internal_wallet.sign_tx(tx)
101
+ prev_txs = if funding_tx
102
+ output = funding_tx.outputs.first
103
+ [{
104
+ txid: funding_tx.txid,
105
+ vout: 0,
106
+ scriptPubKey: output.script_pubkey.to_hex,
107
+ amount: output.value
108
+ }]
109
+ else
110
+ []
111
+ end
112
+ issuer.internal_wallet.sign_tx(tx, prev_txs)
82
113
  end
83
114
 
84
115
  def create_reissue_tx(funding_tx:, issuer:, amount:, color_id:, fee_estimator: FixedFeeEstimator.new)
@@ -103,7 +134,7 @@ module Glueby
103
134
  issuer.internal_wallet.sign_tx(tx, prev_txs)
104
135
  end
105
136
 
106
- def create_transfer_tx(color_id:, sender:, receiver_address:, amount:, fee_estimator: FixedFeeEstimator.new)
137
+ def create_transfer_tx(funding_tx:nil, color_id:, sender:, receiver_address:, amount:, fee_estimator: FixedFeeEstimator.new)
107
138
  tx = Tapyrus::Tx.new
108
139
 
109
140
  utxos = sender.internal_wallet.list_unspent
@@ -117,14 +148,32 @@ module Glueby
117
148
  fill_change_token(tx, sender, sum_token - amount, color_id)
118
149
 
119
150
  fee = fee_estimator.fee(dummy_tx(tx))
120
- sum_tpc, outputs = sender.internal_wallet.collect_uncolored_outputs(fee)
121
- fill_input(tx, outputs)
151
+ sum_tpc = if funding_tx
152
+ out_point = Tapyrus::OutPoint.from_txid(funding_tx.txid, 0)
153
+ tx.inputs << Tapyrus::TxIn.new(out_point: out_point)
154
+ funding_tx.outputs.first.value
155
+ else
156
+ sum_tpc, outputs = sender.internal_wallet.collect_uncolored_outputs(fee)
157
+ fill_input(tx, outputs)
158
+ sum_tpc
159
+ end
122
160
 
123
161
  fill_change_tpc(tx, sender, sum_tpc - fee)
124
- sender.internal_wallet.sign_tx(tx)
162
+ prev_txs = if funding_tx
163
+ output = funding_tx.outputs.first
164
+ [{
165
+ txid: funding_tx.txid,
166
+ vout: 0,
167
+ scriptPubKey: output.script_pubkey.to_hex,
168
+ amount: output.value
169
+ }]
170
+ else
171
+ []
172
+ end
173
+ sender.internal_wallet.sign_tx(tx, prev_txs)
125
174
  end
126
175
 
127
- def create_burn_tx(color_id:, sender:, amount: 0, fee_estimator: FixedFeeEstimator.new)
176
+ def create_burn_tx(funding_tx:nil, color_id:, sender:, amount: 0, fee_estimator: FixedFeeEstimator.new)
128
177
  tx = Tapyrus::Tx.new
129
178
 
130
179
  utxos = sender.internal_wallet.list_unspent
@@ -135,12 +184,30 @@ module Glueby
135
184
 
136
185
  fee = fee_estimator.fee(dummy_tx(tx))
137
186
 
138
- dust = 600 # in case that the wallet has output which has just fee amount.
139
- sum_tpc, outputs = sender.internal_wallet.collect_uncolored_outputs(fee + dust)
140
- fill_input(tx, outputs)
187
+ sum_tpc = if funding_tx
188
+ out_point = Tapyrus::OutPoint.from_txid(funding_tx.txid, 0)
189
+ tx.inputs << Tapyrus::TxIn.new(out_point: out_point)
190
+ funding_tx.outputs.first.value
191
+ else
192
+ dust = 600 # in case that the wallet has output which has just fee amount.
193
+ sum_tpc, outputs = sender.internal_wallet.collect_uncolored_outputs(fee + dust)
194
+ fill_input(tx, outputs)
195
+ sum_tpc
196
+ end
141
197
 
142
198
  fill_change_tpc(tx, sender, sum_tpc - fee)
143
- sender.internal_wallet.sign_tx(tx)
199
+ prev_txs = if funding_tx
200
+ output = funding_tx.outputs.first
201
+ [{
202
+ txid: funding_tx.txid,
203
+ vout: 0,
204
+ scriptPubKey: output.script_pubkey.to_hex,
205
+ amount: output.value
206
+ }]
207
+ else
208
+ []
209
+ end
210
+ sender.internal_wallet.sign_tx(tx, prev_txs)
144
211
  end
145
212
 
146
213
  def fill_input(tx, outputs)
@@ -81,7 +81,7 @@ module Glueby
81
81
  end
82
82
 
83
83
  # Show the address of Fee Provider
84
- def address
84
+ def print_address
85
85
  puts wallet.receive_address
86
86
  end
87
87
 
@@ -8,6 +8,7 @@ module Glueby
8
8
  WALLET_ID = 'FEE_PROVIDER_WALLET'
9
9
  DEFAULT_FIXED_FEE = 1000
10
10
  DEFAULT_UTXO_POOL_SIZE = 20
11
+ MAX_UTXO_POOL_SIZE = 2_000
11
12
 
12
13
  attr_reader :fixed_fee, :utxo_pool_size, :wallet,
13
14
 
@@ -33,6 +34,7 @@ module Glueby
33
34
  Internal::Wallet.create(WALLET_ID)
34
35
  end
35
36
 
37
+ validate_config!
36
38
  @fixed_fee = (FeeProvider.config && FeeProvider.config[:fixed_fee]) || DEFAULT_FIXED_FEE
37
39
  @utxo_pool_size = (FeeProvider.config && FeeProvider.config[:utxo_pool_size]) || DEFAULT_UTXO_POOL_SIZE
38
40
  end
@@ -69,5 +71,14 @@ module Glueby
69
71
  def get_signature(script_sig)
70
72
  script_sig.chunks.first.pushed_data
71
73
  end
74
+
75
+ def validate_config!
76
+ if FeeProvider.config
77
+ utxo_pool_size = FeeProvider.config[:utxo_pool_size]
78
+ if utxo_pool_size && (!utxo_pool_size.is_a?(Integer) || utxo_pool_size > MAX_UTXO_POOL_SIZE)
79
+ raise Glueby::Configuration::Errors::InvalidConfiguration, "utxo_pool_size(#{utxo_pool_size}) should not be greater than #{MAX_UTXO_POOL_SIZE}"
80
+ end
81
+ end
82
+ end
72
83
  end
73
84
  end
@@ -72,6 +72,8 @@ module Glueby
72
72
  # @param [Boolean] only_finalized - The UTXOs includes only finalized UTXO value if it
73
73
  # is true. Default is true.
74
74
  # @param [String] label - Label for filtering UTXOs
75
+ # - If label is nil or :unlabeled, only unlabeled UTXOs will be returned.
76
+ # - If label=:all, it will return all utxos
75
77
  # @return [Array of UTXO]
76
78
  #
77
79
  # ## The UTXO structure
@@ -101,8 +103,10 @@ module Glueby
101
103
  #
102
104
  # @param [String] wallet_id - The wallet id that is offered by `create_wallet()` method.
103
105
  # @param [Tapyrus::Tx] tx - The transaction to be broadcasterd.
106
+ # @yield Option. If a block given, the block is called before actual broadcasting.
107
+ # @yieldparam [Tapyrus::Tx] tx - The tx that is going to be broadcasted as is.
104
108
  # @return [String] txid
105
- def broadcast(wallet_id, tx)
109
+ def broadcast(wallet_id, tx, &block)
106
110
  raise NotImplementedError, "You must implement #{self.class}##{__method__}"
107
111
  end
108
112
 
@@ -93,8 +93,15 @@ module Glueby
93
93
  wallet = AR::Wallet.find_by(wallet_id: wallet_id)
94
94
  utxos = wallet.utxos
95
95
  utxos = utxos.where(status: :finalized) if only_finalized
96
- utxos = utxos.where(label: label) if label && (label != :unlabeled)
97
- utxos = utxos.where(label: nil) if label == :unlabeled
96
+
97
+ if [:unlabeled, nil].include?(label)
98
+ utxos = utxos.where(label: nil)
99
+ elsif label && (label != :all)
100
+ utxos = utxos.where(label: label)
101
+ else
102
+ utxos
103
+ end
104
+
98
105
  utxos.map do |utxo|
99
106
  {
100
107
  txid: utxo.txid,
@@ -102,7 +109,8 @@ module Glueby
102
109
  script_pubkey: utxo.script_pubkey,
103
110
  color_id: utxo.color_id,
104
111
  amount: utxo.value,
105
- finalized: utxo.status == 'finalized'
112
+ finalized: utxo.status == 'finalized',
113
+ label: utxo.label
106
114
  }
107
115
  end
108
116
  end
@@ -112,10 +120,11 @@ module Glueby
112
120
  wallet.sign(tx, prevtxs, sighashtype: sighashtype)
113
121
  end
114
122
 
115
- def broadcast(wallet_id, tx)
123
+ def broadcast(wallet_id, tx, &block)
116
124
  ::ActiveRecord::Base.transaction do
117
125
  AR::Utxo.destroy_for_inputs(tx)
118
126
  AR::Utxo.create_or_update_for_outputs(tx, status: :broadcasted)
127
+ block.call(tx) if block
119
128
  Glueby::Internal::RPC.client.sendrawtransaction(tx.to_hex)
120
129
  end
121
130
  end
@@ -23,7 +23,6 @@ module Glueby
23
23
  include Glueby::Internal::Wallet::TapyrusCoreWalletAdapter::Util
24
24
 
25
25
  WALLET_PREFIX = 'wallet-'
26
- ADDRESS_TYPE = 'legacy'
27
26
 
28
27
  RPC_WALLET_ERROR_ERROR_CODE = -4 # Unspecified problem with wallet (key not found etc.)
29
28
  RPC_WALLET_NOT_FOUND_ERROR_CODE = -18 # Invalid wallet specified
@@ -83,14 +82,21 @@ module Glueby
83
82
  end
84
83
  end
85
84
 
85
+ # If label=nil, it will return unlabeled utxos to protect labeled utxos for specific purpose
86
+ # If label=:all, it will return all utxos
86
87
  def list_unspent(wallet_id, only_finalized = true, label = nil)
87
88
  perform_as(wallet_id) do |client|
88
89
  min_conf = only_finalized ? 1 : 0
89
90
  res = client.listunspent(min_conf)
90
91
 
91
- res = res.filter { |i| i['label'] == label } if label && (label != :unlabeled)
92
- res = res.filter { |i| i['label'] == "" } if label == :unlabeled
93
-
92
+ if [:unlabeled, nil].include?(label)
93
+ res = res.filter { |i| i['label'] == "" }
94
+ elsif label && (label != :all)
95
+ res = res.filter { |i| i['label'] == label }
96
+ else
97
+ res
98
+ end
99
+
94
100
  res.map do |i|
95
101
  script = Tapyrus::Script.parse_from_payload(i['scriptPubKey'].htb)
96
102
  color_id = if script.cp2pkh? || script.cp2sh?
@@ -102,7 +108,8 @@ module Glueby
102
108
  script_pubkey: i['scriptPubKey'],
103
109
  color_id: color_id,
104
110
  amount: tpc_to_tapyrus(i['amount']),
105
- finalized: i['confirmations'] != 0
111
+ finalized: i['confirmations'] != 0,
112
+ label: i['label']
106
113
  }
107
114
  end
108
115
  end
@@ -119,27 +126,28 @@ module Glueby
119
126
  end
120
127
  end
121
128
 
122
- def broadcast(wallet_id, tx)
129
+ def broadcast(wallet_id, tx, &block)
123
130
  perform_as(wallet_id) do |client|
131
+ block.call(tx) if block
124
132
  client.sendrawtransaction(tx.to_hex)
125
133
  end
126
134
  end
127
135
 
128
136
  def receive_address(wallet_id, label = nil)
129
137
  perform_as(wallet_id) do |client|
130
- client.getnewaddress(label || '', ADDRESS_TYPE)
138
+ client.getnewaddress(label || '')
131
139
  end
132
140
  end
133
141
 
134
142
  def change_address(wallet_id)
135
143
  perform_as(wallet_id) do |client|
136
- client.getrawchangeaddress(ADDRESS_TYPE)
144
+ client.getrawchangeaddress
137
145
  end
138
146
  end
139
147
 
140
148
  def create_pubkey(wallet_id)
141
149
  perform_as(wallet_id) do |client|
142
- address = client.getnewaddress('', ADDRESS_TYPE)
150
+ address = client.getnewaddress('')
143
151
  info = client.getaddressinfo(address)
144
152
  Tapyrus::Key.new(pubkey: info['pubkey'])
145
153
  end
@@ -84,9 +84,10 @@ module Glueby
84
84
 
85
85
  # @param only_finalized [Boolean] The flag to get a UTXO with status only finalized
86
86
  # @param label [String] This label is used to filtered the UTXOs with labeled if a key or Utxo is labeled.
87
- # - If label is not specified (label=nil), all UTXOs will be returned.
88
- # - If label=:unlabeled, only unlabeled UTXOs will be returned.
89
- def list_unspent(only_finalized = true, label = nil)
87
+ # - If label is nil or :unlabeled, only unlabeled UTXOs will be returned.
88
+ # - If label=:all, all UTXOs will be returned.
89
+ def list_unspent(only_finalized = true, label = :unlabeled)
90
+ label = :unlabeled unless label
90
91
  wallet_adapter.list_unspent(id, only_finalized, label)
91
92
  end
92
93
 
@@ -117,10 +118,7 @@ module Glueby
117
118
  # @param [Proc] block The block that is called before broadcasting. It can be used to handle tx that is modified by FeeProvider.
118
119
  def broadcast(tx, without_fee_provider: false, &block)
119
120
  tx = FeeProvider.provide(tx) if !without_fee_provider && Glueby.configuration.fee_provider_bears?
120
-
121
- block.call(tx) if block
122
-
123
- wallet_adapter.broadcast(id, tx)
121
+ wallet_adapter.broadcast(id, tx, &block)
124
122
  tx
125
123
  end
126
124
 
@@ -136,8 +134,9 @@ module Glueby
136
134
  wallet_adapter.create_pubkey(id)
137
135
  end
138
136
 
139
- def collect_uncolored_outputs(amount, label = nil)
140
- utxos = list_unspent(true, label)
137
+ def collect_uncolored_outputs(amount, label = nil, only_finalized = true, shuffle = false)
138
+ utxos = list_unspent(only_finalized, label)
139
+ utxos.shuffle! if shuffle
141
140
 
142
141
  utxos.inject([0, []]) do |sum, output|
143
142
  next sum if output[:color_id]
@@ -1,14 +1,11 @@
1
1
  module Glueby
2
2
  class Railtie < ::Rails::Railtie
3
- initializer "glueby.register_syncers" do
4
- BlockSyncer.register_syncer(Contract::Timestamp::Syncer)
5
- end
6
-
7
3
  rake_tasks do
8
4
  load "tasks/glueby/contract.rake"
9
5
  load "tasks/glueby/contract/timestamp.rake"
10
6
  load "tasks/glueby/block_syncer.rake"
11
7
  load "tasks/glueby/fee_provider.rake"
8
+ load "tasks/glueby/utxo_provider.rake"
12
9
  end
13
10
  end
14
11
  end
@@ -0,0 +1,135 @@
1
+ module Glueby
2
+ class UtxoProvider
3
+ class Tasks
4
+ include Glueby::Contract::TxBuilder
5
+
6
+ attr_reader :utxo_provider
7
+
8
+ STATUS = {
9
+ # UtxoProvider is ready to pay tpcs.
10
+ ready: 'Ready',
11
+ # UtxoProvider is ready to pay tpcs, but it doesn't have enough amount to fill the UTXO pool by UTXOs which is for paying tpcs.
12
+ insufficient_amount: 'Insufficient Amount',
13
+ # UtxoProvider is not ready to pay tpcs. It has no UTXOs for paying amounts.
14
+ not_ready: 'Not Ready'
15
+ }
16
+
17
+ def initialize
18
+ @utxo_provider = Glueby::UtxoProvider.new
19
+ end
20
+
21
+ # Create UTXOs for paying tpc
22
+ #
23
+ # UtxoProvider have the UTXO pool. the pool is manged to keep some number of UTXOs that have fixed value. The
24
+ # value is configurable by :default_value. This method do the management to the pool.
25
+ def manage_utxo_pool
26
+ txb = Tapyrus::TxBuilder.new
27
+
28
+ sum, utxos = collect_outputs
29
+ return if utxos.empty?
30
+
31
+ utxos.each { |utxo| txb.add_utxo(utxo) }
32
+ address = wallet.receive_address
33
+
34
+ shortage = [utxo_provider.utxo_pool_size - current_utxo_pool_size, 0].max
35
+ return if shortage == 0
36
+
37
+ added_outputs = 0
38
+ shortage.times do
39
+ fee = utxo_provider.fee_estimator.fee(dummy_tx(txb.build))
40
+ break if (sum - fee) < utxo_provider.default_value
41
+ txb.pay(address, utxo_provider.default_value)
42
+ sum -= utxo_provider.default_value
43
+ added_outputs += 1
44
+ end
45
+
46
+ return if added_outputs == 0
47
+
48
+ fee = utxo_provider.fee_estimator.fee(dummy_tx(txb.build))
49
+ tx = txb.change_address(address)
50
+ .fee(fee)
51
+ .build
52
+ tx = wallet.sign_tx(tx)
53
+ wallet.broadcast(tx)
54
+ ensure
55
+ status
56
+ end
57
+
58
+ # Show the status of the UTXO pool
59
+ def status
60
+ status = :ready
61
+
62
+ if current_utxo_pool_size < utxo_provider.utxo_pool_size
63
+ if tpc_amount < value_to_fill_utxo_pool
64
+ status = :insufficient_amount
65
+ message = <<~MESSAGE
66
+ 1. Please replenishment TPC which is for paying tpc to UtxoProvider.
67
+ UtxoProvider needs #{value_to_fill_utxo_pool} tapyrus in UTXO pool.
68
+ UtxoProvider wallet's address is '#{wallet.receive_address}'
69
+ 2. Then create UTXOs for paying in UTXO pool with 'rake glueby:utxo_provider:manage_utxo_pool'
70
+ MESSAGE
71
+ else
72
+ message = "Please create UTXOs for paying in UTXO pool with 'rake glueby:utxo_provider:manage_utxo_pool'\n"
73
+ end
74
+ end
75
+
76
+ status = :not_ready if current_utxo_pool_size == 0
77
+
78
+ puts <<~EOS
79
+ Status: #{STATUS[status]}
80
+ TPC amount: #{delimit(tpc_amount)}
81
+ UTXO pool size: #{delimit(current_utxo_pool_size)}
82
+ #{"\n" if message}#{message}
83
+ Configuration:
84
+ default_value = #{delimit(utxo_provider.default_value)}
85
+ utxo_pool_size = #{delimit(utxo_provider.utxo_pool_size)}
86
+ EOS
87
+ end
88
+
89
+ # Show the address of Utxo Provider
90
+ def print_address
91
+ puts wallet.receive_address
92
+ end
93
+
94
+ private
95
+
96
+ def tpc_amount
97
+ wallet.balance(false)
98
+ end
99
+
100
+ def collect_outputs
101
+ wallet.list_unspent.inject([0, []]) do |sum, output|
102
+ next sum if output[:color_id] || output[:amount] == utxo_provider.default_value
103
+
104
+ new_sum = sum[0] + output[:amount]
105
+ new_outputs = sum[1] << {
106
+ txid: output[:txid],
107
+ script_pubkey: output[:script_pubkey],
108
+ value: output[:amount],
109
+ index: output[:vout] ,
110
+ finalized: output[:finalized]
111
+ }
112
+ [new_sum, new_outputs]
113
+ end
114
+ end
115
+
116
+ def current_utxo_pool_size
117
+ wallet
118
+ .list_unspent(false)
119
+ .count { |o| !o[:color_id] && o[:amount] == utxo_provider.default_value }
120
+ end
121
+
122
+ def value_to_fill_utxo_pool
123
+ utxo_provider.default_value * utxo_provider.utxo_pool_size
124
+ end
125
+
126
+ def wallet
127
+ utxo_provider.wallet
128
+ end
129
+
130
+ def delimit(num)
131
+ num.to_s.reverse.scan(/.{1,3}/).join('_').reverse
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,85 @@
1
+ module Glueby
2
+ class UtxoProvider
3
+ include Glueby::Contract::TxBuilder
4
+
5
+ autoload :Tasks, 'glueby/utxo_provider/tasks'
6
+
7
+ WALLET_ID = 'UTXO_PROVIDER_WALLET'
8
+ DEFAULT_VALUE = 1_000
9
+ DEFAULT_UTXO_POOL_SIZE = 20
10
+ MAX_UTXO_POOL_SIZE = 2_000
11
+
12
+ class << self
13
+ attr_reader :config
14
+
15
+ # @param [Hash] config
16
+ # @option config [Integer] :default_value
17
+ # @option opts [Integer] :utxo_pool_size
18
+ # @option opts [Glueby::Contract::FeeEstimator] :fee_estimator
19
+ def configure(config)
20
+ @config = config
21
+ end
22
+ end
23
+
24
+ def initialize
25
+ @wallet = load_wallet
26
+ validate_config!
27
+ @fee_estimator = (UtxoProvider.config && UtxoProvider.config[:fee_estimator]) || Glueby::Contract::FixedFeeEstimator.new
28
+ @default_value = (UtxoProvider.config && UtxoProvider.config[:default_value]) || DEFAULT_VALUE
29
+ @utxo_pool_size = (UtxoProvider.config && UtxoProvider.config[:utxo_pool_size]) || DEFAULT_UTXO_POOL_SIZE
30
+ end
31
+
32
+ attr_reader :wallet, :fee_estimator, :default_value, :utxo_pool_size
33
+
34
+ # Provide a UTXO
35
+ # @param [Tapyrus::Script] script_pubkey The script to be provided
36
+ # @param [Integer] value The tpc amount to be provided
37
+ # @return [Array<(Tapyrus::Tx, Integer)>]
38
+ # The tx that has a UTXO to be provided in its outputs.
39
+ # The output index in the tx to indicate the place of a provided UTXO.
40
+ # @raise [Glueby::Contract::Errors::InsufficientFunds] if provider does not have any utxo which has specified value.
41
+ def get_utxo(script_pubkey, value = DEFAULT_VALUE)
42
+ txb = Tapyrus::TxBuilder.new
43
+ txb.pay(script_pubkey.addresses.first, value)
44
+
45
+ fee = fee_estimator.fee(dummy_tx(txb.build))
46
+ # The outputs need to be shuffled so that no utxos are spent twice as possible.
47
+ sum, outputs = wallet.collect_uncolored_outputs(fee + value, nil, true, true)
48
+
49
+ outputs.each do |utxo|
50
+ txb.add_utxo({
51
+ script_pubkey: Tapyrus::Script.parse_from_payload(utxo[:script_pubkey].htb),
52
+ txid: utxo[:txid],
53
+ index: utxo[:vout],
54
+ value: utxo[:amount]
55
+ })
56
+ end
57
+
58
+ txb.fee(fee).change_address(wallet.change_address)
59
+
60
+ tx = txb.build
61
+ signed_tx = wallet.sign_tx(tx)
62
+ [signed_tx, 0]
63
+ end
64
+
65
+ private
66
+
67
+ # Create wallet for provider
68
+ def load_wallet
69
+ begin
70
+ Glueby::Internal::Wallet.load(WALLET_ID)
71
+ rescue Glueby::Internal::Wallet::Errors::WalletNotFound => _
72
+ Glueby::Internal::Wallet.create(WALLET_ID)
73
+ end
74
+ end
75
+
76
+ def validate_config!
77
+ if UtxoProvider.config
78
+ utxo_pool_size = UtxoProvider.config[:utxo_pool_size]
79
+ if utxo_pool_size && (!utxo_pool_size.is_a?(Integer) || utxo_pool_size > MAX_UTXO_POOL_SIZE)
80
+ raise Glueby::Configuration::Errors::InvalidConfiguration, "utxo_pool_size(#{utxo_pool_size}) should not be greater than #{MAX_UTXO_POOL_SIZE}"
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -1,3 +1,3 @@
1
1
  module Glueby
2
- VERSION = "0.4.2"
2
+ VERSION = "0.5.1"
3
3
  end
data/lib/glueby.rb CHANGED
@@ -10,6 +10,7 @@ module Glueby
10
10
  autoload :FeeProvider, 'glueby/fee_provider'
11
11
  autoload :Configuration, 'glueby/configuration'
12
12
  autoload :BlockSyncer, 'glueby/block_syncer'
13
+ autoload :UtxoProvider, 'glueby/utxo_provider'
13
14
 
14
15
  if defined? ::Rails::Railtie
15
16
  require 'glueby/railtie'
@@ -8,15 +8,22 @@ module Glueby
8
8
 
9
9
  def create
10
10
  timestamps = Glueby::Contract::AR::Timestamp.where(status: :init)
11
+ utxo_provider = Glueby::UtxoProvider.new if Glueby.configuration.use_utxo_provider?
11
12
  timestamps.each do |t|
12
13
  begin
14
+ wallet = Glueby::Wallet.load(t.wallet_id)
15
+ funding_tx, tx = create_txs(wallet, t.prefix, t.content_hash, Glueby::Contract::FixedFeeEstimator.new, utxo_provider)
16
+ if funding_tx
17
+ ::ActiveRecord::Base.transaction do
18
+ wallet.internal_wallet.broadcast(funding_tx)
19
+ puts "funding tx was broadcasted(id=#{t.id}, funding_tx.txid=#{funding_tx.txid})"
20
+ end
21
+ end
13
22
  ::ActiveRecord::Base.transaction do
14
- wallet = Glueby::Wallet.load(t.wallet_id)
15
- tx = create_tx(wallet, t.prefix, t.content_hash, Glueby::Contract::FixedFeeEstimator.new)
16
23
  wallet.internal_wallet.broadcast(tx) do |tx|
17
24
  t.update(txid: tx.txid, status: :unconfirmed)
18
25
  end
19
- puts "broadcasted (id=#{t.id}, txid=#{tx.txid})"
26
+ puts "timestamp tx was broadcasted (id=#{t.id}, txid=#{tx.txid})"
20
27
  end
21
28
  rescue => e
22
29
  puts "failed to broadcast (id=#{t.id}, reason=#{e.message})"
@@ -12,7 +12,7 @@ namespace :glueby do
12
12
 
13
13
  desc 'Show the address of the Glueby::FeeProvider'
14
14
  task :address, [] => [:environment] do |_, _|
15
- Glueby::FeeProvider::Tasks.new.address
15
+ Glueby::FeeProvider::Tasks.new.print_address
16
16
  end
17
17
  end
18
18
  end
@@ -0,0 +1,18 @@
1
+ namespace :glueby do
2
+ namespace :utxo_provider do
3
+ desc 'Manage the UTXO pool in Glueby::UtxoProvider. Creates outputs for paying utxo if the outputs is less than configured pool size by :utxo_pool_size'
4
+ task :manage_utxo_pool, [] => [:environment] do |_, _|
5
+ Glueby::UtxoProvider::Tasks.new.manage_utxo_pool
6
+ end
7
+
8
+ desc 'Show the status of the UTXO pool in Glueby::UtxoProvider'
9
+ task :status, [] => [:environment] do |_, _|
10
+ Glueby::UtxoProvider::Tasks.new.status
11
+ end
12
+
13
+ desc 'Show the address of the Glueby::UtxoProvider'
14
+ task :address, [] => [:environment] do |_, _|
15
+ Glueby::UtxoProvider::Tasks.new.print_address
16
+ end
17
+ end
18
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: glueby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - azuchi
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-08-15 00:00:00.000000000 Z
11
+ date: 2021-12-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: tapyrus
@@ -28,16 +28,16 @@ dependencies:
28
28
  name: activerecord
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">="
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: 6.1.3
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ">="
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
40
+ version: 6.1.3
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: sqlite3
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rails
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 6.1.3
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 6.1.3
55
69
  description: A Ruby library of smart contracts that can be used on Tapyrus.
56
70
  email:
57
71
  - azuchi@chaintope.com
@@ -117,12 +131,15 @@ files:
117
131
  - lib/glueby/internal/wallet/errors.rb
118
132
  - lib/glueby/internal/wallet/tapyrus_core_wallet_adapter.rb
119
133
  - lib/glueby/railtie.rb
134
+ - lib/glueby/utxo_provider.rb
135
+ - lib/glueby/utxo_provider/tasks.rb
120
136
  - lib/glueby/version.rb
121
137
  - lib/glueby/wallet.rb
122
138
  - lib/tasks/glueby/block_syncer.rake
123
139
  - lib/tasks/glueby/contract.rake
124
140
  - lib/tasks/glueby/contract/timestamp.rake
125
141
  - lib/tasks/glueby/fee_provider.rake
142
+ - lib/tasks/glueby/utxo_provider.rake
126
143
  homepage: https://github.com/chaintope/glueby
127
144
  licenses:
128
145
  - MIT