trident_assistant 0.1.1 → 0.1.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 83a47a5a2a8383565a259f1fb9017d257f0eb2c4d52c2dfb80e7d46fab64ed70
4
- data.tar.gz: 631300add4c04e26e00c235e8c9157c7d95334cb264432caac0c3edcf05873b0
3
+ metadata.gz: f164a9116aa89a445553f7af742157ac0da7670dc436c8235508ff5e4a8030be
4
+ data.tar.gz: e0602539c1087780a03b543c90da70afbae5aced33373eb50339575a733f97e7
5
5
  SHA512:
6
- metadata.gz: a082212e1eecb460dad1baa94f7fe48c7795f6e9631b8cefae1b8053970f2afc09b2386ad607e3cf1d7991641e1360534a5c7274820e9538f9d43dc143adc17a
7
- data.tar.gz: b87d7fa6949c0532a74cf9a0ecdcd4eb492eeae15fffe466e1c0acf00c48aff776c65bdbf0b405cb4681a7ec8adbf44ed6df726ae7f597fda588d25e09118be1
6
+ metadata.gz: 8c3292e2f06b569a50357d64e0d8811218cdb1911e0c2eb544560c25e64a698f02b758f59a149cad1c5b9d0705bc952b73aaff1c77360ef83379a9217a69f6f2
7
+ data.tar.gz: ed3f043aa8ec27ee9931d41f2becaa031588d208c7a7b142c29db028380939d4a220319b5768a4cb2a912c0051bbae2c1e9ff4601d5f87cec1a4a1d5d1f25bcd
data/.rubocop.yml CHANGED
@@ -25,6 +25,8 @@ Metrics/PerceivedComplexity:
25
25
  Enabled: false
26
26
  Metrics/CyclomaticComplexity:
27
27
  Enabled: false
28
+ Metrics/ModuleLength:
29
+ Enabled: false
28
30
 
29
31
  Gemspec/DateAssignment: # new in 1.10
30
32
  Enabled: true
@@ -9,7 +9,7 @@ module TridentAssistant
9
9
 
10
10
  def deposit(collection, token)
11
11
  token_id = MixinBot::Utils::Nfo.new(collection: collection, token: token).unique_token_id
12
- collectible = mixin_bot.collectibles(state: :unspent)["data"].find(&->(c) { c["token_id"] == token_id })
12
+ collectible = find_collectible(:unspent, token_id)
13
13
  raise "Unauthorized" if collectible.blank?
14
14
 
15
15
  nfo = MixinBot::Utils::Nfo.new(extra: "deposit".unpack1("H*")).encode.hex
@@ -36,8 +36,8 @@ module TridentAssistant
36
36
 
37
37
  def airdrop(collection, token, **kwargs)
38
38
  token_id = MixinBot::Utils::Nfo.new(collection: collection, token: token).unique_token_id
39
- collectible = mixin_bot.collectibles(state: :unspent)["data"].find(&->(c) { c["token_id"] == token_id })
40
- collectible ||= mixin_bot.collectibles(state: :signed)["data"].find(&->(c) { c["token_id"] == token_id })
39
+ collectible = find_collectible(:unspent, token_id)
40
+ collectible ||= find_collectible(:signed, token_id)
41
41
  raise "Cannot find collectible in wallet" if collectible.blank?
42
42
 
43
43
  memo =
@@ -56,25 +56,57 @@ module TridentAssistant
56
56
  )
57
57
  end
58
58
 
59
+ def transfer(collection, token, recipient, **_kwargs)
60
+ token_id = MixinBot::Utils::Nfo.new(collection: collection, token: token).unique_token_id
61
+ collectible = find_collectible(:unspent, token_id)
62
+ collectible ||= find_collectible(:signed, token_id)
63
+ raise "Cannot find collectible in wallet" if collectible.blank?
64
+
65
+ memo = "TRANSFER"
66
+ nfo = MixinBot::Utils::Nfo.new(extra: memo.unpack1("H*")).encode.hex
67
+
68
+ _transfer_nft(
69
+ collectible,
70
+ nfo,
71
+ receivers: [recipient],
72
+ threshold: 1
73
+ )
74
+ end
75
+
59
76
  private
60
77
 
78
+ def find_collectible(state, token_id)
79
+ limit = 500
80
+ offset = ""
81
+
82
+ loop do
83
+ r = mixin_bot.collectibles(state: state, limit: limit, offset: offset)["data"]
84
+ puts "offset: #{offset}, loaded #{r.size} collectibles"
85
+ collectible = r.find(&->(c) { c["token_id"] == token_id })
86
+ break collectible if collectible.present?
87
+
88
+ break if r.size < 500
89
+
90
+ offset = r.last["updated_at"]
91
+ end
92
+ end
93
+
61
94
  def _transfer_nft(collectible, nfo, **kwargs)
62
- tx =
63
- if collectible["state"] == "signed"
64
- collectible["signed_tx"]
65
- else
66
- raw = mixin_bot.build_collectible_transaction(
67
- collectible: collectible,
68
- receivers: kwargs[:receivers],
69
- receivers_threshold: kwargs[:threshold],
70
- nfo: nfo
71
- )
72
- mixin_bot.sign_raw_transaction raw
73
- end
74
-
75
- request = mixin_bot.create_sign_collectible_request tx
76
- sign = mixin_bot.sign_collectible_request request["request_id"], keystore[:pin]
77
- mixin_bot.send_raw_transaction sign["raw_transaction"]
95
+ if collectible["state"] == "signed"
96
+ mixin_bot.send_raw_transaction collectible["signed_tx"]
97
+ else
98
+ raw = mixin_bot.build_collectible_transaction(
99
+ collectible: collectible,
100
+ receivers: kwargs[:receivers],
101
+ receivers_threshold: kwargs[:threshold],
102
+ nfo: nfo
103
+ )
104
+ tx = mixin_bot.sign_raw_transaction raw
105
+
106
+ request = mixin_bot.create_sign_collectible_request tx
107
+ sign = mixin_bot.sign_collectible_request request["request_id"], keystore[:pin]
108
+ mixin_bot.send_raw_transaction sign["raw_transaction"]
109
+ end
78
110
  end
79
111
  end
80
112
  end
@@ -34,6 +34,96 @@ module TridentAssistant
34
34
  )
35
35
  end
36
36
 
37
+ def ask_order(collection, token, **kwargs)
38
+ raise ArgumentError, "price cannot be blank" if kwargs[:price].blank?
39
+ raise ArgumentError, "asset_id cannot be blank" if kwargs[:asset_id].blank?
40
+
41
+ trace_id = SecureRandom.uuid
42
+ token_id = MixinBot::Utils::Nfo.new(collection: collection, token: token).unique_token_id
43
+ memo =
44
+ TridentAssistant::Utils::Memo
45
+ .new(
46
+ type: "A",
47
+ order_id: trace_id,
48
+ token_id: token_id,
49
+ price: kwargs[:price],
50
+ asset_id: kwargs[:asset_id],
51
+ expire_at: kwargs[:expire_at]
52
+ )
53
+
54
+ mixin_bot.create_multisig_transaction(
55
+ keystore[:pin],
56
+ {
57
+ asset_id: EXCHANGE_ASSET_ID,
58
+ trace_id: trace_id,
59
+ amount: MINIMUM_AMOUNT,
60
+ memo: memo.encode,
61
+ receivers: TridentAssistant::Utils::TRIDENT_MTG[:members],
62
+ threshold: TridentAssistant::Utils::TRIDENT_MTG[:threshold]
63
+ }
64
+ )
65
+ end
66
+
67
+ def auction_order(collection, token, **kwargs)
68
+ raise ArgumentError, "price cannot be blank" if kwargs[:price].blank?
69
+ raise ArgumentError, "asset_id cannot be blank" if kwargs[:asset_id].blank?
70
+
71
+ trace_id = SecureRandom.uuid
72
+ token_id = MixinBot::Utils::Nfo.new(collection: collection, token: token).unique_token_id
73
+ memo =
74
+ TridentAssistant::Utils::Memo
75
+ .new(
76
+ type: "AU",
77
+ order_id: trace_id,
78
+ token_id: token_id,
79
+ price: kwargs[:price],
80
+ reserve_price: kwargs[:reserve_price],
81
+ asset_id: kwargs[:asset_id],
82
+ expire_at: kwargs[:expire_at]
83
+ )
84
+
85
+ mixin_bot.create_multisig_transaction(
86
+ keystore[:pin],
87
+ {
88
+ asset_id: EXCHANGE_ASSET_ID,
89
+ trace_id: trace_id,
90
+ amount: MINIMUM_AMOUNT,
91
+ memo: memo.encode,
92
+ receivers: TridentAssistant::Utils::TRIDENT_MTG[:members],
93
+ threshold: TridentAssistant::Utils::TRIDENT_MTG[:threshold]
94
+ }
95
+ )
96
+ end
97
+
98
+ def bid_order(collection, token, **kwargs)
99
+ raise ArgumentError, "price cannot be blank" if kwargs[:price].blank?
100
+ raise ArgumentError, "asset_id cannot be blank" if kwargs[:asset_id].blank?
101
+
102
+ trace_id = SecureRandom.uuid
103
+ token_id = MixinBot::Utils::Nfo.new(collection: collection, token: token).unique_token_id
104
+ memo =
105
+ TridentAssistant::Utils::Memo
106
+ .new(
107
+ type: "B",
108
+ order_id: trace_id,
109
+ token_id: token_id,
110
+ asset_id: kwargs[:asset_id],
111
+ expire_at: kwargs[:expire_at]
112
+ )
113
+
114
+ mixin_bot.create_multisig_transaction(
115
+ keystore[:pin],
116
+ {
117
+ asset_id: kwargs[:asset_id],
118
+ trace_id: trace_id,
119
+ amount: kwargs[:price],
120
+ memo: memo.encode,
121
+ receivers: TridentAssistant::Utils::TRIDENT_MTG[:members],
122
+ threshold: TridentAssistant::Utils::TRIDENT_MTG[:threshold]
123
+ }
124
+ )
125
+ end
126
+
37
127
  def fill_order(order_id)
38
128
  info = order order_id
39
129
  raise "Order state: #{info["state"]}" if info["state"] != "open"
@@ -44,9 +134,9 @@ module TridentAssistant
44
134
  mixin_bot.create_multisig_transaction(
45
135
  keystore[:pin],
46
136
  {
47
- asset_id: info["asset_id"],
137
+ asset_id: info["type"] == "BidOrder" ? EXCHANGE_ASSET_ID : info["asset_id"],
48
138
  trace_id: trace_id,
49
- amount: info["price"],
139
+ amount: info["type"] == "BidOrder" ? MINIMUM_AMOUNT : info["price"],
50
140
  memo: memo.encode,
51
141
  receivers: TridentAssistant::Utils::TRIDENT_MTG[:members],
52
142
  threshold: TridentAssistant::Utils::TRIDENT_MTG[:threshold]
@@ -65,9 +155,9 @@ module TridentAssistant
65
155
  mixin_bot.create_multisig_transaction(
66
156
  keystore[:pin],
67
157
  {
68
- asset_id: info["asset_id"],
158
+ asset_id: EXCHANGE_ASSET_ID,
69
159
  trace_id: trace_id,
70
- amount: info["price"],
160
+ amount: MINIMUM_AMOUNT,
71
161
  memo: memo.encode,
72
162
  receivers: TridentAssistant::Utils::TRIDENT_MTG[:members],
73
163
  threshold: TridentAssistant::Utils::TRIDENT_MTG[:threshold]
@@ -11,7 +11,7 @@ module TridentAssistant
11
11
  desc: "keystore or keystore.json file of Mixin bot"
12
12
  option :keystore, type: :string, aliases: "k", required: true, desc: "keystore or keystore.json file of Mixin bot"
13
13
  def index
14
- r = api.mixin_bot.collectibles state: options[:state]
14
+ r = api.mixin_bot.collectibles state: options[:state], limit: 500
15
15
 
16
16
  log r["data"]
17
17
  end
@@ -25,6 +25,15 @@ module TridentAssistant
25
25
  log r["data"]
26
26
  end
27
27
 
28
+ desc "transfer COLLECTION, TOKEN, RECIPIENT", "transfer NFT"
29
+ option :keystore, type: :string, aliases: "k", required: true, desc: "keystore or keystore.json file of Mixin bot"
30
+ def transfer(collection, token, recipient)
31
+ log api.transfer collection, token, recipient
32
+ log UI.fmt("{{v}} successfully transfer NFT")
33
+ rescue StandardError => e
34
+ log UI.fmt("{{x}} failed: #{e.inspect} #{e.backtrace.join("\n")}")
35
+ end
36
+
28
37
  desc "deposit COLLECTION TOKEN", "deposit NFT"
29
38
  option :keystore, type: :string, aliases: "k", required: true, desc: "keystore or keystore.json file of Mixin bot"
30
39
  def deposit(collection, token)
@@ -78,7 +87,18 @@ module TridentAssistant
78
87
  log UI.fmt("{{v}} airdrop receiver_id: #{receiver_id}")
79
88
  log UI.fmt("{{v}} airdrop start_at: #{start_at}")
80
89
 
81
- r = api.airdrop metadata.collection["id"], metadata.token["id"], receiver_id: receiver_id, start_at: start_at
90
+ attempt = 0
91
+ r =
92
+ begin
93
+ attempt += 1
94
+ api.airdrop metadata.collection["id"], metadata.token["id"], receiver_id: receiver_id, start_at: start_at
95
+ rescue Errno::ECONNRESET, OpenSSL::SSL::SSLError, MixinBot::HttpError => e
96
+ log UI.fmt("{{x}} #{e.inspect}")
97
+ log UI.fmt("Retrying #{attempt} times...")
98
+ sleep 0.5
99
+ retry
100
+ end
101
+
82
102
  log r["data"]
83
103
  data["_airdrop"] ||= {}
84
104
  data["_airdrop"]["hash"] = r["data"]["hash"]
@@ -21,15 +21,30 @@ module TridentAssistant
21
21
  def bulkmint(dir)
22
22
  raise "#{dir} is not a directory" unless Dir.exist?(dir)
23
23
 
24
- Dir.glob("#{dir}/*.json").each do |file|
24
+ files = Dir.glob("#{dir}/*.json")
25
+ minted = []
26
+ files.each do |file|
25
27
  log "-" * 80
26
28
  log UI.fmt("{{v}} found #{file}")
27
- _mint file
28
- rescue TridentAssistant::Utils::Metadata::InvalidFormatError, JSON::ParserError, Client::RequestError,
29
- MixinBot::Error, RuntimeError => e
29
+ attempt = 0
30
+ success =
31
+ begin
32
+ attempt += 1
33
+ _mint file
34
+ rescue Errno::ECONNRESET, OpenSSL::SSL::SSLError, MixinBot::HttpError, TridentAssistant::Client::HttpError,
35
+ TridentAssistant::Client::RequestError, MixinBot::RequestError => e
36
+ log UI.fmt("{{x}} #{e.inspect}")
37
+ log UI.fmt("Retrying #{attempt} times...")
38
+ sleep 0.5
39
+ retry
40
+ end
41
+ minted.push(file) if success
42
+ rescue TridentAssistant::Utils::Metadata::InvalidFormatError, JSON::ParserError, RuntimeError => e
30
43
  log UI.fmt("{{x}} #{file} failed: #{e.inspect}")
31
44
  next
32
45
  end
46
+ ensure
47
+ log UI.fmt("Found #{files.size} json file, minted #{minted.size}")
33
48
  end
34
49
 
35
50
  private
@@ -46,6 +61,14 @@ module TridentAssistant
46
61
 
47
62
  raise "Creator ID incompatible with keystore" if metadata.creator[:id] != api.mixin_bot.client_id
48
63
 
64
+ # upload metadata
65
+ if data.dig("_mint", "metahash").blank?
66
+ api.upload_metadata metadata: metadata.json, metahash: metadata.metahash
67
+ data["_mint"] ||= {}
68
+ data["_mint"]["metahash"] = metadata.metahash
69
+ end
70
+ log UI.fmt("{{v}} metadata uploaded: #{options[:endpoint]}/api/collectibles/#{metadata.metahash}")
71
+
49
72
  token_id = MixinBot::Utils::Nfo.new(collection: metadata.collection[:id],
50
73
  token: metadata.token[:id]).unique_token_id
51
74
  collectible =
@@ -56,51 +79,39 @@ module TridentAssistant
56
79
  end
57
80
  if collectible.present?
58
81
  log UI.fmt("{{v}} already minted: #{token_id}")
59
- return
82
+ return true
60
83
  end
61
84
 
62
- # upload metadata
63
- if data.dig("_mint", "metahash").blank?
64
- api.upload_metadata metadata: metadata.json, metahash: metadata.metahash
65
- data["_mint"] ||= {}
66
- data["_mint"]["metahash"] = metadata.metahash
67
- end
68
- log UI.fmt("{{v}} metadata uploaded: #{options[:endpoint]}/api/collectibles/#{metadata.metahash}")
69
-
70
85
  # pay to NFO
71
86
  trace_id = data.dig("_mint", "trace_id") || SecureRandom.uuid
72
87
  memo = api.mixin_bot.nft_memo metadata.collection[:id], metadata.token[:id].to_i, metadata.metahash
73
88
 
74
89
  data["_mint"]["trace_id"] = trace_id
75
- 10.times do
90
+ begin
76
91
  payment =
77
- begin
78
- api.mixin_bot.create_multisig_transaction(
79
- api.keystore[:pin],
80
- {
81
- asset_id: TridentAssistant::Utils::MINT_ASSET_ID,
82
- trace_id: trace_id,
83
- amount: TridentAssistant::Utils::MINT_AMOUNT,
84
- memo: memo,
85
- receivers: TridentAssistant::Utils::NFO_MTG[:members],
86
- threshold: TridentAssistant::Utils::NFO_MTG[:threshold]
87
- }
88
- )
89
- rescue MixinBot::InsufficientPoolError => e
90
- log UI.fmt("{{x}} #{e.inspect}")
91
- log "Retrying to pay..."
92
- sleep 0.5
93
- nil
94
- end
95
-
96
- next if payment.blank? || payment["errors"].present?
92
+ api.mixin_bot.create_multisig_transaction(
93
+ api.keystore[:pin],
94
+ {
95
+ asset_id: TridentAssistant::Utils::MINT_ASSET_ID,
96
+ trace_id: trace_id,
97
+ amount: TridentAssistant::Utils::MINT_AMOUNT,
98
+ memo: memo,
99
+ receivers: TridentAssistant::Utils::NFO_MTG[:members],
100
+ threshold: TridentAssistant::Utils::NFO_MTG[:threshold]
101
+ }
102
+ )
97
103
 
98
104
  log UI.fmt("{{v}} NFT mint payment paid: #{payment["data"]}")
99
105
  data["_mint"]["token_id"] = token_id
100
- break
106
+ log UI.fmt("{{v}} NFT successfully minted")
107
+ rescue MixinBot::InsufficientPoolError, MixinBot::HttpError => e
108
+ log UI.fmt("{{x}} #{e.inspect}")
109
+ log "Retrying to pay..."
110
+ sleep 1
111
+ retry
101
112
  end
102
113
 
103
- log UI.fmt("{{v}} NFT successfully minted")
114
+ data.dig("_mint", "token_id").present?
104
115
  ensure
105
116
  if File.file? raw
106
117
  File.write raw, data.to_json
@@ -33,14 +33,36 @@ module TridentAssistant
33
33
  log api.order id
34
34
  end
35
35
 
36
- desc "sell", "sell NFT at fixed price"
37
- def ask; end
36
+ desc "ask COLECTION TOKEN", "sell NFT at fixed price"
37
+ option :asset, type: :string, aliases: "a", required: true, desc: "Order asset ID"
38
+ option :price, type: :numeric, aliases: "p", required: true, desc: "Order price"
39
+ option :expiration, type: :string, aliases: "e", required: false, desc: "Order expiration"
40
+ option :keystore, type: :string, aliases: "k", required: true, desc: "keystore or keystore.json file of Mixin bot"
41
+ def ask(collection, token)
42
+ log api.ask_order collection, token, asset_id: options[:asset], price: options[:price],
43
+ expire_at: options[:expiration]
44
+ end
38
45
 
39
46
  desc "auction", "auction NFT"
40
- def auction; end
47
+ option :asset, type: :string, aliases: "a", required: true, desc: "Order asset ID"
48
+ option :price, type: :numeric, aliases: "p", required: true, desc: "Order price"
49
+ option :reserve_price, type: :numeric, aliases: "r", required: true, desc: "Order reserve price"
50
+ option :expiration, type: :string, aliases: "e", required: false, desc: "Order expiration"
51
+ option :keystore, type: :string, aliases: "k", required: true, desc: "keystore or keystore.json file of Mixin bot"
52
+ def auction(collection, token)
53
+ log api.auction_order collection, token, asset_id: options[:asset], price: options[:price],
54
+ reserve_price: options[:reserve_price], expire_at: options[:expiration]
55
+ end
41
56
 
42
- desc "bid", "bid NFT"
43
- def bid; end
57
+ desc "bid COLECTION TOKEN", "bid NFT"
58
+ option :asset, type: :string, aliases: "a", required: true, desc: "Order asset ID"
59
+ option :price, type: :numeric, aliases: "p", required: true, desc: "Order price"
60
+ option :expiration, type: :string, aliases: "e", required: false, desc: "Order expiration"
61
+ option :keystore, type: :string, aliases: "k", required: true, desc: "keystore or keystore.json file of Mixin bot"
62
+ def bid(collection, token)
63
+ log api.bid_order collection, token, asset_id: options[:asset], price: options[:price],
64
+ expire_at: options[:expiration]
65
+ end
44
66
 
45
67
  desc "fill ID", "fill order"
46
68
  option :keystore, type: :string, aliases: "k", required: true, desc: "keystore or keystore.json file of Mixin bot"
@@ -44,7 +44,7 @@ module TridentAssistant
44
44
  R: reserve_price && format("%.8f", reserve_price.to_f).gsub(/(0)+\z/, ""),
45
45
  RC: receiver_id && MixinBot::Utils::UUID.new(hex: receiver_id).packed,
46
46
  S: start_at && Time.parse(start_at).to_i,
47
- E: expire_at && Time.parse(start_at).to_i
47
+ E: expire_at && Time.parse(expire_at).to_i
48
48
  }.compact
49
49
 
50
50
  @encoded =
@@ -30,6 +30,14 @@ module TridentAssistant
30
30
  ].sort,
31
31
  threshold: 3
32
32
  }.freeze
33
+ # TRIDENT_MTG = {
34
+ # members: %w[
35
+ # 28d390c7-a31b-4c46-bec2-871c86aaec53
36
+ # 0508a116-1239-4e28-b150-85a8e3e6b400
37
+ # 7ed9292d-7c95-4333-aa48-a8c640064186
38
+ # ].sort,
39
+ # threshold: 2
40
+ # }.freeze
33
41
 
34
42
  class << self
35
43
  def hash_from_url(url)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TridentAssistant
4
- VERSION = "0.1.1"
4
+ VERSION = "0.1.4"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trident_assistant
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - an-lee
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-04-11 00:00:00.000000000 Z
11
+ date: 2022-05-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mixin_bot
@@ -36,7 +36,6 @@ files:
36
36
  - CHANGELOG.md
37
37
  - CODE_OF_CONDUCT.md
38
38
  - Gemfile
39
- - Gemfile.lock
40
39
  - LICENSE.txt
41
40
  - README.md
42
41
  - Rakefile
data/Gemfile.lock DELETED
@@ -1,106 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- trident_assistant (0.1.0)
5
- mixin_bot (~> 0.8)
6
-
7
- GEM
8
- remote: https://rubygems.org/
9
- specs:
10
- activesupport (7.0.2.3)
11
- concurrent-ruby (~> 1.0, >= 1.0.2)
12
- i18n (>= 1.6, < 2)
13
- minitest (>= 5.1)
14
- tzinfo (~> 2.0)
15
- addressable (2.8.0)
16
- public_suffix (>= 2.0.2, < 5.0)
17
- ast (2.4.2)
18
- awesome_print (1.9.2)
19
- bcrypt (3.1.17)
20
- cli-ui (1.5.1)
21
- concurrent-ruby (1.1.10)
22
- domain_name (0.5.20190701)
23
- unf (>= 0.0.5, < 1.0.0)
24
- eventmachine (1.2.7)
25
- faye-websocket (0.11.1)
26
- eventmachine (>= 0.12.0)
27
- websocket-driver (>= 0.5.1)
28
- ffi (1.15.5)
29
- ffi-compiler (1.0.1)
30
- ffi (>= 1.0.0)
31
- rake
32
- hamster (3.0.0)
33
- concurrent-ruby (~> 1.0)
34
- http (4.4.1)
35
- addressable (~> 2.3)
36
- http-cookie (~> 1.0)
37
- http-form_data (~> 2.2)
38
- http-parser (~> 1.2.0)
39
- http-cookie (1.0.4)
40
- domain_name (~> 0.5)
41
- http-form_data (2.3.0)
42
- http-parser (1.2.3)
43
- ffi-compiler (>= 1.0, < 2.0)
44
- i18n (1.10.0)
45
- concurrent-ruby (~> 1.0)
46
- jose (1.1.3)
47
- hamster
48
- minitest (5.15.0)
49
- mixin_bot (0.8.4)
50
- activesupport (>= 5)
51
- awesome_print (~> 1.8)
52
- bcrypt (~> 3.1)
53
- cli-ui (~> 1.3)
54
- faye-websocket (>= 0.11)
55
- http (~> 4.1)
56
- jose (~> 1.1)
57
- msgpack (~> 1.3)
58
- rbnacl (~> 7.1)
59
- sha3 (~> 1.0)
60
- thor (~> 1.0)
61
- msgpack (1.5.1)
62
- parallel (1.22.1)
63
- parser (3.1.1.0)
64
- ast (~> 2.4.1)
65
- public_suffix (4.0.6)
66
- rainbow (3.1.1)
67
- rake (13.0.6)
68
- rbnacl (7.1.1)
69
- ffi
70
- regexp_parser (2.2.1)
71
- rexml (3.2.5)
72
- rubocop (1.26.1)
73
- parallel (~> 1.10)
74
- parser (>= 3.1.0.0)
75
- rainbow (>= 2.2.2, < 4.0)
76
- regexp_parser (>= 1.8, < 3.0)
77
- rexml
78
- rubocop-ast (>= 1.16.0, < 2.0)
79
- ruby-progressbar (~> 1.7)
80
- unicode-display_width (>= 1.4.0, < 3.0)
81
- rubocop-ast (1.16.0)
82
- parser (>= 3.1.1.0)
83
- ruby-progressbar (1.11.0)
84
- sha3 (1.0.4)
85
- thor (1.2.1)
86
- tzinfo (2.0.4)
87
- concurrent-ruby (~> 1.0)
88
- unf (0.1.4)
89
- unf_ext
90
- unf_ext (0.0.8.1)
91
- unicode-display_width (2.1.0)
92
- websocket-driver (0.7.5)
93
- websocket-extensions (>= 0.1.0)
94
- websocket-extensions (0.1.5)
95
-
96
- PLATFORMS
97
- x86_64-linux
98
-
99
- DEPENDENCIES
100
- minitest (~> 5.0)
101
- rake (~> 13.0)
102
- rubocop (~> 1.21)
103
- trident_assistant!
104
-
105
- BUNDLED WITH
106
- 2.2.30