glueby 1.2.3 → 1.3.0
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 +4 -8
- data/.ruby-version +1 -1
- data/Gemfile +2 -0
- data/glueby.gemspec +2 -1
- data/lib/generators/glueby/contract/templates/timestamp_table.rb.erb +1 -1
- data/lib/generators/glueby/contract/templates/utxo_table.rb.erb +1 -0
- data/lib/glueby/configuration.rb +1 -1
- data/lib/glueby/contract/active_record/timestamp.rb +25 -6
- data/lib/glueby/contract/errors.rb +1 -0
- data/lib/glueby/contract/timestamp.rb +53 -4
- data/lib/glueby/contract/token.rb +0 -27
- data/lib/glueby/contract/tx_builder.rb +5 -8
- data/lib/glueby/fee_provider/tasks.rb +0 -10
- data/lib/glueby/internal/contract_builder.rb +1 -1
- data/lib/glueby/internal/wallet/abstract_wallet_adapter.rb +20 -2
- data/lib/glueby/internal/wallet/active_record/utxo.rb +1 -0
- data/lib/glueby/internal/wallet/active_record_wallet_adapter.rb +43 -22
- data/lib/glueby/internal/wallet/tapyrus_core_wallet_adapter.rb +9 -2
- data/lib/glueby/internal/wallet.rb +24 -9
- data/lib/glueby/version.rb +1 -1
- data/lib/glueby/wallet.rb +4 -0
- data/lib/glueby.rb +1 -1
- metadata +21 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 41286c658b45bd9914f4c46f27e8e0f8696b61a8d763b5fcc2b0117d0e91668d
|
4
|
+
data.tar.gz: 3237815c98b14f3fc126e5531c8ff229d468fe77832bcca4b22828ffd386c7bd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dad03d9f436a2720b854450fb95e8fab7fedde3d721f5db3bf0c69c1aa7b818ebfc359cda0c1057f4d98075295459f55f5261c69a4cc99a49f752bba3683e95c
|
7
|
+
data.tar.gz: eb8f0724b6b7b849a343b14e5630480584df5b6f408509dcdeebcca711055f8bcd3a62c188130b75118a7f93e18e015aeb2afd60784d4382cd27741b010f2c06
|
data/.github/workflows/ruby.yml
CHANGED
@@ -7,19 +7,15 @@
|
|
7
7
|
|
8
8
|
name: Ruby
|
9
9
|
|
10
|
-
on:
|
11
|
-
push:
|
12
|
-
branches: [master, v1.1, v1.2]
|
13
|
-
pull_request:
|
14
|
-
branches: [master, v1.1, v1.2]
|
10
|
+
on: [push,pull_request]
|
15
11
|
|
16
12
|
jobs:
|
17
13
|
test:
|
18
14
|
runs-on: ubuntu-latest
|
19
15
|
strategy:
|
20
16
|
matrix:
|
21
|
-
ruby-version: ["
|
22
|
-
|
17
|
+
ruby-version: ["3.0", "3.1", "3.2", "3.3"]
|
18
|
+
permissions: write-all
|
23
19
|
steps:
|
24
20
|
- run: docker pull tapyrus/tapyrusd:v0.5.2
|
25
21
|
- uses: actions/checkout@v2
|
@@ -31,4 +27,4 @@ jobs:
|
|
31
27
|
ruby-version: ${{ matrix.ruby-version }}
|
32
28
|
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
33
29
|
- name: Run tests
|
34
|
-
run: bundle exec rake
|
30
|
+
run: bundle exec rake
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
ruby-3.
|
1
|
+
ruby-3.3.0
|
data/Gemfile
CHANGED
data/glueby.gemspec
CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.description = %q{A Ruby library of smart contracts that can be used on Tapyrus.}
|
11
11
|
spec.homepage = "https://github.com/chaintope/glueby"
|
12
12
|
spec.license = "MIT"
|
13
|
-
spec.required_ruby_version = Gem::Requirement.new(">=
|
13
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 3.0.0")
|
14
14
|
|
15
15
|
|
16
16
|
spec.metadata["homepage_uri"] = spec.homepage
|
@@ -28,6 +28,7 @@ Gem::Specification.new do |spec|
|
|
28
28
|
|
29
29
|
spec.add_runtime_dependency 'tapyrus', '>= 0.3.1'
|
30
30
|
spec.add_runtime_dependency 'activerecord', '~> 7.0.0'
|
31
|
+
spec.add_runtime_dependency 'kaminari'
|
31
32
|
spec.add_development_dependency 'sqlite3'
|
32
33
|
spec.add_development_dependency 'mysql2'
|
33
34
|
spec.add_development_dependency 'rails', '~> 7.0.0'
|
@@ -13,7 +13,7 @@ class CreateTimestamp < ActiveRecord::Migration<%= migration_version %>
|
|
13
13
|
t.string :payment_base
|
14
14
|
t.bigint :prev_id
|
15
15
|
t.boolean :latest, null: false, default: true
|
16
|
-
t.
|
16
|
+
t.string :version, null: false, default: "1"
|
17
17
|
end
|
18
18
|
|
19
19
|
add_index :glueby_timestamps, [:prev_id], unique: true
|
data/lib/glueby/configuration.rb
CHANGED
@@ -24,7 +24,7 @@ module Glueby
|
|
24
24
|
end
|
25
25
|
|
26
26
|
# Specify wallet adapter.
|
27
|
-
# @param [Symbol] adapter - The adapter type :activerecord or :
|
27
|
+
# @param [Symbol] adapter - The adapter type :activerecord, :core, or :mysql is currently supported.
|
28
28
|
def wallet_adapter=(adapter)
|
29
29
|
case adapter
|
30
30
|
when :core
|
@@ -9,7 +9,14 @@ module Glueby
|
|
9
9
|
|
10
10
|
attr_reader :tx
|
11
11
|
|
12
|
-
belongs_to :prev, class_name: 'Glueby::Contract::AR::Timestamp', optional: true
|
12
|
+
belongs_to :prev, class_name: 'Glueby::Contract::AR::Timestamp', inverse_of: :next, optional: true
|
13
|
+
has_one :next, class_name: 'Glueby::Contract::AR::Timestamp', foreign_key: 'prev_id'
|
14
|
+
|
15
|
+
validates :version, presence: true, inclusion: { in: ['1', '2'] }
|
16
|
+
|
17
|
+
def next_id
|
18
|
+
self.next&.id
|
19
|
+
end
|
13
20
|
|
14
21
|
validate :validate_prev
|
15
22
|
|
@@ -35,11 +42,14 @@ module Glueby
|
|
35
42
|
# - content
|
36
43
|
# - prefix(optional)
|
37
44
|
# - timestamp_type(optional)
|
38
|
-
# -
|
45
|
+
# - version [String] Version of the timestamp recording method.
|
46
|
+
# The format in which the timestamp is recorded differs depending on the version.
|
47
|
+
# Version "1" treats the specified content and prefix as a binary string.
|
48
|
+
# Version "2" treats the specified content and prefix as a hexadecimal string with the string set to prefix and content.
|
39
49
|
# @raise [Glueby::ArgumentError] If the timestamp_type is not in :simple or :trackable
|
40
50
|
def initialize(attributes = nil)
|
41
51
|
# Set content_hash from :content attribute
|
42
|
-
hex = attributes[:
|
52
|
+
hex = attributes[:version] == '1' ? false : true
|
43
53
|
content_hash = Timestamp.digest_content(attributes[:content], attributes[:digest] || :sha256, hex)
|
44
54
|
super(
|
45
55
|
wallet_id: attributes[:wallet_id],
|
@@ -48,7 +58,7 @@ module Glueby
|
|
48
58
|
status: :init,
|
49
59
|
timestamp_type: attributes[:timestamp_type] || :simple,
|
50
60
|
prev_id: attributes[:prev_id],
|
51
|
-
|
61
|
+
version: attributes[:version]
|
52
62
|
)
|
53
63
|
rescue ::ArgumentError => e
|
54
64
|
raise Glueby::ArgumentError, e.message
|
@@ -114,6 +124,7 @@ module Glueby
|
|
114
124
|
|
115
125
|
if update_trackable?
|
116
126
|
prev.latest = false
|
127
|
+
prev.next = self
|
117
128
|
prev.save!
|
118
129
|
end
|
119
130
|
end
|
@@ -129,6 +140,12 @@ module Glueby
|
|
129
140
|
raise Errors::FailedToBroadcast, "failed to broadcast (id=#{id}, reason=#{e.message})"
|
130
141
|
end
|
131
142
|
|
143
|
+
def hex?
|
144
|
+
version != '1'
|
145
|
+
end
|
146
|
+
|
147
|
+
alias_method :hex, :hex?
|
148
|
+
|
132
149
|
private
|
133
150
|
|
134
151
|
def wallet
|
@@ -139,11 +156,13 @@ module Glueby
|
|
139
156
|
builder = builder_class.new(wallet, fee_estimator)
|
140
157
|
|
141
158
|
if builder.instance_of?(Contract::Timestamp::TxBuilder::UpdatingTrackable)
|
159
|
+
prev_prefix = prev.hex ? prev.prefix&.htb : prev.prefix
|
160
|
+
prev_content_hash = prev.hex ? prev.content_hash&.htb : prev.content_hash
|
142
161
|
builder.set_prev_timestamp_info(
|
143
162
|
timestamp_utxo: prev.utxo,
|
144
163
|
payment_base: prev.payment_base,
|
145
|
-
prefix:
|
146
|
-
data:
|
164
|
+
prefix: prev_prefix,
|
165
|
+
data: prev_content_hash
|
147
166
|
)
|
148
167
|
end
|
149
168
|
|
@@ -15,6 +15,7 @@ module Glueby
|
|
15
15
|
class UnsupportedTokenType < ArgumentError; end
|
16
16
|
class UnknownScriptPubkey < ArgumentError; end
|
17
17
|
class UnsupportedDigestType < ArgumentError; end
|
18
|
+
class UnsupportedTimestampVersion < ArgumentError; end
|
18
19
|
class PrevTimestampNotFound < ArgumentError; end
|
19
20
|
class PrevTimestampIsNotTrackable < ArgumentError; end
|
20
21
|
class UnnecessaryPrevTimestamp < ArgumentError; end
|
@@ -7,6 +7,51 @@ module Glueby
|
|
7
7
|
# * 1 output to send the change TPC back to the wallet.
|
8
8
|
#
|
9
9
|
# Storing timestamp transaction to the blockchain enables everyone to verify that the data existed at that time and a user signed it.
|
10
|
+
#
|
11
|
+
# == Versioning Timestamp
|
12
|
+
#
|
13
|
+
# The timestamp has an attribute called "version".
|
14
|
+
# Version indicates how the timestamp is recorded in the blockchain. Currently, only versions 1 and 2 are supported, and each is recorded in the following manner
|
15
|
+
# * Version 1: The first version of the blockchain is used to record timestamps.
|
16
|
+
# treats the content and prefix received as parameters as a binary string
|
17
|
+
# * Version 2:.
|
18
|
+
# treats the specified content and prefix as a hexadecimal string with the string set to prefix and content.
|
19
|
+
#
|
20
|
+
# For example, when recording a simple type of timestamp, the difference between the content recorded by version 1 and version 2 is as follows
|
21
|
+
# Version 1:
|
22
|
+
# Save the timestamp as follows:
|
23
|
+
#
|
24
|
+
# Glueby::Contract::Timestamp.new(
|
25
|
+
# wallet: wallet,
|
26
|
+
# content: "1234",
|
27
|
+
# prefix: "071222",
|
28
|
+
# digest: :none,
|
29
|
+
# version: "1"
|
30
|
+
# )
|
31
|
+
#
|
32
|
+
# The output script of the recorded transaction will include OP_RETURN and will look like this:
|
33
|
+
#
|
34
|
+
# OP_RETURN 30373132323231323334
|
35
|
+
#
|
36
|
+
# Note that prefix: "071222" and content: "1234" are interpreted as ASCII strings and their hexadecimal representation "3037313232323132323334" is recorded in the actual blockchain, respectively.
|
37
|
+
#
|
38
|
+
# Version 2:
|
39
|
+
#
|
40
|
+
# To save the timestamp in version 2, simply change the version of the previous example to "2".
|
41
|
+
#
|
42
|
+
# Glueby::Contract::Timestamp.new(
|
43
|
+
# wallet: wallet,
|
44
|
+
# content: "1234",
|
45
|
+
# prefix: "071222",
|
46
|
+
# digest: :none,
|
47
|
+
# version: "2"
|
48
|
+
# )
|
49
|
+
#
|
50
|
+
# The output script will look like this:
|
51
|
+
#
|
52
|
+
# OP_RETURN 0712221234
|
53
|
+
#
|
54
|
+
# In this case, prefix: "071222" and content: "1234" are treated as a hexadecimal string and recorded directly in the blockchain.
|
10
55
|
class Timestamp
|
11
56
|
P2C_DEFAULT_VALUE = 1_000
|
12
57
|
|
@@ -29,7 +74,10 @@ module Glueby
|
|
29
74
|
# - :simple
|
30
75
|
# - :trackable
|
31
76
|
# @param [Integer] prev_timestamp_id The id column of glueby_timestamps that will be updated by the timestamp that will be created
|
32
|
-
# @param [
|
77
|
+
# @param [String] version Version of the timestamp recording method.
|
78
|
+
# The format in which the timestamp is recorded differs depending on the version.
|
79
|
+
# Version "1" treats the specified content and prefix as a binary string.
|
80
|
+
# Version "2" treats the specified content and prefix as a hexadecimal string with the string set to prefix and content.
|
33
81
|
# @raise [Glueby::Contract::Errors::UnsupportedDigestType] if digest is unsupported
|
34
82
|
# @raise [Glueby::Contract::Errors::InvalidTimestampType] if timestamp_type is unsupported
|
35
83
|
def initialize(
|
@@ -41,7 +89,7 @@ module Glueby
|
|
41
89
|
utxo_provider: nil,
|
42
90
|
timestamp_type: :simple,
|
43
91
|
prev_timestamp_id: nil,
|
44
|
-
|
92
|
+
version:
|
45
93
|
)
|
46
94
|
@wallet = wallet
|
47
95
|
@content = content
|
@@ -53,7 +101,8 @@ module Glueby
|
|
53
101
|
raise Glueby::Contract::Errors::InvalidTimestampType, "#{timestamp_type} is invalid type, supported types are :simple, and :trackable." unless [:simple, :trackable].include?(timestamp_type)
|
54
102
|
@timestamp_type = timestamp_type
|
55
103
|
@prev_timestamp_id = prev_timestamp_id
|
56
|
-
|
104
|
+
raise Glueby::Contract::Errors::UnsupportedTimestampVersion, "#{version} is unsupported, supported versions are '1' and '2'." unless ['1', '2'].include?(version)
|
105
|
+
@version = version
|
57
106
|
end
|
58
107
|
|
59
108
|
# broadcast to Tapyrus Core
|
@@ -70,7 +119,7 @@ module Glueby
|
|
70
119
|
timestamp_type: @timestamp_type,
|
71
120
|
digest: @digest,
|
72
121
|
prev_id: @prev_timestamp_id,
|
73
|
-
|
122
|
+
version: @version
|
74
123
|
)
|
75
124
|
@ar.save_with_broadcast!(fee_estimator: @fee_estimator, utxo_provider: @utxo_provider)
|
76
125
|
@ar.txid
|
@@ -86,27 +86,8 @@ module Glueby
|
|
86
86
|
Glueby::AR::SystemInformation.use_only_finalized_utxo?
|
87
87
|
end
|
88
88
|
|
89
|
-
# Sign to pay-to-contract output.
|
90
|
-
#
|
91
|
-
# @param issuer [Glueby::Walelt] Issuer of the token
|
92
|
-
# @param tx [Tapyrus::Tx] The transaction to be signed with metadata
|
93
|
-
# @param funding_tx [Tapyrus::Tx] The funding transaction that has pay-to-contract output in its first output
|
94
|
-
# @param payment_base [String] The public key used to generate pay to contract public key
|
95
|
-
# @param metadata [String] Data that represents token metadata
|
96
|
-
# @return [Tapyrus::Tx] signed tx
|
97
|
-
def sign_to_p2c_output(issuer, tx, funding_tx, payment_base, metadata)
|
98
|
-
utxo = { txid: funding_tx.txid, vout: 0, script_pubkey: funding_tx.outputs[0].script_pubkey.to_hex }
|
99
|
-
issuer.internal_wallet.sign_to_pay_to_contract_address(tx, utxo, payment_base, metadata)
|
100
|
-
end
|
101
|
-
|
102
89
|
private
|
103
90
|
|
104
|
-
def create_p2c_address(wallet, metadata)
|
105
|
-
p2c_address, payment_base = wallet.internal_wallet.create_pay_to_contract_address(metadata)
|
106
|
-
script = Tapyrus::Script.parse_from_addr(p2c_address)
|
107
|
-
[script, p2c_address, payment_base]
|
108
|
-
end
|
109
|
-
|
110
91
|
def issue_reissuable_token(issuer:, amount:, split: 1, fee_estimator:, metadata: nil)
|
111
92
|
txb = Internal::ContractBuilder.new(
|
112
93
|
sender_wallet: issuer.internal_wallet,
|
@@ -244,14 +225,6 @@ module Glueby
|
|
244
225
|
end
|
245
226
|
end
|
246
227
|
end
|
247
|
-
|
248
|
-
# Add dummy inputs and outputs to tx for issue non-reissuable transaction and nft transaction
|
249
|
-
def dummy_issue_tx_from_out_point
|
250
|
-
tx = Tapyrus::Tx.new
|
251
|
-
receiver_colored_script = Tapyrus::Script.parse_from_payload('21c20000000000000000000000000000000000000000000000000000000000000000bc76a914000000000000000000000000000000000000000088ac'.htb)
|
252
|
-
tx.outputs << Tapyrus::TxOut.new(value: 0, script_pubkey: receiver_colored_script)
|
253
|
-
FeeEstimator.dummy_tx(tx)
|
254
|
-
end
|
255
228
|
end
|
256
229
|
|
257
230
|
attr_reader :color_id
|
@@ -206,8 +206,8 @@ module Glueby
|
|
206
206
|
tx = Tapyrus::Tx.new
|
207
207
|
|
208
208
|
amount = receivers.reduce(0) { |sum, r| sum + r[:amount].to_i }
|
209
|
-
utxos = sender.internal_wallet.list_unspent(only_finalized)
|
210
|
-
sum_token, outputs = collect_colored_outputs(utxos,
|
209
|
+
utxos = sender.internal_wallet.list_unspent(only_finalized, color_id: color_id)
|
210
|
+
sum_token, outputs = collect_colored_outputs(utxos, amount)
|
211
211
|
fill_input(tx, outputs)
|
212
212
|
|
213
213
|
receivers.each do |r|
|
@@ -247,8 +247,8 @@ module Glueby
|
|
247
247
|
def create_burn_tx(color_id:, sender:, amount: 0, fee_estimator: FeeEstimator::Fixed.new, only_finalized: true)
|
248
248
|
tx = Tapyrus::Tx.new
|
249
249
|
|
250
|
-
utxos = sender.internal_wallet.list_unspent(only_finalized)
|
251
|
-
sum_token, outputs = collect_colored_outputs(utxos,
|
250
|
+
utxos = sender.internal_wallet.list_unspent(only_finalized, color_id: color_id)
|
251
|
+
sum_token, outputs = collect_colored_outputs(utxos, amount)
|
252
252
|
fill_input(tx, outputs)
|
253
253
|
|
254
254
|
fill_change_token(tx, sender, sum_token - amount, color_id) if amount.positive?
|
@@ -319,12 +319,9 @@ module Glueby
|
|
319
319
|
# Returns the set of utxos that satisfies the specified amount and has the specified color_id.
|
320
320
|
# if amount is not specified or 0, return all utxos with color_id
|
321
321
|
# @param results [Array] response of Glueby::Internal::Wallet#list_unspent
|
322
|
-
# @param color_id [Tapyrus::Color::ColorIdentifier] color identifier
|
323
322
|
# @param amount [Integer]
|
324
|
-
def collect_colored_outputs(results,
|
323
|
+
def collect_colored_outputs(results, amount = 0)
|
325
324
|
results = results.inject([0, []]) do |sum, output|
|
326
|
-
next sum unless output[:color_id] == color_id.to_hex
|
327
|
-
|
328
325
|
new_sum = sum[0] + output[:amount]
|
329
326
|
new_outputs = sum[1] << output
|
330
327
|
return [new_sum, new_outputs] if new_sum >= amount && amount.positive?
|
@@ -90,16 +90,6 @@ module Glueby
|
|
90
90
|
|
91
91
|
private
|
92
92
|
|
93
|
-
def check_wallet_amount!
|
94
|
-
if tpc_amount < fee_provider.fixed_fee
|
95
|
-
raise InsufficientTPC, <<~MESSAGE
|
96
|
-
FeeProvider has insufficient TPC to create fee outputs to fill the UTXO pool.
|
97
|
-
1. Please replenishment TPC which is for paying fee to FeeProvider. FeeProvider needs #{fee_provider.utxo_pool_size * fee_provider.fixed_fee} tapyrus at least. FeeProvider wallet's address is '#{wallet.receive_address}'
|
98
|
-
2. Then create UTXOs for paying in UTXO pool with 'rake glueby:fee_provider:manage_utxo_pool'
|
99
|
-
MESSAGE
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
93
|
def tpc_amount
|
104
94
|
wallet.balance(false)
|
105
95
|
end
|
@@ -357,7 +357,7 @@ module Glueby
|
|
357
357
|
end
|
358
358
|
|
359
359
|
def get_fee_estimator(fee_estimator_name)
|
360
|
-
Glueby::Contract::FeeEstimator.
|
360
|
+
Glueby::Contract::FeeEstimator.const_get(fee_estimator_name.capitalize, false).new
|
361
361
|
end
|
362
362
|
|
363
363
|
def valid_fee_estimator?(fee_estimator)
|
@@ -65,6 +65,21 @@ module Glueby
|
|
65
65
|
raise NotImplementedError, "You must implement #{self.class}##{__method__}"
|
66
66
|
end
|
67
67
|
|
68
|
+
# Returns all tokens with specified color_id
|
69
|
+
#
|
70
|
+
# @param [String] wallet_id - The wallet id that is offered by `create_wallet()` method.
|
71
|
+
# @param [Boolean] only_finalized - includes only finalized UTXO value if it
|
72
|
+
# is true. Default is true.
|
73
|
+
# @param [Tapyrus::Color::ColorIdentifier] color_id The color identifier associated with UTXO.
|
74
|
+
# It will return only UTXOs with specified color_id. If color_id is nil, it will return all UTXOs.
|
75
|
+
# If Tapyrus::Color::ColorIdentifier.default is specified, it will return uncolored UTXOs(i.e. TPC)
|
76
|
+
# @param [Integer] page - The page parameter is responsible for specifying the current page being viewed within the paginated results. default is 1.
|
77
|
+
# @param [Integer] per - The per parameter is used to determine the number of items to display per page. default is 25.
|
78
|
+
# @return [Array<Utxo>] The array of the utxos with specified color_id
|
79
|
+
def list_unspent_with_count(wallet_id, only_finalized = true, label = nil, color_id: nil, page: 1, per: 25)
|
80
|
+
raise NotImplementedError, "You must implement #{self.class}##{__method__}"
|
81
|
+
end
|
82
|
+
|
68
83
|
# Returns the UTXOs that the wallet has.
|
69
84
|
# If label is specified, return UTXOs filtered with label
|
70
85
|
#
|
@@ -74,6 +89,9 @@ module Glueby
|
|
74
89
|
# @param [String] label - Label for filtering UTXOs
|
75
90
|
# - If label is nil or :unlabeled, only unlabeled UTXOs will be returned.
|
76
91
|
# - If label=:all, it will return all utxos
|
92
|
+
# @param [Tapyrus::Color::ColorIdentifier] color_id - The color identifier.
|
93
|
+
# It will return only UTXOs with specified color_id. If color_id is nil, it will return all UTXOs.
|
94
|
+
# If Tapyrus::Color::ColorIdentifier.default is specified, it will return uncolored UTXOs(i.e. TPC)
|
77
95
|
# @return [Array of UTXO]
|
78
96
|
#
|
79
97
|
# ## The UTXO structure
|
@@ -84,7 +102,7 @@ module Glueby
|
|
84
102
|
# - finalized: [Boolean] Whether the UTXO is finalized
|
85
103
|
# - color_id: [String] Color id of the UTXO. If it is TPC UTXO, color_id is nil.
|
86
104
|
# - script_pubkey: [String] Script pubkey of the UTXO
|
87
|
-
def list_unspent(wallet_id, only_finalized = true, label = nil)
|
105
|
+
def list_unspent(wallet_id, only_finalized = true, label = nil, color_id: nil)
|
88
106
|
raise NotImplementedError, "You must implement #{self.class}##{__method__}"
|
89
107
|
end
|
90
108
|
|
@@ -139,7 +157,7 @@ module Glueby
|
|
139
157
|
|
140
158
|
# Returns information for the addresses
|
141
159
|
#
|
142
|
-
# @param [String]
|
160
|
+
# @param [String, Array<String>] addresses - The p2pkh address to get information about
|
143
161
|
# @return [Array<Hash>] The array of hash instance which has keys wallet_id, label and purpose.
|
144
162
|
# Returns blank array if the key correspond with the address is not exist.
|
145
163
|
def get_addresses_info(addresses)
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'securerandom'
|
4
|
+
require 'kaminari'
|
4
5
|
|
5
6
|
module Glueby
|
6
7
|
module Internal
|
@@ -89,29 +90,18 @@ module Glueby
|
|
89
90
|
utxos.sum(&:value)
|
90
91
|
end
|
91
92
|
|
92
|
-
def
|
93
|
-
|
94
|
-
utxos =
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
else
|
101
|
-
utxos
|
102
|
-
end
|
93
|
+
def list_unspent_with_count(wallet_id, only_finalized = true, label = nil, color_id: nil, page: 1, per: 25)
|
94
|
+
utxos = list_unspent_internal(wallet_id, color_id, only_finalized, label)
|
95
|
+
utxos = utxos.page(page).per(per) if per > 0
|
96
|
+
{
|
97
|
+
count: utxos.total_count,
|
98
|
+
outputs: utxos_to_h(utxos)
|
99
|
+
}
|
100
|
+
end
|
103
101
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
vout: utxo.index,
|
108
|
-
script_pubkey: utxo.script_pubkey,
|
109
|
-
color_id: utxo.color_id,
|
110
|
-
amount: utxo.value,
|
111
|
-
finalized: utxo.status == 'finalized',
|
112
|
-
label: utxo.label
|
113
|
-
}
|
114
|
-
end
|
102
|
+
def list_unspent(wallet_id, only_finalized = true, label = nil, color_id: nil)
|
103
|
+
utxos = list_unspent_internal(wallet_id, color_id, only_finalized, label)
|
104
|
+
utxos_to_h(utxos)
|
115
105
|
end
|
116
106
|
|
117
107
|
def sign_tx(wallet_id, tx, prevtxs = [], sighashtype: Tapyrus::SIGHASH_TYPE[:all])
|
@@ -245,6 +235,37 @@ module Glueby
|
|
245
235
|
key_type: Tapyrus::Key::TYPES[:compressed]
|
246
236
|
)
|
247
237
|
end
|
238
|
+
|
239
|
+
def list_unspent_internal(wallet_id, color_id = nil, only_finalized = true, label = nil)
|
240
|
+
wallet = AR::Wallet.find_by(wallet_id: wallet_id)
|
241
|
+
utxos = wallet.utxos.where(locked_at: nil)
|
242
|
+
utxos = utxos.where(color_id: color_id.to_hex) if color_id && !color_id.default?
|
243
|
+
utxos = utxos.where(color_id: nil) if color_id && color_id.default?
|
244
|
+
utxos = utxos.where(status: :finalized) if only_finalized
|
245
|
+
utxos = utxos.order(:id)
|
246
|
+
utxos = if [:unlabeled, nil].include?(label)
|
247
|
+
utxos = utxos.where(label: nil)
|
248
|
+
elsif label && (label != :all)
|
249
|
+
utxos = utxos.where(label: label)
|
250
|
+
else
|
251
|
+
utxos
|
252
|
+
end
|
253
|
+
utxos
|
254
|
+
end
|
255
|
+
|
256
|
+
def utxos_to_h(utxos)
|
257
|
+
utxos.map do |utxo|
|
258
|
+
{
|
259
|
+
txid: utxo.txid,
|
260
|
+
vout: utxo.index,
|
261
|
+
script_pubkey: utxo.script_pubkey,
|
262
|
+
color_id: utxo.color_id,
|
263
|
+
amount: utxo.value,
|
264
|
+
finalized: utxo.status == 'finalized',
|
265
|
+
label: utxo.label
|
266
|
+
}
|
267
|
+
end
|
268
|
+
end
|
248
269
|
end
|
249
270
|
end
|
250
271
|
end
|
@@ -84,7 +84,7 @@ module Glueby
|
|
84
84
|
|
85
85
|
# If label=nil, it will return unlabeled utxos to protect labeled utxos for specific purpose
|
86
86
|
# If label=:all, it will return all utxos
|
87
|
-
def list_unspent(wallet_id, only_finalized = true, label = nil)
|
87
|
+
def list_unspent(wallet_id, only_finalized = true, label = nil, color_id: nil)
|
88
88
|
perform_as(wallet_id) do |client|
|
89
89
|
min_conf = only_finalized ? 1 : 0
|
90
90
|
res = client.listunspent(min_conf)
|
@@ -97,6 +97,13 @@ module Glueby
|
|
97
97
|
res
|
98
98
|
end
|
99
99
|
|
100
|
+
if color_id
|
101
|
+
res = res.filter do |i|
|
102
|
+
script = Tapyrus::Script.parse_from_payload(i['scriptPubKey'].htb)
|
103
|
+
script.cp2pkh? || script.cp2sh? && color_id == Tapyrus::Color::ColorIdentifier.parse_from_payload(script.chunks[0].pushed_data)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
100
107
|
res.map do |i|
|
101
108
|
script = Tapyrus::Script.parse_from_payload(i['scriptPubKey'].htb)
|
102
109
|
color_id = if script.cp2pkh? || script.cp2sh?
|
@@ -177,7 +184,7 @@ module Glueby
|
|
177
184
|
type = case sighashtype & (~(Tapyrus::SIGHASH_TYPE[:anyonecanpay]))
|
178
185
|
when Tapyrus::SIGHASH_TYPE[:all] then 'ALL'
|
179
186
|
when Tapyrus::SIGHASH_TYPE[:none] then 'NONE'
|
180
|
-
when Tapyrus::SIGHASH_TYPE[:single] then '
|
187
|
+
when Tapyrus::SIGHASH_TYPE[:single] then 'SINGLE'
|
181
188
|
else
|
182
189
|
raise Errors::InvalidSighashType, "Invalid sighash type '#{sighashtype}'"
|
183
190
|
end
|
@@ -93,9 +93,25 @@ module Glueby
|
|
93
93
|
# @param label [String] This label is used to filtered the UTXOs with labeled if a key or Utxo is labeled.
|
94
94
|
# - If label is nil or :unlabeled, only unlabeled UTXOs will be returned.
|
95
95
|
# - If label=:all, all UTXOs will be returned.
|
96
|
-
|
96
|
+
# @param color_id [Tapyrus::Color::ColorIdentifier] The color identifier associated with UTXO.
|
97
|
+
# It will return only UTXOs with specified color_id. If color_id is nil, it will return all UTXOs.
|
98
|
+
# If Tapyrus::Color::ColorIdentifier.default is specified, it will return uncolored UTXOs(i.e. TPC)
|
99
|
+
# @param page [Integer] The page parameter is responsible for specifying the current page being viewed within the paginated results. default is 1.
|
100
|
+
# @param per [Integer] The per parameter is used to determine the number of items to display per page. default is 25.
|
101
|
+
def list_unspent_with_count(only_finalized = true, label = nil, color_id: nil, page: 1, per: 25)
|
102
|
+
wallet_adapter.list_unspent_with_count(id, only_finalized, label, color_id: color_id, page: page, per: per)
|
103
|
+
end
|
104
|
+
|
105
|
+
# @param only_finalized [Boolean] The flag to get a UTXO with status only finalized
|
106
|
+
# @param label [String] This label is used to filtered the UTXOs with labeled if a key or Utxo is labeled.
|
107
|
+
# - If label is nil or :unlabeled, only unlabeled UTXOs will be returned.
|
108
|
+
# - If label=:all, all UTXOs will be returned.
|
109
|
+
# @param color_id [Tapyrus::Color::ColorIdentifier] The color identifier associated with UTXO.
|
110
|
+
# It will return only UTXOs with specified color_id. If color_id is nil, it will return all UTXOs.
|
111
|
+
# If Tapyrus::Color::ColorIdentifier.default is specified, it will return uncolored UTXOs(i.e. TPC)
|
112
|
+
def list_unspent(only_finalized = true, label = :unlabeled, color_id: nil )
|
97
113
|
label = :unlabeled unless label
|
98
|
-
wallet_adapter.list_unspent(id, only_finalized, label)
|
114
|
+
wallet_adapter.list_unspent(id, only_finalized, label, color_id: color_id)
|
99
115
|
end
|
100
116
|
|
101
117
|
def lock_unspent(utxo)
|
@@ -171,8 +187,7 @@ module Glueby
|
|
171
187
|
lock_utxos = false,
|
172
188
|
excludes = []
|
173
189
|
)
|
174
|
-
collect_utxos(amount, label, only_finalized, shuffle, lock_utxos, excludes) do |output|
|
175
|
-
next false unless output[:color_id].nil?
|
190
|
+
collect_utxos(amount, label, Tapyrus::Color::ColorIdentifier.default, only_finalized, shuffle, lock_utxos, excludes) do |output|
|
176
191
|
next yield(output) if block_given?
|
177
192
|
|
178
193
|
true
|
@@ -206,8 +221,7 @@ module Glueby
|
|
206
221
|
lock_utxos = false,
|
207
222
|
excludes = []
|
208
223
|
)
|
209
|
-
collect_utxos(amount, label, only_finalized, shuffle, lock_utxos, excludes) do |output|
|
210
|
-
next false unless output[:color_id] == color_id.to_hex
|
224
|
+
collect_utxos(amount, label, color_id, only_finalized, shuffle, lock_utxos, excludes) do |output|
|
211
225
|
next yield(output) if block_given?
|
212
226
|
|
213
227
|
true
|
@@ -261,7 +275,7 @@ module Glueby
|
|
261
275
|
while current_amount - fee < target_amount
|
262
276
|
sum, utxos = collect_uncolored_outputs(
|
263
277
|
fee + target_amount - current_amount,
|
264
|
-
nil,
|
278
|
+
nil, false, true, true,
|
265
279
|
provided_utxos,
|
266
280
|
&block
|
267
281
|
)
|
@@ -288,7 +302,8 @@ module Glueby
|
|
288
302
|
def collect_utxos(
|
289
303
|
amount,
|
290
304
|
label,
|
291
|
-
|
305
|
+
color_id,
|
306
|
+
only_finalized = true,
|
292
307
|
shuffle = true,
|
293
308
|
lock_utxos = false,
|
294
309
|
excludes = []
|
@@ -296,7 +311,7 @@ module Glueby
|
|
296
311
|
collect_all = amount.nil?
|
297
312
|
|
298
313
|
raise Glueby::ArgumentError, 'amount must be positive' unless collect_all || amount.positive?
|
299
|
-
utxos = list_unspent(only_finalized, label)
|
314
|
+
utxos = list_unspent(only_finalized, label, color_id: color_id)
|
300
315
|
utxos = utxos.shuffle if shuffle
|
301
316
|
|
302
317
|
r = utxos.inject([0, []]) do |(sum, outputs), output|
|
data/lib/glueby/version.rb
CHANGED
data/lib/glueby/wallet.rb
CHANGED
@@ -46,6 +46,10 @@ module Glueby
|
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
|
+
def token_utxos(color_id = nil, only_finalized = true, page = 1, per = 25)
|
50
|
+
@internal_wallet.list_unspent_with_count(only_finalized, nil, color_id: color_id, page: page, per: per)
|
51
|
+
end
|
52
|
+
|
49
53
|
private
|
50
54
|
|
51
55
|
def initialize(internal_wallet)
|
data/lib/glueby.rb
CHANGED
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: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- azuchi
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-01-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: tapyrus
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 7.0.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: kaminari
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: sqlite3
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -173,7 +187,7 @@ metadata:
|
|
173
187
|
homepage_uri: https://github.com/chaintope/glueby
|
174
188
|
source_code_uri: https://github.com/chaintope/glueby
|
175
189
|
changelog_uri: https://github.com/chaintope/glueby
|
176
|
-
post_install_message:
|
190
|
+
post_install_message:
|
177
191
|
rdoc_options: []
|
178
192
|
require_paths:
|
179
193
|
- lib
|
@@ -181,15 +195,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
181
195
|
requirements:
|
182
196
|
- - ">="
|
183
197
|
- !ruby/object:Gem::Version
|
184
|
-
version:
|
198
|
+
version: 3.0.0
|
185
199
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
186
200
|
requirements:
|
187
201
|
- - ">="
|
188
202
|
- !ruby/object:Gem::Version
|
189
203
|
version: '0'
|
190
204
|
requirements: []
|
191
|
-
rubygems_version: 3.
|
192
|
-
signing_key:
|
205
|
+
rubygems_version: 3.5.3
|
206
|
+
signing_key:
|
193
207
|
specification_version: 4
|
194
208
|
summary: A Ruby library of smart contracts that can be used on Tapyrus.
|
195
209
|
test_files: []
|