artq 0.2.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Manifest.txt +2 -0
- data/README.md +37 -2
- data/lib/artq/contract.rb +6 -6
- data/lib/artq/layers.rb +100 -0
- data/lib/artq/tokens.rb +107 -0
- data/lib/artq/version.rb +1 -1
- data/lib/artq.rb +53 -108
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 173bf8cbe3bc0e9db811e19b585bd04bc23956b28b1b4cb055c1697288472d7e
|
4
|
+
data.tar.gz: 90c2751c1028ca2986e12825f83d8afbb9055ce864228f5a611a9110481f1439
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 339f0a49d30a544ce53892ec7f3c1a04a3ddb47d279ddc938d995ae8efc7c25356db9920a44f06d61a5d3482efe9975a965ba791ca6c6603cc427a6353914ab1
|
7
|
+
data.tar.gz: db571cdfcd4e29e3486199ac775a5494e1f4a42256d7d7449c8adbc3fdf7d4259356863dd3f440b60b94bcc30cf104c365c727965226eefe6a9e1ee849aa23da
|
data/Manifest.txt
CHANGED
data/README.md
CHANGED
@@ -184,7 +184,7 @@ and inline svg images in the base64 format get "cut" from the metadata and "past
|
|
184
184
|
```
|
185
185
|
|
186
186
|
|
187
|
-
####
|
187
|
+
#### Case No. 3 - "On-Blockchain" Layers (Incl. Metadata & Images)
|
188
188
|
|
189
189
|
|
190
190
|
Note: Some "on-blockchain" pixel art collections
|
@@ -339,7 +339,42 @@ such as
|
|
339
339
|
and many more.
|
340
340
|
|
341
341
|
|
342
|
-
Tip:
|
342
|
+
Tip: For more art collections with "on-blockchain" layers see the [**Art Factory Sandbox »**](https://github.com/pixelartexchange/artfactory.sandbox)
|
343
|
+
|
344
|
+
|
345
|
+
|
346
|
+
|
347
|
+
|
348
|
+
### Using the ArtQ Machinery in Your Own Scripts
|
349
|
+
|
350
|
+
|
351
|
+
Yes, you can. Let's try the (crypto) marcs:
|
352
|
+
|
353
|
+
|
354
|
+
``` ruby
|
355
|
+
require 'artq'
|
356
|
+
|
357
|
+
marcs_eth = "0xe9b91d537c3aa5a3fa87275fbd2e4feaaed69bd0"
|
358
|
+
|
359
|
+
marcs = ArtQ::Contract.new( marcs_eth )
|
360
|
+
|
361
|
+
n = 0
|
362
|
+
m = 0
|
363
|
+
res = marcs.traitData( n, m ) ## note: return binary blob (for n,m-index)
|
364
|
+
pp res
|
365
|
+
#=> ["\x89PNG..."]
|
366
|
+
|
367
|
+
res = marcs.traitDetails( n, m ) ## note: returns tuple (name, mimetype, hide?)
|
368
|
+
pp res
|
369
|
+
#=> ["Zombie", "image/png", false]
|
370
|
+
|
371
|
+
|
372
|
+
|
373
|
+
## or with convenience download_layers helper
|
374
|
+
ArtQ.download_layers( marcs_eth, outdir: './marcs' )
|
375
|
+
```
|
376
|
+
|
377
|
+
|
343
378
|
|
344
379
|
|
345
380
|
|
data/lib/artq/contract.rb
CHANGED
@@ -50,13 +50,12 @@ class Contract
|
|
50
50
|
|
51
51
|
|
52
52
|
|
53
|
-
|
54
|
-
|
55
|
-
|
53
|
+
## note: forward to Ethlite.config.rpc
|
54
|
+
## keep config here as a convenience shortcut - why? why not?
|
55
|
+
def self.rpc() Ethlite.config.rpc; end
|
56
|
+
def self.rpc=(value) Ethlite.config.rpc = value; end
|
57
|
+
|
56
58
|
|
57
|
-
def self.rpc=(value)
|
58
|
-
@rpc = value.is_a?( String ) ? JsonRpc.new( value ) : value
|
59
|
-
end
|
60
59
|
|
61
60
|
|
62
61
|
def initialize( contract_address )
|
@@ -66,6 +65,7 @@ class Contract
|
|
66
65
|
######
|
67
66
|
# private helper to call method
|
68
67
|
def _do_call( eth, args )
|
68
|
+
puts " calling method >#{eth.name}< with args >#{args}<... "
|
69
69
|
eth.do_call( self.class.rpc, @contract_address, args )
|
70
70
|
end
|
71
71
|
|
data/lib/artq/layers.rb
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
|
2
|
+
module ArtQ
|
3
|
+
|
4
|
+
|
5
|
+
## use alternate Encoding::BINARY - why? why not?
|
6
|
+
## or just use .b e.g. "GIF87".b or such !!!
|
7
|
+
JPGSIG = "\xFF\xD8\xFF".force_encoding( Encoding::ASCII_8BIT )
|
8
|
+
PNGSIG = "\x89PNG".force_encoding( Encoding::ASCII_8BIT )
|
9
|
+
GIF87SIG = "GIF87".force_encoding( Encoding::ASCII_8BIT )
|
10
|
+
GIF89SIG = "GIF89".force_encoding( Encoding::ASCII_8BIT )
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
def self.download_layers( contract_address,
|
15
|
+
outdir: "./#{contract_address}" )
|
16
|
+
|
17
|
+
puts "==> download layers for art collection contract @ >#{contract_address}<:"
|
18
|
+
|
19
|
+
c = Contract.new( contract_address )
|
20
|
+
|
21
|
+
## get some metadata - why? why not?
|
22
|
+
name = c.name
|
23
|
+
symbol = c.symbol
|
24
|
+
totalSupply = c.totalSupply
|
25
|
+
|
26
|
+
traitDetails = []
|
27
|
+
n=0
|
28
|
+
loop do
|
29
|
+
m=0
|
30
|
+
loop do
|
31
|
+
rec = c.traitDetails( n, m )
|
32
|
+
break if rec == ['','',false] ## note: assume end-of-list if all values are zeros / defaults.
|
33
|
+
|
34
|
+
traitDetails << [[n,m], rec ]
|
35
|
+
m += 1
|
36
|
+
sleep( 0.5 )
|
37
|
+
end
|
38
|
+
break if m==0
|
39
|
+
n += 1
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
## todo/check: include or drop hide (of any use?) - why? why not?
|
44
|
+
headers = ['index', 'name', 'type', 'hide']
|
45
|
+
recs = []
|
46
|
+
traitDetails.each do |t|
|
47
|
+
recs << [ t[0].join('/'),
|
48
|
+
t[1][0],
|
49
|
+
t[1][1],
|
50
|
+
t[1][2].to_s]
|
51
|
+
end
|
52
|
+
|
53
|
+
buf = String.new('')
|
54
|
+
buf << headers.join( ', ' )
|
55
|
+
buf << "\n"
|
56
|
+
recs.each do |rec|
|
57
|
+
buf << rec.join( ', ' )
|
58
|
+
buf << "\n"
|
59
|
+
end
|
60
|
+
|
61
|
+
write_text( "#{outdir}/cache/layers.csv", buf )
|
62
|
+
|
63
|
+
#####
|
64
|
+
# try to download all images
|
65
|
+
traitDetails.each_with_index do |t,i|
|
66
|
+
puts " [#{i+1}/#{traitDetails.size}] downloading #{t[1][1]} >#{t[1][0]}<..."
|
67
|
+
|
68
|
+
n,m = t[0]
|
69
|
+
data = c.traitData( n, m )
|
70
|
+
|
71
|
+
basename = "#{n}_#{m}"
|
72
|
+
if data.start_with?( PNGSIG )
|
73
|
+
puts "BINGO!! it's a png blob - #{data.size} byte(s)"
|
74
|
+
write_blob( "#{outdir}/cache/#{basename}.png", data )
|
75
|
+
elsif data.start_with?( GIF87SIG ) || data.start_with?( GIF89SIG )
|
76
|
+
puts "BINGO!! it's a gif blob - #{data.size} byte(s)"
|
77
|
+
write_blob( "#{outdir}/cache/#{basename}.gif", data )
|
78
|
+
elsif data.start_with?( JPGSIG )
|
79
|
+
puts "BINGO!! it's a jpg blob - #{data.size} byte(s)"
|
80
|
+
write_blob( "#{outdir}/cache/#{basename}.jpg", data )
|
81
|
+
elsif data.index( /<svg[^>]*?>/i ) ## add more markers to find - why? why not?
|
82
|
+
puts "BINGO!! it's a svg (text) blob - #{data.size} byte(s)"
|
83
|
+
## todo/check - save text as binary blob 1:1 - why? why not?
|
84
|
+
write_blob( "#{outdir}/cache/#{basename}.svg", data )
|
85
|
+
else
|
86
|
+
puts "!! ERROR - unknown image format; sorry"
|
87
|
+
exit 1
|
88
|
+
end
|
89
|
+
sleep( 0.5 )
|
90
|
+
end
|
91
|
+
|
92
|
+
|
93
|
+
puts " name: >#{name}<"
|
94
|
+
puts " symbol: >#{symbol}<"
|
95
|
+
puts " totalSupply: >#{totalSupply}<"
|
96
|
+
puts
|
97
|
+
puts " traitDetails:"
|
98
|
+
pp traitDetails
|
99
|
+
end
|
100
|
+
end # module ArtQ
|
data/lib/artq/tokens.rb
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
|
2
|
+
module ArtQ
|
3
|
+
|
4
|
+
|
5
|
+
|
6
|
+
class Meta ## check: change/rename to MetaToken or such - why? why not?
|
7
|
+
def self.parse( tokenURI )
|
8
|
+
if tokenURI.start_with?( 'data:application/json;base64' )
|
9
|
+
|
10
|
+
str = tokenURI.sub( 'data:application/json;base64', '' )
|
11
|
+
str = Base64.decode64( str )
|
12
|
+
data = JSON.parse( str )
|
13
|
+
|
14
|
+
## check for image_data - and replace if base64 encoded
|
15
|
+
image_data = data['image_data']
|
16
|
+
svg_image_data = data['svg_image_data']
|
17
|
+
|
18
|
+
if svg_image_data && svg_image_data.start_with?( 'data:image/svg+xml;base64' )
|
19
|
+
data['svg_image_data'] = '...'
|
20
|
+
data['image_data'] = '...' if image_data
|
21
|
+
## note: prefer svg_image_data if present over image_data - why? why not?
|
22
|
+
str = svg_image_data.sub( 'data:image/svg+xml;base64', '' )
|
23
|
+
image_data = Base64.decode64( str )
|
24
|
+
elsif image_data && image_data.start_with?( 'data:image/svg+xml;base64' )
|
25
|
+
data['image_data'] = '...'
|
26
|
+
str = image_data.sub( 'data:image/svg+xml;base64', '' )
|
27
|
+
image_data = Base64.decode64( str )
|
28
|
+
else
|
29
|
+
## assume no inline image_data ??
|
30
|
+
end
|
31
|
+
|
32
|
+
new( data, image_data )
|
33
|
+
else
|
34
|
+
new ## use new({},nil) - why? why not?
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def initialize( data={},
|
39
|
+
image_data=nil )
|
40
|
+
@data = data
|
41
|
+
@image_data = image_data
|
42
|
+
end
|
43
|
+
|
44
|
+
def data() @data; end
|
45
|
+
def image_data() @image_data; end
|
46
|
+
end # class Meta
|
47
|
+
|
48
|
+
|
49
|
+
|
50
|
+
## download on-blockchain token metadata and (inline) images
|
51
|
+
def self.download_tokens( contract_address,
|
52
|
+
outdir: "./#{contract_address}",
|
53
|
+
ids: (0..99) )
|
54
|
+
|
55
|
+
puts "==> download token (on-blockchain) metadata and (inline) images for art collection contract @ >#{contract_address}<:"
|
56
|
+
|
57
|
+
c = Contract.new( contract_address )
|
58
|
+
|
59
|
+
## get some metadata - why? why not?
|
60
|
+
name = c.name
|
61
|
+
symbol = c.symbol
|
62
|
+
totalSupply = c.totalSupply
|
63
|
+
|
64
|
+
|
65
|
+
warns = [] ## collect all warnings
|
66
|
+
|
67
|
+
tokenIds = ids
|
68
|
+
tokenIds.each do |tokenId|
|
69
|
+
tokenURI = c.tokenURI( tokenId )
|
70
|
+
sleep( 0.5 )
|
71
|
+
|
72
|
+
|
73
|
+
puts " tokenId #{tokenId}:"
|
74
|
+
meta = Meta.parse( tokenURI )
|
75
|
+
if meta.data.empty?
|
76
|
+
## todo/check: raise TypeError or such or return nil - why? why not?
|
77
|
+
warns << "token no. #{tokenId} metadata not 'on-blockchain'? expected json base64-encoded; got:"
|
78
|
+
puts "!! WARN - " + warns[-1]
|
79
|
+
pp tokenURI
|
80
|
+
else
|
81
|
+
path = "#{outdir}/token/#{tokenId}.json"
|
82
|
+
write_json( path, meta.data )
|
83
|
+
|
84
|
+
if meta.image_data
|
85
|
+
## assume svg for now - always - why? why not?
|
86
|
+
path = "#{outdir}/token-i/#{tokenId}.svg"
|
87
|
+
write_text( path, meta.image_data )
|
88
|
+
else
|
89
|
+
warns << "token no. #{tokenId} (inline) image data not found in 'on-blockchain' metadata; got:"
|
90
|
+
puts "!! WARN - " + warns[-1]
|
91
|
+
pp meta.data
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
if warns.size > 0
|
97
|
+
puts "!!! #{warns.size} WARNING(S):"
|
98
|
+
pp warns
|
99
|
+
end
|
100
|
+
|
101
|
+
puts
|
102
|
+
puts " name: >#{name}<"
|
103
|
+
puts " symbol: >#{symbol}<"
|
104
|
+
puts " totalSupply: >#{totalSupply}<"
|
105
|
+
end
|
106
|
+
|
107
|
+
end # module ArtQ
|
data/lib/artq/version.rb
CHANGED
data/lib/artq.rb
CHANGED
@@ -5,16 +5,25 @@ require 'optparse'
|
|
5
5
|
## our own code
|
6
6
|
require_relative 'artq/version' # let version go first
|
7
7
|
require_relative 'artq/contract'
|
8
|
+
require_relative 'artq/layers'
|
9
|
+
require_relative 'artq/tokens'
|
8
10
|
|
9
11
|
|
10
12
|
|
11
13
|
module ArtQ
|
12
14
|
|
15
|
+
class Tool
|
13
16
|
|
14
17
|
|
18
|
+
def self.is_addr?( str )
|
19
|
+
## e.g.
|
20
|
+
## must for now start with 0x (or 0X)
|
21
|
+
## and than 40 hexdigits (20 bytes)
|
22
|
+
## e.g. 0xe21ebcd28d37a67757b9bc7b290f4c4928a430b1
|
23
|
+
str.match( /\A0x[0-9a-f]{40}\z/i )
|
24
|
+
end
|
15
25
|
|
16
26
|
|
17
|
-
class Tool
|
18
27
|
|
19
28
|
def self.main( args=ARGV )
|
20
29
|
puts "==> welcome to artq tool with args:"
|
@@ -49,14 +58,38 @@ class Tool
|
|
49
58
|
exit
|
50
59
|
end
|
51
60
|
|
52
|
-
|
61
|
+
|
62
|
+
## todo/check - use collection_name/slug or such?
|
63
|
+
contract_address = nil
|
64
|
+
outdir = nil
|
65
|
+
|
66
|
+
if is_addr?( args[0] ) ## do nothing; it's an address
|
67
|
+
contract_address = args[0]
|
68
|
+
outdir = "./tmp/#{contract_address}"
|
69
|
+
else ## try reading collection.yml config
|
70
|
+
config_path = "./#{args[0]}/collection.yml"
|
71
|
+
if File.exist?( config_path )
|
72
|
+
config = read_yaml( config_path )
|
73
|
+
contract_address = config['token']['contract']
|
74
|
+
outdir = "./#{args[0]}"
|
75
|
+
else
|
76
|
+
puts "!! ERROR - no config found for collection >#{contract_address}<; sorry"
|
77
|
+
exit 1
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
|
53
82
|
command = args[1] || 'info'
|
54
83
|
|
55
84
|
|
56
85
|
if ['i','inf','info'].include?( command )
|
57
86
|
do_info( contract_address )
|
58
87
|
elsif ['l', 'layer', 'layers'].include?( command )
|
59
|
-
|
88
|
+
## note: outdir - save into cache for now
|
89
|
+
do_layers( contract_address, outdir: outdir )
|
90
|
+
elsif ['t', 'token', 'tokens'].include?( command )
|
91
|
+
## note: outdir - saves into token (metadata) & token-i (images)
|
92
|
+
do_tokens( contract_address, outdir: outdir )
|
60
93
|
else
|
61
94
|
puts "!! ERROR - unknown command >#{command}<, sorry"
|
62
95
|
end
|
@@ -77,11 +110,11 @@ class Tool
|
|
77
110
|
symbol = c.symbol
|
78
111
|
totalSupply = c.totalSupply
|
79
112
|
|
80
|
-
|
113
|
+
recs = []
|
81
114
|
tokenIds = (0..2)
|
82
115
|
tokenIds.each do |tokenId|
|
83
116
|
tokenURI = c.tokenURI( tokenId )
|
84
|
-
|
117
|
+
recs << [tokenId, tokenURI]
|
85
118
|
end
|
86
119
|
|
87
120
|
puts " name: >#{name}<"
|
@@ -89,122 +122,34 @@ class Tool
|
|
89
122
|
puts " totalSupply: >#{totalSupply}<"
|
90
123
|
puts
|
91
124
|
puts " tokenURIs #{tokenIds}:"
|
92
|
-
|
125
|
+
recs.each do |tokenId, tokenURI|
|
93
126
|
puts " tokenId #{tokenId}:"
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
str = Base64.decode64( str )
|
100
|
-
data = JSON.parse( str )
|
101
|
-
|
102
|
-
|
103
|
-
## check for image_data - and replace if base64 encoded
|
104
|
-
image_data = data['image_data']
|
105
|
-
|
106
|
-
if image_data.start_with?( 'data:image/svg+xml;base64' )
|
107
|
-
data['image_data'] = '...'
|
108
|
-
str = image_data.sub( 'data:image/svg+xml;base64', '' )
|
109
|
-
image_data = Base64.decode64( str )
|
110
|
-
end
|
111
|
-
|
112
|
-
pp data
|
127
|
+
meta = Meta.parse( tokenURI )
|
128
|
+
if meta.data.empty? ## assume "off-blockchain" if no "on-blockchain" data found
|
129
|
+
puts " #{tokenURI}"
|
130
|
+
else ## assume "on-blockchain" data
|
131
|
+
pp meta.data
|
113
132
|
puts
|
114
133
|
puts " image_data:"
|
115
|
-
puts image_data
|
116
|
-
else
|
117
|
-
puts " #{tokenURI}"
|
134
|
+
puts meta.image_data
|
118
135
|
end
|
119
136
|
end
|
120
137
|
end
|
121
138
|
|
122
139
|
|
123
140
|
|
124
|
-
|
125
|
-
PNGSIG = "\x89PNG".force_encoding( Encoding::ASCII_8BIT )
|
126
|
-
GIF87SIG = "GIF87".force_encoding( Encoding::ASCII_8BIT )
|
127
|
-
GIF89SIG = "GIF89".force_encoding( Encoding::ASCII_8BIT )
|
128
|
-
|
129
|
-
|
130
|
-
def self.do_layers( contract_address )
|
141
|
+
def self.do_layers( contract_address, outdir: )
|
131
142
|
puts "==> query layers for art collection contract @ >#{contract_address}<:"
|
132
143
|
|
133
|
-
|
134
|
-
|
135
|
-
name = c.name
|
136
|
-
symbol = c.symbol
|
137
|
-
totalSupply = c.totalSupply
|
138
|
-
|
139
|
-
|
140
|
-
traitDetails = []
|
141
|
-
n=0
|
142
|
-
loop do
|
143
|
-
m=0
|
144
|
-
loop do
|
145
|
-
rec = c.traitDetails( n, m )
|
146
|
-
break if rec == ['','',false]
|
147
|
-
|
148
|
-
traitDetails << [[n,m], rec ]
|
149
|
-
m += 1
|
150
|
-
sleep( 0.5 )
|
151
|
-
end
|
152
|
-
break if m==0
|
153
|
-
n += 1
|
154
|
-
end
|
155
|
-
|
156
|
-
headers = ['index', 'name', 'type', 'hide']
|
157
|
-
recs = []
|
158
|
-
traitDetails.each do |t|
|
159
|
-
recs << [ t[0].join('/'),
|
160
|
-
t[1][0],
|
161
|
-
t[1][1],
|
162
|
-
t[1][2].to_s]
|
163
|
-
end
|
164
|
-
|
165
|
-
buf = String.new('')
|
166
|
-
buf << headers.join( ', ' )
|
167
|
-
buf << "\n"
|
168
|
-
recs.each do |rec|
|
169
|
-
buf << rec.join( ', ' )
|
170
|
-
buf << "\n"
|
171
|
-
end
|
172
|
-
|
173
|
-
outdir = "./tmp/#{contract_address}"
|
174
|
-
write_text( "#{outdir}/layers.csv", buf )
|
175
|
-
|
176
|
-
#####
|
177
|
-
# try to download all images
|
178
|
-
traitDetails.each do |t|
|
179
|
-
n,m = t[0]
|
180
|
-
data = c.traitData( n, m )
|
181
|
-
|
182
|
-
basename = "#{n}_#{m}"
|
183
|
-
if data.start_with?( PNGSIG )
|
184
|
-
puts "BINGO!! it's a png blob"
|
185
|
-
write_blob( "#{outdir}/#{basename}.png", data )
|
186
|
-
elsif data.start_with?( GIF87SIG ) || data.start_with?( GIF89SIG )
|
187
|
-
puts "BINGO!! it's a gif blob"
|
188
|
-
write_blob( "#{outdir}/#{basename}.gif", data )
|
189
|
-
elsif data.start_with?( JPGSIG )
|
190
|
-
puts "BINGO!! it's a jpg blob"
|
191
|
-
write_blob( "#{outdir}/#{basename}.jpg", data )
|
192
|
-
else
|
193
|
-
puts "!! ERROR - unknown image format; sorry"
|
194
|
-
exit 1
|
195
|
-
end
|
196
|
-
sleep( 0.5 )
|
197
|
-
end
|
198
|
-
|
199
|
-
|
200
|
-
puts " name: >#{name}<"
|
201
|
-
puts " symbol: >#{symbol}<"
|
202
|
-
puts " totalSupply: >#{totalSupply}<"
|
203
|
-
puts
|
204
|
-
puts " traitDetails:"
|
205
|
-
pp traitDetails
|
144
|
+
ArtQ.download_layers( contract_address,
|
145
|
+
outdir: outdir )
|
206
146
|
end
|
207
147
|
|
148
|
+
def self.do_tokens( contract_address, outdir: )
|
149
|
+
puts "==> query inline 'on-blockchain' token metadata & images for art collection contract @ >#{contract_address}<:"
|
150
|
+
ArtQ.download_tokens( contract_address,
|
151
|
+
outdir: outdir )
|
152
|
+
end
|
208
153
|
|
209
154
|
end # class Tool
|
210
155
|
end # module ArtQ
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: artq
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gerald Bauer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-12-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ethlite
|
@@ -76,6 +76,8 @@ files:
|
|
76
76
|
- bin/artq
|
77
77
|
- lib/artq.rb
|
78
78
|
- lib/artq/contract.rb
|
79
|
+
- lib/artq/layers.rb
|
80
|
+
- lib/artq/tokens.rb
|
79
81
|
- lib/artq/version.rb
|
80
82
|
homepage: https://github.com/pixelartexchange/artbase
|
81
83
|
licenses:
|