glueby 0.1.0 → 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/.ruby-gemset +1 -1
 - data/.ruby-version +1 -1
 - data/.travis.yml +3 -2
 - data/README.md +27 -17
 - data/glueby.gemspec +1 -1
 - data/lib/generators/glueby/{initializer_generator.rb → contract/initializer_generator.rb} +0 -0
 - data/lib/generators/glueby/contract/templates/initializer.rb.erb +3 -0
 - data/lib/generators/glueby/contract/templates/key_table.rb.erb +15 -0
 - data/lib/generators/glueby/{templates → contract/templates}/timestamp_table.rb.erb +2 -1
 - data/lib/generators/glueby/contract/templates/utxo_table.rb.erb +15 -0
 - data/lib/generators/glueby/contract/templates/wallet_table.rb.erb +10 -0
 - data/lib/generators/glueby/contract/timestamp_generator.rb +26 -0
 - data/lib/generators/glueby/contract/wallet_adapter_generator.rb +46 -0
 - data/lib/glueby.rb +18 -1
 - data/lib/glueby/contract.rb +3 -14
 - data/lib/glueby/contract/active_record/timestamp.rb +8 -5
 - data/lib/glueby/contract/errors.rb +6 -0
 - data/lib/glueby/contract/payment.rb +54 -0
 - data/lib/glueby/contract/timestamp.rb +39 -38
 - data/lib/glueby/contract/token.rb +193 -0
 - data/lib/glueby/contract/tx_builder.rb +197 -31
 - data/lib/glueby/generator.rb +5 -0
 - data/lib/glueby/generator/migrate_generator.rb +38 -0
 - data/lib/glueby/internal.rb +6 -0
 - data/lib/glueby/internal/rpc.rb +35 -0
 - data/lib/glueby/internal/wallet.rb +122 -0
 - data/lib/glueby/internal/wallet/abstract_wallet_adapter.rb +131 -0
 - data/lib/glueby/internal/wallet/active_record.rb +15 -0
 - data/lib/glueby/internal/wallet/active_record/key.rb +72 -0
 - data/lib/glueby/internal/wallet/active_record/utxo.rb +50 -0
 - data/lib/glueby/internal/wallet/active_record/wallet.rb +54 -0
 - data/lib/glueby/internal/wallet/active_record_wallet_adapter.rb +133 -0
 - data/lib/glueby/internal/wallet/errors.rb +11 -0
 - data/lib/glueby/internal/wallet/tapyrus_core_wallet_adapter.rb +158 -0
 - data/lib/glueby/version.rb +1 -1
 - data/lib/glueby/wallet.rb +51 -0
 - data/lib/tasks/glueby/contract/timestamp.rake +5 -5
 - data/lib/tasks/glueby/contract/wallet_adapter.rake +42 -0
 - metadata +30 -10
 - data/lib/generators/glueby/templates/initializer.rb.erb +0 -4
 - data/lib/generators/glueby/timestamp_generator.rb +0 -57
 - 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 
     | 
    
         
            -
                   
     | 
| 
       5 
     | 
    
         
            -
             
     | 
| 
       6 
     | 
    
         
            -
                   
     | 
| 
       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 
     | 
    
         
            -
             
     | 
| 
      
 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 
     | 
    
         
            -
             
     | 
| 
      
 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[ 
     | 
| 
      
 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 
     | 
    
         
            -
             
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
       32 
     | 
    
         
            -
             
     | 
| 
       33 
     | 
    
         
            -
             
     | 
| 
       34 
     | 
    
         
            -
             
     | 
| 
       35 
     | 
    
         
            -
             
     | 
| 
       36 
     | 
    
         
            -
                   
     | 
| 
       37 
     | 
    
         
            -
             
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
     | 
    
         
            -
                     
     | 
| 
       40 
     | 
    
         
            -
             
     | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
      
 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 
     | 
    
         
            -
                     
     | 
| 
      
 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,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
         
     |