trident_assistant 0.1.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.
@@ -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,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TridentAssistant
4
+ VERSION = "0.1.0"
5
+ 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: []