glueby 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-gemset +1 -1
  3. data/.ruby-version +1 -1
  4. data/.travis.yml +3 -2
  5. data/README.md +27 -17
  6. data/glueby.gemspec +1 -1
  7. data/lib/generators/glueby/{initializer_generator.rb → contract/initializer_generator.rb} +0 -0
  8. data/lib/generators/glueby/contract/templates/initializer.rb.erb +3 -0
  9. data/lib/generators/glueby/contract/templates/key_table.rb.erb +15 -0
  10. data/lib/generators/glueby/{templates → contract/templates}/timestamp_table.rb.erb +2 -1
  11. data/lib/generators/glueby/contract/templates/utxo_table.rb.erb +15 -0
  12. data/lib/generators/glueby/contract/templates/wallet_table.rb.erb +10 -0
  13. data/lib/generators/glueby/contract/timestamp_generator.rb +26 -0
  14. data/lib/generators/glueby/contract/wallet_adapter_generator.rb +46 -0
  15. data/lib/glueby.rb +18 -1
  16. data/lib/glueby/contract.rb +3 -14
  17. data/lib/glueby/contract/active_record/timestamp.rb +8 -5
  18. data/lib/glueby/contract/errors.rb +6 -0
  19. data/lib/glueby/contract/payment.rb +54 -0
  20. data/lib/glueby/contract/timestamp.rb +39 -38
  21. data/lib/glueby/contract/token.rb +193 -0
  22. data/lib/glueby/contract/tx_builder.rb +197 -31
  23. data/lib/glueby/generator.rb +5 -0
  24. data/lib/glueby/generator/migrate_generator.rb +38 -0
  25. data/lib/glueby/internal.rb +6 -0
  26. data/lib/glueby/internal/rpc.rb +35 -0
  27. data/lib/glueby/internal/wallet.rb +122 -0
  28. data/lib/glueby/internal/wallet/abstract_wallet_adapter.rb +131 -0
  29. data/lib/glueby/internal/wallet/active_record.rb +15 -0
  30. data/lib/glueby/internal/wallet/active_record/key.rb +72 -0
  31. data/lib/glueby/internal/wallet/active_record/utxo.rb +50 -0
  32. data/lib/glueby/internal/wallet/active_record/wallet.rb +54 -0
  33. data/lib/glueby/internal/wallet/active_record_wallet_adapter.rb +133 -0
  34. data/lib/glueby/internal/wallet/errors.rb +11 -0
  35. data/lib/glueby/internal/wallet/tapyrus_core_wallet_adapter.rb +158 -0
  36. data/lib/glueby/version.rb +1 -1
  37. data/lib/glueby/wallet.rb +51 -0
  38. data/lib/tasks/glueby/contract/timestamp.rake +5 -5
  39. data/lib/tasks/glueby/contract/wallet_adapter.rake +42 -0
  40. metadata +30 -10
  41. data/lib/generators/glueby/templates/initializer.rb.erb +0 -4
  42. data/lib/generators/glueby/timestamp_generator.rb +0 -57
  43. data/lib/glueby/contract/rpc.rb +0 -15
@@ -0,0 +1,193 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Glueby
4
+ module Contract
5
+ # This class represents custom token issued by application user.
6
+ # Application users can
7
+ # - issue their own tokens.
8
+ # - send to other users.
9
+ # - make the tokens disable.
10
+ #
11
+ # Examples:
12
+ #
13
+ # alice = Glueby::Wallet.create
14
+ # bob = Glueby::Wallet.create
15
+ #
16
+ # Issue
17
+ # token = Token.issue!(issuer: alice, amount: 100)
18
+ # token.amount(wallet: alice)
19
+ # => 100
20
+ #
21
+ # Send
22
+ # token.transfer!(sender: alice, receiver: bob, amount: 1)
23
+ # token.amount(wallet: alice)
24
+ # => 99
25
+ # token.amount(wallet: bob)
26
+ # => 1
27
+ #
28
+ # Burn
29
+ # token.burn!(sender: alice, amount: 10)
30
+ # token.amount(wallet: alice)
31
+ # => 89
32
+ # token.burn!(sender: alice)
33
+ # token.amount(wallet: alice)
34
+ # => 0
35
+ #
36
+ # Reissue
37
+ # token.reissue!(issuer: alice, amount: 100)
38
+ # token.amount(wallet: alice)
39
+ # => 100
40
+ #
41
+ class Token
42
+ include Glueby::Contract::TxBuilder
43
+ extend Glueby::Contract::TxBuilder
44
+
45
+ class << self
46
+ # Issue new token with specified amount and token type.
47
+ # REISSUABLE token can be reissued with #reissue! method, and
48
+ # NON_REISSUABLE and NFT token can not.
49
+ # Amount is set to 1 when the token type is NFT
50
+ #
51
+ # @param issuer [Glueby::Wallet]
52
+ # @param token_type [TokenTypes]
53
+ # @param amount [Integer]
54
+ # @return [Token] token
55
+ # @raise [InsufficientFunds] if wallet does not have enough TPC to send transaction.
56
+ # @raise [InvalidAmount] if amount is not positive integer.
57
+ # @raise [UnspportedTokenType] if token is not supported.
58
+ def issue!(issuer:, token_type: Tapyrus::Color::TokenTypes::REISSUABLE, amount: 1)
59
+ raise Glueby::Contract::Errors::InvalidAmount unless amount.positive?
60
+
61
+ txs, color_id, script_pubkey = case token_type
62
+ when Tapyrus::Color::TokenTypes::REISSUABLE
63
+ issue_reissuable_token(issuer: issuer, amount: amount)
64
+ when Tapyrus::Color::TokenTypes::NON_REISSUABLE
65
+ issue_non_reissuable_token(issuer: issuer, amount: amount)
66
+ when Tapyrus::Color::TokenTypes::NFT
67
+ issue_nft_token(issuer: issuer)
68
+ else
69
+ raise Glueby::Contract::Errors::UnsupportedTokenType
70
+ end
71
+ txs.each { |tx| issuer.internal_wallet.broadcast(tx) }
72
+ new(color_id: color_id, script_pubkey: script_pubkey)
73
+ end
74
+
75
+ private
76
+
77
+ def issue_reissuable_token(issuer:, amount:)
78
+ estimated_fee = FixedFeeProvider.new.fee(Tapyrus::Tx.new)
79
+ funding_tx = create_funding_tx(wallet: issuer, amount: estimated_fee)
80
+ tx = create_issue_tx_for_reissuable_token(funding_tx: funding_tx, issuer: issuer, amount: amount)
81
+ script_pubkey = funding_tx.outputs.first.script_pubkey
82
+ color_id = Tapyrus::Color::ColorIdentifier.reissuable(script_pubkey)
83
+ [[funding_tx, tx], color_id, script_pubkey]
84
+ end
85
+
86
+ def issue_non_reissuable_token(issuer:, amount:)
87
+ tx = create_issue_tx_for_non_reissuable_token(issuer: issuer, amount: amount)
88
+ out_point = tx.inputs.first.out_point
89
+ color_id = Tapyrus::Color::ColorIdentifier.non_reissuable(out_point)
90
+ [[tx], color_id, nil]
91
+ end
92
+
93
+ def issue_nft_token(issuer:)
94
+ tx = create_issue_tx_for_nft_token(issuer: issuer)
95
+ out_point = tx.inputs.first.out_point
96
+ color_id = Tapyrus::Color::ColorIdentifier.nft(out_point)
97
+ [[tx], color_id, nil]
98
+ end
99
+ end
100
+
101
+ attr_reader :color_id
102
+
103
+ # Re-issue the token with specified amount.
104
+ # A wallet can issue the token only when it is REISSUABLE token.
105
+ # @param issuer [Glueby::Wallet]
106
+ # @param amount [Integer]
107
+ # @raise [InsufficientFunds] if wallet does not have enough TPC to send transaction.
108
+ # @raise [InvalidAmount] if amount is not positive integer.
109
+ # @raise [InvalidTokenType] if token is not reissuable.
110
+ # @raise [UnknownScriptPubkey] when token is reissuable but it doesn't know script pubkey to issue token.
111
+ def reissue!(issuer:, amount:)
112
+ raise Glueby::Contract::Errors::InvalidAmount unless amount.positive?
113
+ raise Glueby::Contract::Errors::InvalidTokenType unless token_type == Tapyrus::Color::TokenTypes::REISSUABLE
114
+ raise Glueby::Contract::Errors::UnknownScriptPubkey unless @script_pubkey
115
+
116
+ estimated_fee = FixedFeeProvider.new.fee(Tapyrus::Tx.new)
117
+ funding_tx = create_funding_tx(wallet: issuer, amount: estimated_fee, script: @script_pubkey)
118
+ tx = create_reissue_tx(funding_tx: funding_tx, issuer: issuer, amount: amount, color_id: color_id)
119
+ [funding_tx, tx].each { |tx| issuer.internal_wallet.broadcast(tx) }
120
+ end
121
+
122
+ # Send the token to other wallet
123
+ #
124
+ # @param sender [Glueby::Wallet] wallet to send this token
125
+ # @param receiver [Glueby::Wallet] wallet to receive this token
126
+ # @param amount [Integer]
127
+ # @return [Token] receiver token
128
+ # @raise [InsufficientFunds] if wallet does not have enough TPC to send transaction.
129
+ # @raise [InsufficientTokens] if wallet does not have enough token to send.
130
+ # @raise [InvalidAmount] if amount is not positive integer.
131
+ def transfer!(sender:, receiver:, amount: 1)
132
+ raise Glueby::Contract::Errors::InvalidAmount unless amount.positive?
133
+
134
+ tx = create_transfer_tx(color_id: color_id, sender: sender, receiver: receiver, amount: amount)
135
+ sender.internal_wallet.broadcast(tx)
136
+ end
137
+
138
+ # Burn token
139
+ # If amount is not specified or 0, burn all token associated with the wallet.
140
+ #
141
+ # @param sender [Glueby::Wallet] wallet to send this token
142
+ # @param amount [Integer]
143
+ # @raise [InsufficientFunds] if wallet does not have enough TPC to send transaction.
144
+ # @raise [InsufficientTokens] if wallet does not have enough token to send transaction.
145
+ # @raise [InvalidAmount] if amount is not positive integer.
146
+ def burn!(sender:, amount: 0)
147
+ raise Glueby::Contract::Errors::InvalidAmount unless amount.positive?
148
+
149
+ tx = create_burn_tx(color_id: color_id, sender: sender, amount: amount)
150
+ sender.internal_wallet.broadcast(tx)
151
+ end
152
+
153
+ # Return balance of token in the specified wallet.
154
+ # @param wallet [Glueby::Wallet]
155
+ # @return [Integer] amount of utxo value associated with this token.
156
+ def amount(wallet:)
157
+ # collect utxo associated with this address
158
+ utxos = wallet.internal_wallet.list_unspent
159
+ _, results = collect_colored_outputs(utxos, color_id)
160
+ results.sum { |result| result[:amount] }
161
+ end
162
+
163
+ # Return token type
164
+ # @return [Tapyrus::Color::TokenTypes]
165
+ def token_type
166
+ color_id.type
167
+ end
168
+
169
+ # Return serialized payload
170
+ # @return [String] payload
171
+ def to_payload
172
+ payload = +''
173
+ payload << @color_id.to_payload
174
+ payload << @script_pubkey.to_payload if @script_pubkey
175
+ end
176
+
177
+ # Restore token from payload
178
+ # @param payload [String]
179
+ # @return [Glueby::Contract::Token]
180
+ def self.parse_from_payload(payload)
181
+ color_id, script_pubkey = payload.unpack('a33a*')
182
+ color_id = Tapyrus::Color::ColorIdentifier.parse_from_payload(color_id)
183
+ script_pubkey = Tapyrus::Script.parse_from_payload(script_pubkey) if script_pubkey
184
+ new(color_id: color_id, script_pubkey: script_pubkey)
185
+ end
186
+
187
+ def initialize(color_id:, script_pubkey:nil)
188
+ @color_id = color_id
189
+ @script_pubkey = script_pubkey
190
+ end
191
+ end
192
+ end
193
+ end
@@ -1,46 +1,212 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Glueby
2
4
  module Contract
3
5
  module TxBuilder
4
- # collect outputs in results so that sum of them exceeds up to the specified amount.
5
- # @param [Array] results of listunspent
6
- # @param [Numeric] amount
7
- # @return [(Numeric, Array)] sum value of outputs and outputs
8
- # @raise [InsufficientFunds] if result of listunspent is not enough to pay the specified amount
9
- def collect_outputs(results, amount)
10
- results.inject([0, []]) do |sum, output|
11
- new_sum = sum[0] + (output['amount'] * 100_000_000)
12
- new_outputs = sum[1] << output
13
- return [new_sum, new_outputs] if new_sum >= amount
6
+ def receive_address(wallet:)
7
+ wallet.receive_address
8
+ end
14
9
 
15
- [new_sum, new_outputs]
10
+ # Create new public key, and new transaction that sends TPC to it
11
+ def create_funding_tx(wallet:, amount:, script: nil, fee_provider: FixedFeeProvider.new)
12
+ tx = Tapyrus::Tx.new
13
+ fee = fee_provider.fee(dummy_tx(tx))
14
+
15
+ sum, outputs = wallet.internal_wallet.collect_uncolored_outputs(fee + amount)
16
+ fill_input(tx, outputs)
17
+
18
+ receiver_script = script ? script : Tapyrus::Script.parse_from_addr(wallet.internal_wallet.receive_address)
19
+ tx.outputs << Tapyrus::TxOut.new(value: amount, script_pubkey: receiver_script)
20
+
21
+ fill_change_tpc(tx, wallet, sum - fee - amount)
22
+ wallet.internal_wallet.sign_tx(tx)
23
+ end
24
+
25
+ def create_issue_tx_for_reissuable_token(funding_tx:, issuer:, amount:, fee_provider: FixedFeeProvider.new)
26
+ tx = Tapyrus::Tx.new
27
+
28
+ out_point = Tapyrus::OutPoint.from_txid(funding_tx.txid, 0)
29
+ tx.inputs << Tapyrus::TxIn.new(out_point: out_point)
30
+ output = funding_tx.outputs.first
31
+
32
+ receiver_script = Tapyrus::Script.parse_from_payload(output.script_pubkey.to_payload)
33
+ color_id = Tapyrus::Color::ColorIdentifier.reissuable(receiver_script)
34
+ receiver_colored_script = receiver_script.add_color(color_id)
35
+ tx.outputs << Tapyrus::TxOut.new(value: amount, script_pubkey: receiver_colored_script)
36
+
37
+ fee = fee_provider.fee(dummy_tx(tx))
38
+ fill_change_tpc(tx, issuer, output.value - fee)
39
+ prev_txs = [{
40
+ txid: funding_tx.txid,
41
+ vout: 0,
42
+ scriptPubKey: output.script_pubkey.to_hex,
43
+ amount: output.value
44
+ }]
45
+ issuer.internal_wallet.sign_tx(tx, prev_txs)
46
+ end
47
+
48
+ def create_issue_tx_for_non_reissuable_token(issuer:, amount:, fee_provider: FixedFeeProvider.new)
49
+ create_issue_tx_from_out_point(token_type: Tapyrus::Color::TokenTypes::NON_REISSUABLE, issuer: issuer, amount: amount, fee_provider: fee_provider)
50
+ end
51
+
52
+ def create_issue_tx_for_nft_token(issuer:, fee_provider: FixedFeeProvider.new)
53
+ create_issue_tx_from_out_point(token_type: Tapyrus::Color::TokenTypes::NFT, issuer: issuer, amount: 1, fee_provider: fee_provider)
54
+ end
55
+
56
+ def create_issue_tx_from_out_point(token_type:, issuer:, amount:, fee_provider: FixedFeeProvider.new)
57
+ tx = Tapyrus::Tx.new
58
+
59
+ fee = fee_provider.fee(dummy_issue_tx_from_out_point)
60
+ sum, outputs = issuer.internal_wallet.collect_uncolored_outputs(fee)
61
+ fill_input(tx, outputs)
62
+
63
+ out_point = tx.inputs.first.out_point
64
+ color_id = case token_type
65
+ when Tapyrus::Color::TokenTypes::NON_REISSUABLE
66
+ Tapyrus::Color::ColorIdentifier.non_reissuable(out_point)
67
+ when Tapyrus::Color::TokenTypes::NFT
68
+ Tapyrus::Color::ColorIdentifier.nft(out_point)
69
+ else
70
+ raise Glueby::Contract::Errors::UnsupportedTokenType
16
71
  end
17
- raise Glueby::Contract::Errors::InsufficientFunds
72
+
73
+ receiver_script = Tapyrus::Script.parse_from_addr(issuer.internal_wallet.receive_address)
74
+ receiver_colored_script = receiver_script.add_color(color_id)
75
+ tx.outputs << Tapyrus::TxOut.new(value: amount, script_pubkey: receiver_colored_script)
76
+
77
+ fill_change_tpc(tx, issuer, sum - fee)
78
+ issuer.internal_wallet.sign_tx(tx)
79
+ end
80
+
81
+ def create_reissue_tx(funding_tx:, issuer:, amount:, color_id:, fee_provider: FixedFeeProvider.new)
82
+ tx = Tapyrus::Tx.new
83
+
84
+ out_point = Tapyrus::OutPoint.from_txid(funding_tx.txid, 0)
85
+ tx.inputs << Tapyrus::TxIn.new(out_point: out_point)
86
+ output = funding_tx.outputs.first
87
+
88
+ receiver_script = Tapyrus::Script.parse_from_payload(output.script_pubkey.to_payload)
89
+ receiver_colored_script = receiver_script.add_color(color_id)
90
+ tx.outputs << Tapyrus::TxOut.new(value: amount, script_pubkey: receiver_colored_script)
91
+
92
+ fee = fee_provider.fee(dummy_tx(tx))
93
+ fill_change_tpc(tx, issuer, output.value - fee)
94
+ prev_txs = [{
95
+ txid: funding_tx.txid,
96
+ vout: 0,
97
+ scriptPubKey: output.script_pubkey.to_hex,
98
+ amount: output.value
99
+ }]
100
+ issuer.internal_wallet.sign_tx(tx, prev_txs)
101
+ end
102
+
103
+ def create_transfer_tx(color_id:, sender:, receiver:, amount:, fee_provider: FixedFeeProvider.new)
104
+ tx = Tapyrus::Tx.new
105
+
106
+ utxos = sender.internal_wallet.list_unspent
107
+ sum_token, outputs = collect_colored_outputs(utxos, color_id, amount)
108
+ fill_input(tx, outputs)
109
+
110
+ receiver_script = Tapyrus::Script.parse_from_addr(receiver.internal_wallet.receive_address)
111
+ receiver_colored_script = receiver_script.add_color(color_id)
112
+ tx.outputs << Tapyrus::TxOut.new(value: amount, script_pubkey: receiver_colored_script)
113
+
114
+ fill_change_token(tx, sender, sum_token - amount, color_id)
115
+
116
+ fee = fee_provider.fee(dummy_tx(tx))
117
+ sum_tpc, outputs = sender.internal_wallet.collect_uncolored_outputs(fee)
118
+ fill_input(tx, outputs)
119
+
120
+ fill_change_tpc(tx, sender, sum_tpc - fee)
121
+ sender.internal_wallet.sign_tx(tx)
122
+ end
123
+
124
+ def create_burn_tx(color_id:, sender:, amount: 0, fee_provider: FixedFeeProvider.new)
125
+ tx = Tapyrus::Tx.new
126
+
127
+ utxos = sender.internal_wallet.list_unspent
128
+ sum_token, outputs = collect_colored_outputs(utxos, color_id, amount)
129
+ fill_input(tx, outputs)
130
+
131
+ fill_change_token(tx, sender, sum_token - amount, color_id) if amount.positive?
132
+
133
+ fee = fee_provider.fee(dummy_tx(tx))
134
+
135
+ dust = 600 # in case that the wallet has output which has just fee amount.
136
+ sum_tpc, outputs = sender.internal_wallet.collect_uncolored_outputs(fee + dust)
137
+ fill_input(tx, outputs)
138
+
139
+ fill_change_tpc(tx, sender, sum_tpc - fee)
140
+ sender.internal_wallet.sign_tx(tx)
18
141
  end
19
142
 
20
- # Add inputs to tx
21
- # @param [Tapyrus::Tx] tx
22
- # @param [Array] outputs provided as result of listunspent and extracted by #collect_outputs methods
23
- # @return [Tapyrus::Tx] tx which has enough amount in inputs.
24
143
  def fill_input(tx, outputs)
25
144
  outputs.each do |output|
26
- out_point = Tapyrus::OutPoint.new(output['txid'].rhex, output['vout'])
145
+ out_point = Tapyrus::OutPoint.new(output[:txid].rhex, output[:vout])
27
146
  tx.inputs << Tapyrus::TxIn.new(out_point: out_point)
28
147
  end
29
- tx
30
- end
31
-
32
- # Add output to tx, so that allow tx to return the change of the transaction.
33
- # @param [Tapyrus::Tx] tx
34
- # @param [Numeric] fee
35
- # @param [Tapyrus::Script] script for change
36
- # @param [Numeric] sum value of inputs
37
- def fill_change_output(tx, fee, change_script, sum)
38
- amount = fee + tx.outputs.map(&:value).sum
39
- if amount.positive?
40
- change = sum - amount
41
- tx.outputs << Tapyrus::TxOut.new(value: change, script_pubkey: change_script)
148
+ end
149
+
150
+ def fill_change_tpc(tx, wallet, change)
151
+ return unless change.positive?
152
+
153
+ change_script = Tapyrus::Script.parse_from_addr(wallet.internal_wallet.change_address)
154
+ tx.outputs << Tapyrus::TxOut.new(value: change, script_pubkey: change_script)
155
+ end
156
+
157
+ def fill_change_token(tx, wallet, change, color_id)
158
+ return unless change.positive?
159
+
160
+ change_script = Tapyrus::Script.parse_from_addr(wallet.internal_wallet.change_address)
161
+ change_colored_script = change_script.add_color(color_id)
162
+ tx.outputs << Tapyrus::TxOut.new(value: change, script_pubkey: change_colored_script)
163
+ end
164
+
165
+ # Returns the set of utxos that satisfies the specified amount and has the specified color_id.
166
+ # if amount is not specified or 0, return all utxos with color_id
167
+ # @param results [Array] response of Glueby::Internal::Wallet#list_unspent
168
+ # @param color_id [Tapyrus::Color::ColorIdentifier] color identifier
169
+ # @param amount [Integer]
170
+ def collect_colored_outputs(results, color_id, amount = 0)
171
+ results = results.inject([0, []]) do |sum, output|
172
+ next sum unless output[:color_id] == color_id.to_hex
173
+
174
+ new_sum = sum[0] + output[:amount]
175
+ new_outputs = sum[1] << output
176
+ return [new_sum, new_outputs] if new_sum >= amount && amount.positive?
177
+
178
+ [new_sum, new_outputs]
42
179
  end
43
- tx
180
+ raise Glueby::Contract::Errors::InsufficientTokens if amount.positive?
181
+
182
+ results
183
+ end
184
+
185
+ # Add dummy inputs and outputs to tx
186
+ def dummy_tx(tx)
187
+ dummy = Tapyrus::Tx.parse_from_payload(tx.to_payload)
188
+
189
+ # dummy input for tpc
190
+ out_point = Tapyrus::OutPoint.new('00' * 32, 0)
191
+ dummy.inputs << Tapyrus::TxIn.new(out_point: out_point)
192
+
193
+ # Add script_sig to all intpus
194
+ dummy.inputs.each do |input|
195
+ input.script_sig = Tapyrus::Script.parse_from_payload('000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'.htb)
196
+ end
197
+
198
+ # dummy output to return change
199
+ change_script = Tapyrus::Script.to_p2pkh('0000000000000000000000000000000000000000')
200
+ dummy.outputs << Tapyrus::TxOut.new(value: 0, script_pubkey: change_script)
201
+ dummy
202
+ end
203
+
204
+ # Add dummy inputs and outputs to tx for issue non-reissuable transaction and nft transaction
205
+ def dummy_issue_tx_from_out_point
206
+ tx = Tapyrus::Tx.new
207
+ receiver_colored_script = Tapyrus::Script.parse_from_payload('21c20000000000000000000000000000000000000000000000000000000000000000bc76a914000000000000000000000000000000000000000088ac'.htb)
208
+ tx.outputs << Tapyrus::TxOut.new(value: 0, script_pubkey: receiver_colored_script)
209
+ dummy_tx(tx)
44
210
  end
45
211
  end
46
212
  end
@@ -0,0 +1,5 @@
1
+ module Glueby
2
+ module Generator
3
+ autoload :MigrateGenerator, 'glueby/generator/migrate_generator'
4
+ end
5
+ end
@@ -0,0 +1,38 @@
1
+ module Glueby
2
+ module Generator
3
+ module MigrateGenerator
4
+ module ClassMethod
5
+ def next_migration_number(dirname)
6
+ # ::ActiveRecord::Migration.next_migration_number(number)
7
+ # ::ActiveRecord::Generators::Base.next_migration_number(dirname)
8
+ next_migration_number = current_migration_number(dirname) + 1
9
+ ::ActiveRecord::Migration.next_migration_number(next_migration_number)
10
+ end
11
+ end
12
+
13
+ MYSQL_ADAPTERS = [
14
+ "ActiveRecord::ConnectionAdapters::MysqlAdapter",
15
+ "ActiveRecord::ConnectionAdapters::Mysql2Adapter"
16
+ ].freeze
17
+
18
+ def migration_version
19
+ major = ::Rails::VERSION::MAJOR
20
+ if major >= 5
21
+ "[#{major}.#{::Rails::VERSION::MINOR}]"
22
+ end
23
+ end
24
+
25
+ def mysql?
26
+ MYSQL_ADAPTERS.include?(::ActiveRecord::Base.connection.class.name)
27
+ end
28
+
29
+ def table_options
30
+ if mysql?
31
+ ', { options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci" }'
32
+ else
33
+ ""
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end