ethscribe 0.0.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1 -0
- data/Manifest.txt +2 -0
- data/README.md +86 -4
- data/Rakefile +4 -3
- data/lib/ethscribe/api.rb +190 -0
- data/lib/ethscribe/version.rb +19 -0
- data/lib/ethscribe.rb +92 -1
- metadata +22 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '09ac9a5eb1dbb35dde2105a3865bf6c67edd5469e8f9518e46949752f127991a'
|
4
|
+
data.tar.gz: 81e37a9c8a75bf4b1ec7a7ac82feccee8906a4a45636c750f7ba54e8c3797334
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5cc33bb70781c8490fb1f5c8c3512f22d614fa6eade666d90ec7c1e7e30a77559e42a77f0bbaa28518111b1b1b0da498c764b9627d31488e0aab3d7788919f3b
|
7
|
+
data.tar.gz: 73547597a38a756b3be3dcf8d11ee387e651dffdfea3db936f250a146288bdc74b5a7f2d575e1a9eccce9e21b1b204591e4df8436601656f35780866a29afa06
|
data/CHANGELOG.md
CHANGED
data/Manifest.txt
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
# Ethscribe - Inscription (Ethscription Calldata) API Wrapper & Helpers for Ethereum & Co.
|
1
|
+
# Ethscribe - Inscription / Inscribe (Ethscription Calldata) API Wrapper & Helpers for Ethereum & Co.
|
2
2
|
|
3
|
-
ethscribe - inscription (ethscription calldata) api wrapper & helpers for Ethereum & co.
|
3
|
+
ethscribe - inscription / inscribe (ethscription calldata) api wrapper & helpers for Ethereum & co.
|
4
4
|
|
5
5
|
|
6
6
|
|
@@ -10,13 +10,95 @@ ethscribe - inscription (ethscription calldata) api wrapper & helpers for Ethe
|
|
10
10
|
* rdoc :: [rubydoc.info/gems/ethscribe](http://rubydoc.info/gems/ethscribe)
|
11
11
|
|
12
12
|
|
13
|
-
## What's Ethscription Calldata / Ethereum Inscription?!
|
14
13
|
|
15
|
-
|
14
|
+
## What's Ethscription Calldata - Ethereum Inscription / Inscribe?!
|
16
15
|
|
16
|
+
See [Introducing Ethscriptions - A new way of creating and sharing digital artifacts on the Ethereum blockchain using transaction calldata »](https://medium.com/@dumbnamenumbers/introducing-ethscriptions-698b295d6f2a)
|
17
17
|
|
18
18
|
|
19
19
|
|
20
|
+
## Usage
|
21
|
+
|
22
|
+
This is a little "lite" wrapper around the ethscriptions.com api(s).
|
23
|
+
|
24
|
+
|
25
|
+
> The Ethscriptions.com API (v1)
|
26
|
+
> does not require a key, however it is rate limited.
|
27
|
+
> If you need more throughput, contact Middlemarch on Twitter.
|
28
|
+
>
|
29
|
+
> If you build something cool, also contact Middlemarch on Twitter!
|
30
|
+
>
|
31
|
+
> There is a goerli API and a mainnet API. The base URIs are:
|
32
|
+
>
|
33
|
+
> - https://goerli-api.ethscriptions.com/api
|
34
|
+
> - https://mainnet-api.ethscriptions.com/api
|
35
|
+
>
|
36
|
+
> Append the below paths, plus a query string if you want, to access the API!
|
37
|
+
>
|
38
|
+
> -- [Introducing the Ethscriptions.com API (v1)](https://medium.com/@dumbnamenumbers/introducing-the-ethscriptions-com-api-v1-6d2c507d82cd)
|
39
|
+
|
40
|
+
|
41
|
+
|
42
|
+
The (ethereum) goerli testnet api is wrapped in `Ethscribe::Api.goerli` and
|
43
|
+
the (ethereum) mainnet api is wrapped in `Ethscribe::Api.mainnet`.
|
44
|
+
|
45
|
+
Let's try the mainnet:
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
require 'ethscribe'
|
49
|
+
|
50
|
+
web = Ethscribe::Api.mainnet # or Ethscribe::Api.goerli
|
51
|
+
|
52
|
+
|
53
|
+
## get latest 25 inscriptions (defaults: page_size=25, sort_order=desc)
|
54
|
+
pp web.ethscriptions
|
55
|
+
|
56
|
+
## get inscriptions page 1 (same as above)
|
57
|
+
pp web.ethscriptions( page: 1 )
|
58
|
+
|
59
|
+
# get inscriptions page 2
|
60
|
+
pp web.ethscriptions( page: 2 )
|
61
|
+
|
62
|
+
# get oldest first - sort_order=asc
|
63
|
+
pp web.ethscriptions( page: 1, sort_order: 'asc' )
|
64
|
+
pp web.ethscriptions( page: 2, sort_order: 'asc' )
|
65
|
+
|
66
|
+
|
67
|
+
# get inscription by id or num
|
68
|
+
pp web.ethscription( 0 )
|
69
|
+
pp web.ethscription( 1 )
|
70
|
+
pp web.ethscription( 1000 )
|
71
|
+
pp web.ethscription( 1_000_000 )
|
72
|
+
|
73
|
+
|
74
|
+
# get inscriptions owend by <addresss>
|
75
|
+
address = '0x2a878245b52a2d46cb4327541cbc96e403a84791'
|
76
|
+
pp web.ethscriptions_owned_by( address )
|
77
|
+
|
78
|
+
|
79
|
+
# get inscription (decoded) content_data and content_type by id or num
|
80
|
+
pp web.ethscription_data( 0 )
|
81
|
+
pp web.ethscription_data( 1 )
|
82
|
+
pp web.ethscription_data( 2 )
|
83
|
+
|
84
|
+
|
85
|
+
# check if content exists (using sha256 hash)
|
86
|
+
# inscribe no. 0
|
87
|
+
sha = '2817fd9cf901e4435253881550731a5edc5e519c19de46b08e2b19a18e95143e'
|
88
|
+
pp web.ethscription_exists( sha )
|
89
|
+
|
90
|
+
# inscribe no. ??
|
91
|
+
sha = '2817fd9cf901e4435253833550731a5edc5e519c19de46b08e2b19a18e95143e'
|
92
|
+
pp web.ethscription_exists( sha )
|
93
|
+
|
94
|
+
# check the indexer (block) status
|
95
|
+
pp web.block_status
|
96
|
+
```
|
97
|
+
|
98
|
+
|
99
|
+
That's it for now.
|
100
|
+
|
101
|
+
|
20
102
|
|
21
103
|
## Bonus - More Blockchain (Crypto) Tools, Libraries & Scripts In Ruby
|
22
104
|
|
data/Rakefile
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
require 'hoe'
|
2
|
-
|
2
|
+
require './lib/ethscribe/version.rb'
|
3
3
|
|
4
4
|
|
5
5
|
Hoe.spec 'ethscribe' do
|
6
|
-
self.version =
|
6
|
+
self.version = Ethscribe::VERSION
|
7
7
|
|
8
|
-
self.summary = 'ethscribe
|
8
|
+
self.summary = 'ethscribe - inscription / inscribe (ethscription calldata) api wrapper & helpers for Ethereum & co.'
|
9
9
|
self.description = summary
|
10
10
|
|
11
11
|
self.urls = { home: 'https://github.com/s6ruby/rubidity' }
|
@@ -18,6 +18,7 @@ Hoe.spec 'ethscribe' do
|
|
18
18
|
self.history_file = 'CHANGELOG.md'
|
19
19
|
|
20
20
|
self.extra_deps = [
|
21
|
+
['cocos'],
|
21
22
|
]
|
22
23
|
|
23
24
|
self.licenses = ['Public Domain']
|
@@ -0,0 +1,190 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module Ethscribe
|
4
|
+
|
5
|
+
|
6
|
+
class Api ## change/rename Api to Client - why? why not?
|
7
|
+
def self.goerli
|
8
|
+
@goerli ||= new( 'https://goerli-api.ethscriptions.com/api' )
|
9
|
+
@goerli
|
10
|
+
end
|
11
|
+
## todo: add test alias - why? why not?
|
12
|
+
|
13
|
+
def self.mainnet
|
14
|
+
@mainnet ||= new( 'https://api.ethscriptions.com/api' )
|
15
|
+
@mainnet
|
16
|
+
end
|
17
|
+
## todo: add eth, main or production alias - why? why not?
|
18
|
+
|
19
|
+
|
20
|
+
def config() Ethscribe.config; end ## convenience shortcut helper
|
21
|
+
|
22
|
+
|
23
|
+
def initialize( base )
|
24
|
+
@base = base
|
25
|
+
@requests = 0 ## count requests (for delay_in_s sleeping/throttling)
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
#
|
30
|
+
# Get all ethscriptions
|
31
|
+
#
|
32
|
+
# /ethscriptions
|
33
|
+
#
|
34
|
+
# Query parameters:
|
35
|
+
# page - integer (starting at 1)
|
36
|
+
# per_page - integer (default: 25 - max: 50)
|
37
|
+
# sort_order - string "asc" or "desc" (default: desc - latest first)
|
38
|
+
|
39
|
+
|
40
|
+
def ethscriptions( page: nil, per_page: nil, sort_order: nil )
|
41
|
+
src = "#{@base}/ethscriptions"
|
42
|
+
params = []
|
43
|
+
params << ['page', page.to_s] if page
|
44
|
+
params << ['per_page', per_page.to_s] if per_page
|
45
|
+
params << ['sort_order', sort_order.to_s.downcase ] if sort_order
|
46
|
+
|
47
|
+
if params.size > 0
|
48
|
+
src += "?" + params.map { |key,value| "#{key}=#{value}" }.join('&')
|
49
|
+
end
|
50
|
+
|
51
|
+
res = get( src )
|
52
|
+
res.json ## return parsed json data - why? why not?
|
53
|
+
end
|
54
|
+
|
55
|
+
#
|
56
|
+
# Get ethscriptions owned by address
|
57
|
+
#
|
58
|
+
# /ethscriptions/owned_by/:address
|
59
|
+
#
|
60
|
+
# Query parameters: page, per_page( max 1000), sort_order (asc / desc)
|
61
|
+
|
62
|
+
def ethscriptions_owned_by( address )
|
63
|
+
src = "#{@base}/ethscriptions/owned_by/#{address}"
|
64
|
+
|
65
|
+
res = get( src )
|
66
|
+
res.json ## return parsed json data - why? why not?
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
|
71
|
+
#
|
72
|
+
# Get specific ethscription
|
73
|
+
#
|
74
|
+
# /ethscriptions/:ethscription_id
|
75
|
+
#
|
76
|
+
# Or
|
77
|
+
#
|
78
|
+
# /ethscriptions/:ethscription_number
|
79
|
+
#
|
80
|
+
# (ethscription_id is the transaction hash of the transaction that created the ethscription)
|
81
|
+
|
82
|
+
# note: use singular (overload method by args not possible in ruby)
|
83
|
+
def ethscription( id_or_num )
|
84
|
+
src = "#{@base}/ethscriptions/#{id_or_num}"
|
85
|
+
res = get( src )
|
86
|
+
res.json ## return parsed json data - why? why not?
|
87
|
+
end
|
88
|
+
|
89
|
+
#
|
90
|
+
# Get data of an ethscription
|
91
|
+
#
|
92
|
+
# /ethscriptions/:ethscription_id/data
|
93
|
+
#
|
94
|
+
# Or
|
95
|
+
#
|
96
|
+
# /ethscriptions/:ethscription_number/data
|
97
|
+
#
|
98
|
+
# This will return the ethscription's raw decoded data in the correct mimetype
|
99
|
+
|
100
|
+
|
101
|
+
###
|
102
|
+
# use a struct-like content class - why? why not?
|
103
|
+
class Content
|
104
|
+
attr_reader :data,
|
105
|
+
:type,
|
106
|
+
:length
|
107
|
+
def initialize( data, type, length )
|
108
|
+
@data = data
|
109
|
+
@type = type
|
110
|
+
@length = length
|
111
|
+
end
|
112
|
+
|
113
|
+
alias_method :blob, :data
|
114
|
+
end ## (nested) class Content
|
115
|
+
|
116
|
+
|
117
|
+
def ethscription_data( id_or_num )
|
118
|
+
src = "#{@base}/ethscriptions/#{id_or_num}/data"
|
119
|
+
res = get( src )
|
120
|
+
|
121
|
+
content_type = res.content_type
|
122
|
+
content_length = res.content_length
|
123
|
+
|
124
|
+
## note - content_length -- returns an integer (number)
|
125
|
+
## puts "content_length:"
|
126
|
+
## print content_length.inspect
|
127
|
+
## print " - #{content_length.class.name}\n"
|
128
|
+
|
129
|
+
## fix-fix-fix
|
130
|
+
## if text/json/svg type etc.
|
131
|
+
## convert to utf8 (from binary blob why? why not?) - why? why not?
|
132
|
+
## or add text accessor to content?
|
133
|
+
|
134
|
+
content = Content.new(
|
135
|
+
res.blob,
|
136
|
+
content_type,
|
137
|
+
content_length )
|
138
|
+
content
|
139
|
+
end
|
140
|
+
|
141
|
+
|
142
|
+
###
|
143
|
+
# Check whether content is already ethscribed
|
144
|
+
#
|
145
|
+
# /ethscriptions/exists/:sha
|
146
|
+
#
|
147
|
+
# Where sha is the sha256 of the UTF-8 data URI
|
148
|
+
|
149
|
+
# {"result":false,"ethscription":null}
|
150
|
+
|
151
|
+
def ethscription_exists( sha )
|
152
|
+
src = "#{@base}/ethscriptions/exists/#{sha}"
|
153
|
+
res = get( src )
|
154
|
+
res.json ## return parsed json data - why? why not?
|
155
|
+
end
|
156
|
+
|
157
|
+
# Determine if the indexer is behind
|
158
|
+
#
|
159
|
+
# {"current_block_number":18619883,"last_imported_block":18619883,"blocks_behind":0}
|
160
|
+
|
161
|
+
def block_status
|
162
|
+
src = "#{@base}/block_status"
|
163
|
+
res = get( src )
|
164
|
+
res.json ## return parsed json data - why? why not?
|
165
|
+
end
|
166
|
+
|
167
|
+
|
168
|
+
def get( src )
|
169
|
+
@requests += 1
|
170
|
+
|
171
|
+
if @requests > 1 && config.delay_in_s
|
172
|
+
puts "request no. #{@requests}@#{@base}; sleeping #{config.delay_in_s} sec(s)..."
|
173
|
+
sleep( config.delay_in_s )
|
174
|
+
end
|
175
|
+
|
176
|
+
res = Webclient.get( src )
|
177
|
+
|
178
|
+
if res.status.ok?
|
179
|
+
res
|
180
|
+
else
|
181
|
+
## todo/fix: raise exception here!!!!
|
182
|
+
puts "!! ERROR - HTTP #{res.status.code} #{res.status.message} - failed web request >#{src}<; sorry"
|
183
|
+
exit 1
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end # class Api
|
187
|
+
|
188
|
+
|
189
|
+
end ## module Ethscibe
|
190
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
|
2
|
+
module Ethscribe
|
3
|
+
MAJOR = 0 ## todo: namespace inside version or something - why? why not??
|
4
|
+
MINOR = 2
|
5
|
+
PATCH = 0
|
6
|
+
VERSION = [MAJOR,MINOR,PATCH].join('.')
|
7
|
+
|
8
|
+
def self.version
|
9
|
+
VERSION
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.banner
|
13
|
+
"ethscribe/#{VERSION} on Ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}] in >#{root}<"
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.root
|
17
|
+
File.expand_path( File.dirname(File.dirname(File.dirname(__FILE__))) )
|
18
|
+
end
|
19
|
+
end
|
data/lib/ethscribe.rb
CHANGED
@@ -1,3 +1,94 @@
|
|
1
|
+
require 'cocos'
|
1
2
|
|
2
|
-
|
3
|
+
|
4
|
+
|
5
|
+
module Ethscribe
|
6
|
+
class Configuration
|
7
|
+
|
8
|
+
#######################
|
9
|
+
## accessors
|
10
|
+
def chain=(value)
|
11
|
+
if value.is_a?( String ) || value.is_a?( Symbol )
|
12
|
+
case value.downcase.to_s
|
13
|
+
when 'mainnet' # 'main', 'eth', 'prod', 'production'
|
14
|
+
@chain = 'mainnet'
|
15
|
+
@client = Ethscribe::Api.mainnet
|
16
|
+
when 'goerli' # 'testnet', 'test'
|
17
|
+
@chain = 'goerli'
|
18
|
+
@client = Ethscribe::Api.goerli
|
19
|
+
else
|
20
|
+
raise ArgumentError, "unknown chain - expected mainnet | goerli; got #{value}"
|
21
|
+
end
|
22
|
+
else
|
23
|
+
raise ArgumentError, "only string or symbol supported for now; sorry - got: #{value.inspect} : #{value.class.name}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def chain
|
28
|
+
## note - default to mainnet if not set
|
29
|
+
self.chain = 'mainnet' unless defined?( @chain )
|
30
|
+
@chain
|
31
|
+
end
|
32
|
+
|
33
|
+
## note: read-only for now - why? why not?
|
34
|
+
def client
|
35
|
+
## note - default to btc/ if not set
|
36
|
+
self.chain = 'mainnet' unless defined?( @client )
|
37
|
+
@client
|
38
|
+
end
|
39
|
+
|
40
|
+
def delay_in_s
|
41
|
+
## note - default to 1 (sec) if not set
|
42
|
+
self.delay_in_s = 1 unless defined?( @delay_in_s )
|
43
|
+
@delay_in_s
|
44
|
+
end
|
45
|
+
def delay_in_s=(value) @delay_in_s = value; end
|
46
|
+
alias_method :sleep, :delay_in_s ## add sleep alias (or wait) - why? why not?
|
47
|
+
alias_method :sleep=, :delay_in_s=
|
48
|
+
end # class Configuration
|
49
|
+
|
50
|
+
|
51
|
+
## lets you use
|
52
|
+
## Ordinals.configure do |config|
|
53
|
+
## config.chain = :btc
|
54
|
+
## end
|
55
|
+
def self.configure() yield( config ); end
|
56
|
+
def self.config() @config ||= Configuration.new; end
|
57
|
+
|
58
|
+
## add some convenience shortcut helpers (no config. required) - why? why not?
|
59
|
+
def self.client() config.client; end
|
60
|
+
def self.chain() config.chain; end
|
61
|
+
def self.chain=(value) config.chain = value; end
|
62
|
+
|
63
|
+
|
64
|
+
def self.mainnet?() config.chain == 'mainnet'; end
|
65
|
+
def self.goerli?() config.chain == 'goerli'; end
|
66
|
+
|
67
|
+
|
68
|
+
###################
|
69
|
+
### more convenience shortcuts
|
70
|
+
|
71
|
+
def self.inscribes( **kwargs ) client.ethscriptions( **kwargs ); end
|
72
|
+
def self.inscribe( id_or_num ) client.ethscription( id_or_num ); end
|
73
|
+
end # module Ethscribe
|
74
|
+
|
75
|
+
|
76
|
+
|
77
|
+
|
78
|
+
## our own code
|
79
|
+
require_relative 'ethscribe/version'
|
80
|
+
require_relative 'ethscribe/api'
|
81
|
+
|
82
|
+
|
83
|
+
|
84
|
+
module Ethscribe
|
85
|
+
#############
|
86
|
+
## add more convenience alias - why? why not?
|
87
|
+
API = Api
|
88
|
+
end # module Ethscribe
|
89
|
+
|
90
|
+
|
91
|
+
|
92
|
+
# say hello
|
93
|
+
puts Ethscribe.banner ## if defined?($RUBYCOCOS_DEBUG) && $RUBCOCOS_DEBUG
|
3
94
|
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ethscribe
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gerald Bauer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-11-
|
11
|
+
date: 2023-11-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: cocos
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: rdoc
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -44,8 +58,8 @@ dependencies:
|
|
44
58
|
- - "~>"
|
45
59
|
- !ruby/object:Gem::Version
|
46
60
|
version: '4.0'
|
47
|
-
description: ethscribe
|
48
|
-
for Ethereum & co.
|
61
|
+
description: ethscribe - inscription / inscribe (ethscription calldata) api wrapper
|
62
|
+
& helpers for Ethereum & co.
|
49
63
|
email: gerald.bauer@gmail.com
|
50
64
|
executables: []
|
51
65
|
extensions: []
|
@@ -59,6 +73,8 @@ files:
|
|
59
73
|
- README.md
|
60
74
|
- Rakefile
|
61
75
|
- lib/ethscribe.rb
|
76
|
+
- lib/ethscribe/api.rb
|
77
|
+
- lib/ethscribe/version.rb
|
62
78
|
homepage: https://github.com/s6ruby/rubidity
|
63
79
|
licenses:
|
64
80
|
- Public Domain
|
@@ -83,6 +99,6 @@ requirements: []
|
|
83
99
|
rubygems_version: 3.4.10
|
84
100
|
signing_key:
|
85
101
|
specification_version: 4
|
86
|
-
summary: ethscribe
|
87
|
-
Ethereum & co.
|
102
|
+
summary: ethscribe - inscription / inscribe (ethscription calldata) api wrapper &
|
103
|
+
helpers for Ethereum & co.
|
88
104
|
test_files: []
|