trident_assistant 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rubocop.yml +132 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +106 -0
- data/LICENSE.txt +21 -0
- data/README.md +47 -0
- data/Rakefile +16 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/exe/ta +6 -0
- data/lib/trident_assistant/api/collectible.rb +81 -0
- data/lib/trident_assistant/api/collection.rb +61 -0
- data/lib/trident_assistant/api/metadata.rb +26 -0
- data/lib/trident_assistant/api/order.rb +77 -0
- data/lib/trident_assistant/api.rb +27 -0
- data/lib/trident_assistant/cli/base.rb +55 -0
- data/lib/trident_assistant/cli/collectible.rb +100 -0
- data/lib/trident_assistant/cli/collection.rb +81 -0
- data/lib/trident_assistant/cli/metadata.rb +119 -0
- data/lib/trident_assistant/cli/nfo.rb +101 -0
- data/lib/trident_assistant/cli/order.rb +77 -0
- data/lib/trident_assistant/cli/utils.rb +23 -0
- data/lib/trident_assistant/cli.rb +45 -0
- data/lib/trident_assistant/client.rb +116 -0
- data/lib/trident_assistant/utils/memo.rb +62 -0
- data/lib/trident_assistant/utils/metadata.rb +117 -0
- data/lib/trident_assistant/utils.rb +88 -0
- data/lib/trident_assistant/version.rb +5 -0
- data/lib/trident_assistant.rb +18 -0
- metadata +92 -0
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "./cli/base"
|
4
|
+
require_relative "./cli/collectible"
|
5
|
+
require_relative "./cli/collection"
|
6
|
+
require_relative "./cli/metadata"
|
7
|
+
require_relative "./cli/nfo"
|
8
|
+
require_relative "./cli/order"
|
9
|
+
require_relative "./cli/utils"
|
10
|
+
|
11
|
+
module TridentAssistant
|
12
|
+
# CLI tool
|
13
|
+
module CLI
|
14
|
+
# Main commands of CLI
|
15
|
+
class Command < TridentAssistant::CLI::Base
|
16
|
+
class_option :pretty, type: :boolean, aliases: "-p", default: true, desc: "Print output in pretty"
|
17
|
+
class_option :environment, type: :string, aliases: "-e", default: "prod", desc: "prod | test | dev"
|
18
|
+
class_option :endpoint, type: :string, aliases: "-E", desc: "Specify an endpoint"
|
19
|
+
|
20
|
+
desc "version", "Display TridentAssistant version"
|
21
|
+
def version
|
22
|
+
log VERSION
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.exit_on_failure?
|
26
|
+
true
|
27
|
+
end
|
28
|
+
|
29
|
+
desc "collectible", "commands for collectible"
|
30
|
+
subcommand "collectible", CLI::Collectible
|
31
|
+
|
32
|
+
desc "collection", "commands for collection"
|
33
|
+
subcommand "collection", CLI::Collection
|
34
|
+
|
35
|
+
desc "nfo", "commands for nfo"
|
36
|
+
subcommand "nfo", CLI::NFO
|
37
|
+
|
38
|
+
desc "metadata", "commands for metadata"
|
39
|
+
subcommand "metadata", CLI::Metadata
|
40
|
+
|
41
|
+
desc "order", "commands for order"
|
42
|
+
subcommand "order", CLI::Order
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TridentAssistant
|
4
|
+
# HTTP client to trident server
|
5
|
+
class Client
|
6
|
+
class HttpError < TridentAssistant::Error; end
|
7
|
+
class RequestError < TridentAssistant::Error; end
|
8
|
+
|
9
|
+
ENDPOINT = "https://thetrident.one"
|
10
|
+
|
11
|
+
attr_reader :endpoint
|
12
|
+
|
13
|
+
def initialize(**kwargs)
|
14
|
+
@endpoint = URI(kwargs[:endpoint] || ENDPOINT)
|
15
|
+
end
|
16
|
+
|
17
|
+
def get(path, **options)
|
18
|
+
request(:get, path, **options)
|
19
|
+
end
|
20
|
+
|
21
|
+
def post(path, **options)
|
22
|
+
request(:post, path, **options)
|
23
|
+
end
|
24
|
+
|
25
|
+
def put(path, **options)
|
26
|
+
request(:put, path, **options)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def request(verb, path, **options)
|
32
|
+
uri = uri_for path
|
33
|
+
|
34
|
+
options[:headers] ||= {}
|
35
|
+
options[:headers]["Content-Type"] ||= "application/json"
|
36
|
+
|
37
|
+
begin
|
38
|
+
response = HTTP.timeout(connect: 5, write: 10, read: 10).request(verb, uri, options)
|
39
|
+
rescue HTTP::Error => e
|
40
|
+
raise HttpError, e.message
|
41
|
+
end
|
42
|
+
|
43
|
+
raise RequestError, response.to_s unless response.status.success?
|
44
|
+
|
45
|
+
parse_response(response) do |parse_as, result|
|
46
|
+
case parse_as
|
47
|
+
when :json
|
48
|
+
break result if result["message"].blank?
|
49
|
+
|
50
|
+
raise result["message"]
|
51
|
+
else
|
52
|
+
result
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def uri_for(path)
|
58
|
+
uri_options = {
|
59
|
+
scheme: endpoint.scheme,
|
60
|
+
host: endpoint.host,
|
61
|
+
port: endpoint.port,
|
62
|
+
path: path
|
63
|
+
}
|
64
|
+
Addressable::URI.new(uri_options)
|
65
|
+
end
|
66
|
+
|
67
|
+
def parse_response(response)
|
68
|
+
content_type = response.headers[:content_type]
|
69
|
+
parse_as = {
|
70
|
+
%r{^application/json} => :json,
|
71
|
+
%r{^image/.*} => :file,
|
72
|
+
%r{^text/html} => :xml,
|
73
|
+
%r{^text/plain} => :plain
|
74
|
+
}.each_with_object([]) { |match, memo| memo << match[1] if content_type =~ match[0] }.first || :plain
|
75
|
+
|
76
|
+
if parse_as == :plain
|
77
|
+
result = JSON.parse(response&.body&.to_s)
|
78
|
+
result && yield(:json, result)
|
79
|
+
|
80
|
+
yield(:plain, response.body)
|
81
|
+
end
|
82
|
+
|
83
|
+
case parse_as
|
84
|
+
when :json
|
85
|
+
result = JSON.parse(response.body.to_s)
|
86
|
+
when :file
|
87
|
+
extension =
|
88
|
+
if response.headers[:content_type] =~ %r{^image/.*}
|
89
|
+
{
|
90
|
+
"image/gif": ".gif",
|
91
|
+
"image/jpeg": ".jpg",
|
92
|
+
"image/png": ".png"
|
93
|
+
}[response.headers["content-type"]]
|
94
|
+
else
|
95
|
+
""
|
96
|
+
end
|
97
|
+
|
98
|
+
begin
|
99
|
+
file = Tempfile.new(["mixin-file-", extension])
|
100
|
+
file.binmode
|
101
|
+
file.write(response.body)
|
102
|
+
ensure
|
103
|
+
file&.close
|
104
|
+
end
|
105
|
+
|
106
|
+
result = file
|
107
|
+
when :xml
|
108
|
+
result = Hash.from_xml(response.body.to_s)
|
109
|
+
else
|
110
|
+
result = response.body
|
111
|
+
end
|
112
|
+
|
113
|
+
yield(parse_as, result)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TridentAssistant
|
4
|
+
module Utils
|
5
|
+
# build metadata of NFT
|
6
|
+
class Memo
|
7
|
+
attr_accessor :type, :token_id, :asset_id, :order_id, :price, :reserve_price, :receiver_id, :start_at,
|
8
|
+
:expire_at, :encoded, :decoded
|
9
|
+
|
10
|
+
def initialize(**kwargs)
|
11
|
+
@type = kwargs[:type]
|
12
|
+
@token_id = kwargs[:token_id]
|
13
|
+
@asset_id = kwargs[:asset_id]
|
14
|
+
@order_id = kwargs[:order_id]
|
15
|
+
@price = kwargs[:price]
|
16
|
+
@reserve_price = kwargs[:reserve_price]
|
17
|
+
@receiver_id = kwargs[:receiver_id]
|
18
|
+
@start_at = kwargs[:start_at]
|
19
|
+
@expire_at = kwargs[:expire_at]
|
20
|
+
@encoded = kwargs[:encoded]
|
21
|
+
end
|
22
|
+
|
23
|
+
def json
|
24
|
+
{
|
25
|
+
T: type,
|
26
|
+
N: token_id,
|
27
|
+
A: asset_id,
|
28
|
+
O: order_id,
|
29
|
+
P: price,
|
30
|
+
R: reserve_price,
|
31
|
+
RC: receiver_id,
|
32
|
+
S: start_at,
|
33
|
+
E: expire_at
|
34
|
+
}.compact
|
35
|
+
end
|
36
|
+
|
37
|
+
def encode
|
38
|
+
hash = {
|
39
|
+
T: type,
|
40
|
+
N: token_id && MixinBot::Utils::UUID.new(hex: token_id).packed,
|
41
|
+
A: asset_id && MixinBot::Utils::UUID.new(hex: asset_id).packed,
|
42
|
+
O: order_id && MixinBot::Utils::UUID.new(hex: order_id).packed,
|
43
|
+
P: price && format("%.8f", price.to_f).gsub(/(0)+\z/, ""),
|
44
|
+
R: reserve_price && format("%.8f", reserve_price.to_f).gsub(/(0)+\z/, ""),
|
45
|
+
RC: receiver_id && MixinBot::Utils::UUID.new(hex: receiver_id).packed,
|
46
|
+
S: start_at && Time.parse(start_at).to_i,
|
47
|
+
E: expire_at && Time.parse(start_at).to_i
|
48
|
+
}.compact
|
49
|
+
|
50
|
+
@encoded =
|
51
|
+
Base64.urlsafe_encode64(
|
52
|
+
MessagePack.pack(hash),
|
53
|
+
padding: false
|
54
|
+
)
|
55
|
+
end
|
56
|
+
|
57
|
+
def decode
|
58
|
+
json
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TridentAssistant
|
4
|
+
module Utils
|
5
|
+
# build metadata of NFT
|
6
|
+
class Metadata
|
7
|
+
class InvalidFormatError < TridentAssistant::Error; end
|
8
|
+
|
9
|
+
attr_reader :creator, :collection, :token, :checksum
|
10
|
+
|
11
|
+
def initialize(**kwargs)
|
12
|
+
@creator = kwargs[:creator] || {}
|
13
|
+
@collection = kwargs[:collection] || {}
|
14
|
+
@token = kwargs[:token] || {}
|
15
|
+
@checksum = kwargs[:checksum] || {}
|
16
|
+
end
|
17
|
+
|
18
|
+
def json
|
19
|
+
{
|
20
|
+
creator: creator,
|
21
|
+
collection: collection,
|
22
|
+
token: token,
|
23
|
+
checksum: checksum
|
24
|
+
}.compact.with_indifferent_access
|
25
|
+
end
|
26
|
+
|
27
|
+
def validate!
|
28
|
+
raise InvalidFormatError, creator unless creator_valid?
|
29
|
+
raise InvalidFormatError, collection unless collection_valid?
|
30
|
+
raise InvalidFormatError, token unless token_valid?
|
31
|
+
raise InvalidFormatError, checksum unless checksum_valid?
|
32
|
+
raise InvalidFormatError, "failed to validate hash" unless all_hash_valid?
|
33
|
+
|
34
|
+
true
|
35
|
+
end
|
36
|
+
|
37
|
+
def valid?
|
38
|
+
creator_valid? && collection_valid? && token_valid? && checksum_valid? && all_hash_valid?
|
39
|
+
end
|
40
|
+
|
41
|
+
def creator_valid?
|
42
|
+
return false unless creator.is_a?(Hash)
|
43
|
+
|
44
|
+
@creator = creator.with_indifferent_access
|
45
|
+
creator["id"].present? && creator["name"].present?
|
46
|
+
end
|
47
|
+
|
48
|
+
def collection_valid?
|
49
|
+
return false unless collection.is_a?(Hash)
|
50
|
+
|
51
|
+
@collection = collection.with_indifferent_access
|
52
|
+
return false unless collection["id"].match?(/\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\z/)
|
53
|
+
return false if collection["name"].blank?
|
54
|
+
|
55
|
+
true
|
56
|
+
end
|
57
|
+
|
58
|
+
def token_valid?
|
59
|
+
return false unless token.is_a?(Hash)
|
60
|
+
|
61
|
+
@token = token.with_indifferent_access
|
62
|
+
return false unless token["id"].match?(/\A(?!0)\d+\z/)
|
63
|
+
return false if token["id"].to_i > 8**64
|
64
|
+
return false if token["name"].blank?
|
65
|
+
|
66
|
+
true
|
67
|
+
end
|
68
|
+
|
69
|
+
def checksum_valid?
|
70
|
+
return false unless checksum.is_a?(Hash)
|
71
|
+
|
72
|
+
@checksum = checksum.with_indifferent_access
|
73
|
+
checksum["algorithm"] && checksum["fields"].is_a?(Array)
|
74
|
+
end
|
75
|
+
|
76
|
+
def all_hash_valid?
|
77
|
+
checksum["fields"].each do |field|
|
78
|
+
value = json
|
79
|
+
|
80
|
+
field.split(".").each do |key|
|
81
|
+
next unless value.is_a?(Hash)
|
82
|
+
|
83
|
+
return false if key == "hash" && value["hash"] != TridentAssistant::Utils.hash_from_url(value["url"])
|
84
|
+
|
85
|
+
value = value[key]
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
true
|
90
|
+
end
|
91
|
+
|
92
|
+
def checksum_content
|
93
|
+
return unless checksum_valid?
|
94
|
+
|
95
|
+
checksum["fields"].map do |field|
|
96
|
+
value = json
|
97
|
+
field.split(".").each do |key|
|
98
|
+
value = (value[key] if value.is_a?(Hash))
|
99
|
+
end
|
100
|
+
value.to_s
|
101
|
+
end.join
|
102
|
+
end
|
103
|
+
|
104
|
+
def metahash
|
105
|
+
return unless valid?
|
106
|
+
|
107
|
+
alg = checksum["algorithm"]
|
108
|
+
case alg
|
109
|
+
when "sha256", "sha3-256"
|
110
|
+
SHA3::Digest::SHA256.hexdigest checksum_content
|
111
|
+
else
|
112
|
+
raise "algorithm #{alg} not supported!"
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "./utils/memo"
|
4
|
+
require_relative "./utils/metadata"
|
5
|
+
|
6
|
+
module TridentAssistant
|
7
|
+
# Some useful methods
|
8
|
+
module Utils
|
9
|
+
MINT_ASSET_ID = "c94ac88f-4671-3976-b60a-09064f1811e8"
|
10
|
+
MINT_AMOUNT = 0.001
|
11
|
+
NFO_MTG = {
|
12
|
+
members: %w[
|
13
|
+
047061e6-496d-4c35-b06b-b0424a8a400d
|
14
|
+
4b188942-9fb0-4b99-b4be-e741a06d1ebf
|
15
|
+
50115496-7247-4e2c-857b-ec8680756bee
|
16
|
+
a51006d0-146b-4b32-a2ce-7defbf0d7735
|
17
|
+
acf65344-c778-41ee-bacb-eb546bacfb9f
|
18
|
+
cf4abd9c-2cfa-4b5a-b1bd-e2b61a83fabd
|
19
|
+
dd655520-c919-4349-822f-af92fabdbdf4
|
20
|
+
].sort,
|
21
|
+
threshold: 5
|
22
|
+
}.freeze
|
23
|
+
TRIDENT_MTG = {
|
24
|
+
members: %w[
|
25
|
+
6f5a84ce-d663-451e-b413-2d0c84b7629d
|
26
|
+
99216bb5-9787-49b6-b251-537362ce23eb
|
27
|
+
fcc1e3ec-97f1-41a7-89a3-20a0ec30a31f
|
28
|
+
1a361145-66a7-48cd-ab6c-db9a42da4074
|
29
|
+
9ba50819-159c-45e6-9bed-1eb2dded3360
|
30
|
+
].sort,
|
31
|
+
threshold: 3
|
32
|
+
}.freeze
|
33
|
+
|
34
|
+
class << self
|
35
|
+
def hash_from_url(url)
|
36
|
+
return if url.to_s.blank?
|
37
|
+
|
38
|
+
content =
|
39
|
+
begin
|
40
|
+
URI.parse(url).open(&:read)
|
41
|
+
rescue OpenURI::HTTPError
|
42
|
+
""
|
43
|
+
end
|
44
|
+
|
45
|
+
SHA3::Digest::SHA256.hexdigest content
|
46
|
+
end
|
47
|
+
|
48
|
+
def mixin_bot_from_keystore(keystore)
|
49
|
+
keystore = parse_json keystore if keystore.is_a?(String)
|
50
|
+
|
51
|
+
MixinBot::API.new(
|
52
|
+
client_id: keystore["client_id"],
|
53
|
+
session_id: keystore["session_id"],
|
54
|
+
pin_token: keystore["pin_token"],
|
55
|
+
private_key: keystore["private_key"]
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
59
|
+
def parse_metadata(input)
|
60
|
+
metadata =
|
61
|
+
case input
|
62
|
+
when String
|
63
|
+
TridentAssistant::Utils.parse_json input
|
64
|
+
when Hash
|
65
|
+
input
|
66
|
+
else
|
67
|
+
{}
|
68
|
+
end
|
69
|
+
TridentAssistant::Utils::Metadata.new(
|
70
|
+
creator: metadata["creator"],
|
71
|
+
collection: metadata["collection"],
|
72
|
+
token: metadata["token"],
|
73
|
+
checksum: metadata["checksum"]
|
74
|
+
)
|
75
|
+
end
|
76
|
+
|
77
|
+
def parse_json(input)
|
78
|
+
input =
|
79
|
+
if File.file? input
|
80
|
+
File.read input
|
81
|
+
else
|
82
|
+
input
|
83
|
+
end
|
84
|
+
JSON.parse(input).with_indifferent_access
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "mixin_bot"
|
4
|
+
require "open-uri"
|
5
|
+
|
6
|
+
# Trident SDK
|
7
|
+
module TridentAssistant
|
8
|
+
class Error < StandardError; end
|
9
|
+
|
10
|
+
def self.api
|
11
|
+
TridentAssistant::API.new
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
require_relative "trident_assistant/api"
|
16
|
+
require_relative "trident_assistant/cli"
|
17
|
+
require_relative "trident_assistant/utils"
|
18
|
+
require_relative "trident_assistant/version"
|
metadata
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: trident_assistant
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- an-lee
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-04-07 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: mixin_bot
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.8'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.8'
|
27
|
+
description: A simple program to use Trident NFT
|
28
|
+
email:
|
29
|
+
- an.lee.work@gmail.com
|
30
|
+
executables:
|
31
|
+
- ta
|
32
|
+
extensions: []
|
33
|
+
extra_rdoc_files: []
|
34
|
+
files:
|
35
|
+
- ".rubocop.yml"
|
36
|
+
- CHANGELOG.md
|
37
|
+
- CODE_OF_CONDUCT.md
|
38
|
+
- Gemfile
|
39
|
+
- Gemfile.lock
|
40
|
+
- LICENSE.txt
|
41
|
+
- README.md
|
42
|
+
- Rakefile
|
43
|
+
- bin/console
|
44
|
+
- bin/setup
|
45
|
+
- exe/ta
|
46
|
+
- lib/trident_assistant.rb
|
47
|
+
- lib/trident_assistant/api.rb
|
48
|
+
- lib/trident_assistant/api/collectible.rb
|
49
|
+
- lib/trident_assistant/api/collection.rb
|
50
|
+
- lib/trident_assistant/api/metadata.rb
|
51
|
+
- lib/trident_assistant/api/order.rb
|
52
|
+
- lib/trident_assistant/cli.rb
|
53
|
+
- lib/trident_assistant/cli/base.rb
|
54
|
+
- lib/trident_assistant/cli/collectible.rb
|
55
|
+
- lib/trident_assistant/cli/collection.rb
|
56
|
+
- lib/trident_assistant/cli/metadata.rb
|
57
|
+
- lib/trident_assistant/cli/nfo.rb
|
58
|
+
- lib/trident_assistant/cli/order.rb
|
59
|
+
- lib/trident_assistant/cli/utils.rb
|
60
|
+
- lib/trident_assistant/client.rb
|
61
|
+
- lib/trident_assistant/utils.rb
|
62
|
+
- lib/trident_assistant/utils/memo.rb
|
63
|
+
- lib/trident_assistant/utils/metadata.rb
|
64
|
+
- lib/trident_assistant/version.rb
|
65
|
+
homepage: https://github.com/TheTridentOne/trident_assistant
|
66
|
+
licenses:
|
67
|
+
- MIT
|
68
|
+
metadata:
|
69
|
+
homepage_uri: https://github.com/TheTridentOne/trident_assistant
|
70
|
+
source_code_uri: https://github.com/TheTridentOne/trident_assistant
|
71
|
+
changelog_uri: https://github.com/TheTridentOne/trident_assistant
|
72
|
+
rubygems_mfa_required: 'true'
|
73
|
+
post_install_message:
|
74
|
+
rdoc_options: []
|
75
|
+
require_paths:
|
76
|
+
- lib
|
77
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: 2.6.0
|
82
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
83
|
+
requirements:
|
84
|
+
- - ">="
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '0'
|
87
|
+
requirements: []
|
88
|
+
rubygems_version: 3.3.4
|
89
|
+
signing_key:
|
90
|
+
specification_version: 4
|
91
|
+
summary: A simple program to use Trident NFT
|
92
|
+
test_files: []
|