text: import unittest
  import base64
  
  from mintersdk.sdk.transactions import (
      MinterTx, MinterDelegateTx, MinterSendCoinTx, MinterBuyCoinTx,
      MinterCreateCoinTx, MinterDeclareCandidacyTx, MinterEditCandidateTx,
      MinterRedeemCheckTx, MinterSellAllCoinTx, MinterSellCoinTx,
      MinterSetCandidateOffTx, MinterSetCandidateOnTx, MinterUnbondTx,
      MinterMultiSendCoinTx
  )
  
  
  class TestMinterTx(unittest.TestCase):
  
      def setUp(self):
          self.SIGNED_TX = 'f8900102018a4d4e540000000000000007b6f5a00eb98ea04ae466d8d38f490db3c99b3996a90e24243952ce9822c6dc1e2c1a438a4d4e5400000000000000888ac7230489e80000808001b845f8431ba01c2c8f702d80cf64da1e9bf1f07a52e2fee8721aebe419aa9f62260a98983f89a07ed297d71d9dc37a57ffe9bb16915dccc703d8c09f30da8aadb9d5dbab8c7da9'
          self.PUBLIC_KEY = 'Mp0eb98ea04ae466d8d38f490db3c99b3996a90e24243952ce9822c6dc1e2c1a43'
          self.TX_FROM = 'Mx9f7fd953c2c69044b901426831ed03ee0bd0597a'
          self.TX_TYPE = 7
          self.TX_STAKE = 10
          self.TX_PAYLOAD = '🔳'  # 4 bytes
          self.tx = MinterTx.from_raw(self.SIGNED_TX)
  
      def test_instance(self):
          self.assertIsInstance(self.tx, MinterDelegateTx)
  
      def test_public_key(self):
          self.assertEqual(self.tx.pub_key, self.PUBLIC_KEY)
  
      def test_from_mx(self):
          self.assertEqual(self.tx.from_mx, self.TX_FROM)
  
      def test_type(self):
          self.assertEqual(self.tx.type, self.TX_TYPE)
  
      def test_stake(self):
          self.assertEqual(self.tx.stake, self.TX_STAKE)
  
  
  class TestMinterBuyCoinTx(unittest.TestCase):
  
      def setUp(self):
          self.FROM = 'Mx31e61a05adbd13c6b625262704bc305bf7725026'
          self.PRIVATE_KEY = '07bc17abdcee8b971bb8723e36fe9d2523306d5ab2d683631693238e0f9df142'
          self.SIGNED_TX = 'f8830102018a4d4e540000000000000004a9e88a54455354000000000000880de0b6b3a76400008a4d4e5400000000000000880de0b6b3a7640000808001b845f8431ca04ee095a20ca58062a5758e2a6d3941857daa8943b5873c57f111190ca88dbc56a01148bf2fcc721ca353105e4f4a3419bec471d7ae08173f443a28c3ae6d27018a'
          self.TX = MinterBuyCoinTx(**{
              'nonce': 1,
              'chain_id': MinterTx.TESTNET_CHAIN_ID,
              'gas_coin': 'MNT',
              'coin_to_buy': 'TEST',
              'value_to_buy': 1,
              'coin_to_sell': 'MNT',
              'max_value_to_sell': 1
          })
  
      def test_valid_tx(self):
          """
          Is tx instance of needed TX class.
          """
  
          self.assertIsInstance(self.TX, MinterBuyCoinTx)
  
      def test_sign_tx(self):
          """
          Sign transaction and check signed transaction
          """
          self.TX.sign(self.PRIVATE_KEY)
  
          self.assertEqual(self.TX.signed_tx, self.SIGNED_TX)
  
      def test_sign_with_signature(self):
          self.TX.signature_type = MinterTx.SIGNATURE_SINGLE_TYPE
          signature = self.TX.generate_signature(self.PRIVATE_KEY)
          self.TX.sign(signature=signature)
  
          self.assertEqual(self.TX.signed_tx, self.SIGNED_TX)
  
      def test_from_raw(self):
          tx = MinterTx.from_raw(raw_tx=self.SIGNED_TX)
  
          self.assertEqual(tx.from_mx, self.FROM)
          self.assertEqual(tx.coin_to_buy, self.TX.coin_to_buy)
          self.assertEqual(tx.value_to_buy, self.TX.value_to_buy)
          self.assertEqual(tx.coin_to_sell, self.TX.coin_to_sell)
          self.assertEqual(tx.max_value_to_sell, self.TX.max_value_to_sell)
  
  
  class TestMinterCreateCoinTx(unittest.TestCase):
  
      def setUp(self):
          self.FROM = 'Mx31e61a05adbd13c6b625262704bc305bf7725026'
          self.PRIVATE_KEY = '07bc17abdcee8b971bb8723e36fe9d2523306d5ab2d683631693238e0f9df142'
          self.SIGNED_TX = 'f88f0102018a4d4e540000000000000005b5f48a535550455220544553548a5350525445535400000089056bc75e2d63100000888ac7230489e800000a893635c9adc5dea00000808001b845f8431ca0ccfabd9283d27cf7978bca378e0cc7dc69a39ff3bdc56707fa2d552655f9290da0226057221cbaef35696c9315cd29e783d3c66d842d0a3948a922abb42ca0dabe'
          self.TX = MinterCreateCoinTx(**{
              'nonce': 1,
              'chain_id': MinterTx.TESTNET_CHAIN_ID,
              'gas_coin': 'MNT',
              'name': 'SUPER TEST',
              'symbol': 'SPRTEST',
              'initial_amount': 100,
              'initial_reserve': 10,
              'crr': 10,
              'max_supply': 1000
          })
  
      def test_valid_tx(self):
          """
          Is tx instance of needed TX class.
          """
  
          self.assertIsInstance(self.TX, MinterCreateCoinTx)
  
      def test_sign_tx(self):
          """
          Sign transaction and check signed transaction
          """
          self.TX.sign(self.PRIVATE_KEY)
  
          self.assertEqual(self.TX.signed_tx, self.SIGNED_TX)
  
      def test_sign_with_signature(self):
          self.TX.signature_type = MinterTx.SIGNATURE_SINGLE_TYPE
          signature = self.TX.generate_signature(self.PRIVATE_KEY)
          self.TX.sign(signature=signature)
  
          self.assertEqual(self.TX.signed_tx, self.SIGNED_TX)
  
      def test_from_raw(self):
          tx = MinterTx.from_raw(raw_tx=self.SIGNED_TX)
  
          self.assertEqual(tx.from_mx, self.FROM)
          self.assertEqual(tx.name, self.TX.name)
          self.assertEqual(tx.symbol, self.TX.symbol)
          self.assertEqual(tx.initial_amount, self.TX.initial_amount)
          self.assertEqual(tx.initial_reserve, self.TX.initial_reserve)
          self.assertEqual(tx.crr, self.TX.crr)
          self.assertEqual(tx.max_supply, self.TX.max_supply)
  
  
  class TestMinterDeclareCandidacyTx(unittest.TestCase):
  
      def setUp(self):
          self.PRIVATE_KEY = '6e1df6ec69638d152f563c5eca6c13cdb5db4055861efc11ec1cdd578afd96bf'
          self.SIGNED_TX = 'f8a80102018a4d4e540000000000000006b84df84b949f7fd953c2c69044b901426831ed03ee0bd0597aa00eb98ea04ae466d8d38f490db3c99b3996a90e24243952ce9822c6dc1e2c1a430a8a4d4e5400000000000000884563918244f40000808001b845f8431ca0c379230cbe09103b31983402c9138ad29d839bcecee70e11ac9bf5cfe70850d9a06c92bfb9a627bfaefc3ad46fc60ff1fdc42efe0e8805d57f20795a403c91e8bd'
          self.TX = MinterDeclareCandidacyTx(**{
              'nonce': 1,
              'chain_id': MinterTx.TESTNET_CHAIN_ID,
              'gas_coin': 'MNT',
              'address': 'Mx9f7fd953c2c69044b901426831ed03ee0bd0597a',
              'pub_key': 'Mp0eb98ea04ae466d8d38f490db3c99b3996a90e24243952ce9822c6dc1e2c1a43',
              'commission': 10,
              'coin': 'MNT',
              'stake': 5
          })
  
      def test_valid_tx(self):
          """
          Is tx instance of needed TX class.
          """
  
          self.assertIsInstance(self.TX, MinterDeclareCandidacyTx)
  
      def test_sign_tx(self):
          """
          Sign transaction and check signed transaction
          """
          self.TX.sign(self.PRIVATE_KEY)
  
          self.assertEqual(self.TX.signed_tx, self.SIGNED_TX)
  
      def test_sign_with_signature(self):
          self.TX.signature_type = MinterTx.SIGNATURE_SINGLE_TYPE
          signature = self.TX.generate_signature(self.PRIVATE_KEY)
          self.TX.sign(signature=signature)
  
          self.assertEqual(self.TX.signed_tx, self.SIGNED_TX)
  
      def test_from_raw(self):
          tx = MinterTx.from_raw(raw_tx=self.SIGNED_TX)
  
          self.assertEqual(tx.from_mx, self.TX.address)
          self.assertEqual(tx.address, self.TX.address)
          self.assertEqual(tx.pub_key, self.TX.pub_key)
          self.assertEqual(tx.commission, self.TX.commission)
          self.assertEqual(tx.coin, self.TX.coin)
          self.assertEqual(tx.stake, self.TX.stake)
  
  
  class TestMinterDelegateTx(unittest.TestCase):
  
      def setUp(self):
          self.PRIVATE_KEY = '6e1df6ec69638d152f563c5eca6c13cdb5db4055861efc11ec1cdd578afd96bf'
          self.PUBLIC_KEY = 'Mp0eb98ea04ae466d8d38f490db3c99b3996a90e24243952ce9822c6dc1e2c1a43'
          self.SIGNED_TX = 'f8900102018a4d4e540000000000000007b6f5a00eb98ea04ae466d8d38f490db3c99b3996a90e24243952ce9822c6dc1e2c1a438a4d4e5400000000000000888ac7230489e80000808001b845f8431ba01c2c8f702d80cf64da1e9bf1f07a52e2fee8721aebe419aa9f62260a98983f89a07ed297d71d9dc37a57ffe9bb16915dccc703d8c09f30da8aadb9d5dbab8c7da9'
  
          self.TX = MinterDelegateTx(**{
              'nonce': 1,
              'chain_id': MinterTx.TESTNET_CHAIN_ID,
              'gas_coin': 'MNT',
              'pub_key': self.PUBLIC_KEY,
              'coin': 'MNT',
              'stake': 10
          })
  
      def test_valid_tx(self):
          """
          Is tx instance of needed TX class.
          """
  
          self.assertIsInstance(self.TX, MinterDelegateTx)
  
      def test_sign_tx(self):
          """
          Sign transaction and check signed transaction
          """
          self.TX.sign(self.PRIVATE_KEY)
  
          self.assertEqual(self.TX.signed_tx, self.SIGNED_TX)
  
      def test_sign_with_signature(self):
          self.TX.signature_type = MinterTx.SIGNATURE_SINGLE_TYPE
          signature = self.TX.generate_signature(self.PRIVATE_KEY)
          self.TX.sign(signature=signature)
  
          self.assertEqual(self.TX.signed_tx, self.SIGNED_TX)
  
      def test_from_raw(self):
          tx = MinterTx.from_raw(raw_tx=self.SIGNED_TX)
  
          self.assertEqual(tx.pub_key, self.PUBLIC_KEY)
          self.assertEqual(tx.coin, self.TX.coin)
          self.assertEqual(tx.stake, self.TX.stake)
  
  
  class TestMinterRedeemCheckTx(unittest.TestCase):
  
      def setUp(self):
          self.PRIVATE_KEY = '05ddcd4e6f7d248ed1388f0091fe345bf9bf4fc2390384e26005e7675c98b3c1'
          self.SIGNED_TX = 'f9013f0102018a4d4e540000000000000009b8e4f8e2b89df89b01830f423f8a4d4e5400000000000000843b9aca00b8419b3beac2c6ad88a8bd54d24912754bb820e58345731cb1b9bc0885ee74f9e50a58a80aa990a29c98b05541b266af99d3825bb1e5ed4e540c6e2f7c9b40af9ecc011ca00f7ba6d0aa47d74274b960fba02be03158d0374b978dcaa5f56fc7cf1754f821a019a829a3b7bba2fc290f5c96e469851a3876376d6a6a4df937327b3a5e9e8297b841da021d4f84728e0d3d312a18ec84c21768e0caa12a53cb0a1452771f72b0d1a91770ae139fd6c23bcf8cec50f5f2e733eabb8482cf29ee540e56c6639aac469600808001b845f8431ba009493b3296a085a27f2bc015ad5c1cc644ba21bdce1b78a49e987227f24a87a3a07187da48b6ea528d372ed33923f5d74011f56cc2db3cab2cf5b4bbab97990373'
          self.TX = MinterRedeemCheckTx(**{
              'nonce': 1,
              'chain_id': MinterTx.TESTNET_CHAIN_ID,
              'gas_coin': 'MNT',
              'check': 'Mcf89b01830f423f8a4d4e5400000000000000843b9aca00b8419b3beac2c6ad88a8bd54d24912754bb820e58345731cb1b9bc0885ee74f9e50a58a80aa990a29c98b05541b266af99d3825bb1e5ed4e540c6e2f7c9b40af9ecc011ca00f7ba6d0aa47d74274b960fba02be03158d0374b978dcaa5f56fc7cf1754f821a019a829a3b7bba2fc290f5c96e469851a3876376d6a6a4df937327b3a5e9e8297',
              'proof': 'da021d4f84728e0d3d312a18ec84c21768e0caa12a53cb0a1452771f72b0d1a91770ae139fd6c23bcf8cec50f5f2e733eabb8482cf29ee540e56c6639aac469600'
          })
  
      def test_valid_tx(self):
          """
          Is tx instance of needed TX class.
          """
  
          self.assertIsInstance(self.TX, MinterRedeemCheckTx)
  
      def test_sign_tx(self):
          """
          Sign transaction and check signed transaction
          """
          self.TX.sign(self.PRIVATE_KEY)
  
          self.assertEqual(self.TX.signed_tx, self.SIGNED_TX)
  
      def test_sign_with_signature(self):
          self.TX.signature_type = MinterTx.SIGNATURE_SINGLE_TYPE
          signature = self.TX.generate_signature(self.PRIVATE_KEY)
          self.TX.sign(signature=signature)
  
          self.assertEqual(self.TX.signed_tx, self.SIGNED_TX)
  
      def test_from_raw(self):
          tx = MinterTx.from_raw(raw_tx=self.SIGNED_TX)
  
          self.assertEqual(tx.check, self.TX.check)
          self.assertEqual(tx.proof, self.TX.proof)
  
  
  class TestMinterSellAllCoinTx(unittest.TestCase):
  
      def setUp(self):
          self.FROM = 'Mx31e61a05adbd13c6b625262704bc305bf7725026'
          self.PRIVATE_KEY = '07bc17abdcee8b971bb8723e36fe9d2523306d5ab2d683631693238e0f9df142'
          self.SIGNED_TX = 'f87a0102018a4d4e540000000000000003a0df8a4d4e54000000000000008a54455354000000000000880de0b6b3a7640000808001b845f8431ca0b10794a196b6ad2f94e6162613ca9538429dd49ca493594ba9d99f80d2499765a03c1d78e9e04f57336691e8812a16faccb00bf92ac817ab61cd9bf001e9380d47'
          self.TX = MinterSellAllCoinTx(**{
              'nonce': 1,
              'chain_id': MinterTx.TESTNET_CHAIN_ID,
              'gas_coin': 'MNT',
              'coin_to_sell': 'MNT',
              'coin_to_buy': 'TEST',
              'min_value_to_buy': 1
          })
  
      def test_valid_tx(self):
          """
          Is tx instance of needed TX class.
          """
  
          self.assertIsInstance(self.TX, MinterSellAllCoinTx)
  
      def test_sign_tx(self):
          """
          Sign transaction and check signed transaction
          """
          self.TX.sign(self.PRIVATE_KEY)
  
          self.assertEqual(self.TX.signed_tx, self.SIGNED_TX)
  
      def test_sign_with_signature(self):
          self.TX.signature_type = MinterTx.SIGNATURE_SINGLE_TYPE
          signature = self.TX.generate_signature(self.PRIVATE_KEY)
          self.TX.sign(signature=signature)
  
          self.assertEqual(self.TX.signed_tx, self.SIGNED_TX)
  
      def test_from_raw(self):
          tx = MinterTx.from_raw(raw_tx=self.SIGNED_TX)
  
          self.assertEqual(tx.from_mx, self.FROM)
          self.assertEqual(tx.coin_to_sell, self.TX.coin_to_sell)
          self.assertEqual(tx.coin_to_buy, self.TX.coin_to_buy)
          self.assertEqual(tx.min_value_to_buy, self.TX.min_value_to_buy)
  
  
  class TestMinterSellCoinTx(unittest.TestCase):
  
      def setUp(self):
          self.FROM = 'Mx31e61a05adbd13c6b625262704bc305bf7725026'
          self.PRIVATE_KEY = '07bc17abdcee8b971bb8723e36fe9d2523306d5ab2d683631693238e0f9df142'
          self.SIGNED_TX = 'f8830102018a4d4e540000000000000002a9e88a4d4e5400000000000000880de0b6b3a76400008a54455354000000000000880de0b6b3a7640000808001b845f8431ba0e34be907a18acb5a1aed263ef419f32f5adc6e772b92f949906b497bba557df3a0291d7704980994f7a6f5950ca84720746b5928f21c3cfc5a5fbca2a9f4d35db0'
          self.TX = MinterSellCoinTx(**{
              'nonce': 1,
              'chain_id': MinterTx.TESTNET_CHAIN_ID,
              'gas_coin': 'MNT',
              'coin_to_sell': 'MNT',
              'value_to_sell': 1,
              'coin_to_buy': 'TEST',
              'min_value_to_buy': 1
          })
  
      def test_valid_tx(self):
          """
          Is tx instance of needed TX class.
          """
  
          self.assertIsInstance(self.TX, MinterSellCoinTx)
  
      def test_sign_tx(self):
          """
          Sign transaction and check signed transaction
          """
          self.TX.sign(self.PRIVATE_KEY)
  
          self.assertEqual(self.TX.signed_tx, self.SIGNED_TX)
  
      def test_sign_with_signature(self):
          self.TX.signature_type = MinterTx.SIGNATURE_SINGLE_TYPE
          signature = self.TX.generate_signature(self.PRIVATE_KEY)
          self.TX.sign(signature=signature)
  
          self.assertEqual(self.TX.signed_tx, self.SIGNED_TX)
  
      def test_from_raw(self):
          tx = MinterTx.from_raw(raw_tx=self.SIGNED_TX)
  
          self.assertEqual(tx.from_mx, self.FROM)
          self.assertEqual(tx.coin_to_sell, self.TX.coin_to_sell)
          self.assertEqual(tx.value_to_sell, self.TX.value_to_sell)
          self.assertEqual(tx.coin_to_buy, self.TX.coin_to_buy)
          self.assertEqual(tx.min_value_to_buy, self.TX.min_value_to_buy)
  
  
  class TestMinterSendTx(unittest.TestCase):
  
      def setUp(self):
          self.PRIVATE_KEY = '07bc17abdcee8b971bb8723e36fe9d2523306d5ab2d683631693238e0f9df142'
          self.TO = 'Mx1b685a7c1e78726c48f619c497a07ed75fe00483'
          self.FROM = 'Mx31e61a05adbd13c6b625262704bc305bf7725026'
          self.SIGNED_TX = 'f8840102018a4d4e540000000000000001aae98a4d4e5400000000000000941b685a7c1e78726c48f619c497a07ed75fe00483880de0b6b3a7640000808001b845f8431ca01f36e51600baa1d89d2bee64def9ac5d88c518cdefe45e3de66a3cf9fe410de4a01bc2228dc419a97ded0efe6848de906fbe6c659092167ef0e7dcb8d15024123a'
          self.TX = MinterSendCoinTx(**{
              'nonce': 1,
              'chain_id': MinterTx.TESTNET_CHAIN_ID,
              'gas_coin': 'MNT',
              'to': self.TO,
              'coin': 'MNT',
              'value': 1
          })
  
      def test_valid_tx(self):
          """
          Is tx instance of needed TX class.
          """
  
          self.assertIsInstance(self.TX, MinterSendCoinTx)
  
      def test_sign_tx(self):
          """
          Sign transaction and check signed transaction
          """
          self.TX.sign(self.PRIVATE_KEY)
  
          self.assertEqual(self.TX.signed_tx, self.SIGNED_TX)
  
      def test_sign_with_signature(self):
          self.TX.signature_type = MinterTx.SIGNATURE_SINGLE_TYPE
          signature = self.TX.generate_signature(self.PRIVATE_KEY)
          self.TX.sign(signature=signature)
  
          self.assertEqual(self.TX.signed_tx, self.SIGNED_TX)
  
      def test_from_raw(self):
          tx = MinterTx.from_raw(self.SIGNED_TX)
  
          self.assertEqual(tx.from_mx, self.FROM)
          self.assertEqual(tx.to, self.TX.to)
          self.assertEqual(tx.coin, self.TX.coin)
          self.assertEqual(tx.value, self.TX.value)
  
  
  class TestMinterSetCandidateOffTx(unittest.TestCase):
  
      def setUp(self):
          self.PRIVATE_KEY = '05ddcd4e6f7d248ed1388f0091fe345bf9bf4fc2390384e26005e7675c98b3c1'
          self.SIGNED_TX = 'f87c0102018a4d4e54000000000000000ba2e1a00eb98ea04ae466d8d38f490db3c99b3996a90e24243952ce9822c6dc1e2c1a43808001b845f8431ca02ac45817f167c34b55b8afa0b6d9692be28e2aa41dd28a134663d1f5bebb5ad8a06d5f161a625701d506db20c497d24e9939c2e342a6ff7d724cb1962267bd4ba5'
          self.TX = MinterSetCandidateOffTx(**{
              'nonce': 1,
              'chain_id': MinterTx.TESTNET_CHAIN_ID,
              'gas_coin': 'MNT',
              'pub_key': 'Mp0eb98ea04ae466d8d38f490db3c99b3996a90e24243952ce9822c6dc1e2c1a43'
          })
  
      def test_valid_tx(self):
          """
          Is tx instance of needed TX class.
          """
  
          self.assertIsInstance(self.TX, MinterSetCandidateOffTx)
  
      def test_sign_tx(self):
          """
          Sign transaction and check signed transaction
          """
          self.TX.sign(self.PRIVATE_KEY)
  
          self.assertEqual(self.TX.signed_tx, self.SIGNED_TX)
  
      def test_sign_with_signature(self):
          self.TX.signature_type = MinterTx.SIGNATURE_SINGLE_TYPE
          signature = self.TX.generate_signature(self.PRIVATE_KEY)
          self.TX.sign(signature=signature)
  
          self.assertEqual(self.TX.signed_tx, self.SIGNED_TX)
  
      def test_from_raw(self):
          tx = MinterTx.from_raw(raw_tx=self.SIGNED_TX)
  
          self.assertEqual(tx.pub_key, self.TX.pub_key)
  
  
  class TestMinterSetCandidateOnTx(unittest.TestCase):
  
      def setUp(self):
          self.PRIVATE_KEY = '05ddcd4e6f7d248ed1388f0091fe345bf9bf4fc2390384e26005e7675c98b3c1'
          self.SIGNED_TX = 'f87c0102018a4d4e54000000000000000aa2e1a00eb98ea04ae466d8d38f490db3c99b3996a90e24243952ce9822c6dc1e2c1a43808001b845f8431ba0095aed433171fe5ac385ccd299507bdcad3dd2269794fd0d14d4f58327ddc87ea046ec7e4f8f9b477a1255485f36e0567e62283723ecc5a0bd1e5d201e53e85245'
          self.TX = MinterSetCandidateOnTx(**{
              'nonce': 1,
              'chain_id': MinterTx.TESTNET_CHAIN_ID,
              'gas_coin': 'MNT',
              'pub_key': 'Mp0eb98ea04ae466d8d38f490db3c99b3996a90e24243952ce9822c6dc1e2c1a43'
          })
  
      def test_valid_tx(self):
          """
          Is tx instance of needed TX class.
          """
  
          self.assertIsInstance(self.TX, MinterSetCandidateOnTx)
  
      def test_sign_tx(self):
          """
          Sign transaction and check signed transaction
          """
          self.TX.sign(self.PRIVATE_KEY)
  
          self.assertEqual(self.TX.signed_tx, self.SIGNED_TX)
  
      def test_sign_with_signature(self):
          self.TX.signature_type = MinterTx.SIGNATURE_SINGLE_TYPE
          signature = self.TX.generate_signature(self.PRIVATE_KEY)
          self.TX.sign(signature=signature)
  
          self.assertEqual(self.TX.signed_tx, self.SIGNED_TX)
  
      def test_from_raw(self):
          tx = MinterTx.from_raw(raw_tx=self.SIGNED_TX)
  
          self.assertEqual(tx.pub_key, self.TX.pub_key)
  
  
  class TestMinterUnbondTx(unittest.TestCase):
  
      def setUp(self):
          self.PRIVATE_KEY = '6e1df6ec69638d152f563c5eca6c13cdb5db4055861efc11ec1cdd578afd96bf'
          self.SIGNED_TX = 'f88f0102018a4d4e540000000000000008b6f5a00eb98ea04ae466d8d38f490db3c99b3996a90e24243952ce9822c6dc1e2c1a438a4d4e5400000000000000888ac7230489e80000808001b844f8421ca0ff5766c85847b37a276f3f9d027fb7c99745920fa395c7bd399cedd8265c5e1d9f791bcdfe4d1bc1e73ada7bf833103c828f22d83189dad2b22ad28a54aacf2a'
          self.TX = MinterUnbondTx(**{
              'nonce': 1,
              'chain_id': MinterTx.TESTNET_CHAIN_ID,
              'gas_coin': 'MNT',
              'pub_key': 'Mp0eb98ea04ae466d8d38f490db3c99b3996a90e24243952ce9822c6dc1e2c1a43',
              'coin': 'MNT',
              'value': 10
          })
  
      def test_valid_tx(self):
          """
          Is tx instance of needed TX class.
          """
  
          self.assertIsInstance(self.TX, MinterUnbondTx)
  
      def test_sign_tx(self):
          """
          Sign transaction and check signed transaction
          """
          self.TX.sign(self.PRIVATE_KEY)
  
          self.assertEqual(self.TX.signed_tx, self.SIGNED_TX)
  
      def test_sign_with_signature(self):
          self.TX.signature_type = MinterTx.SIGNATURE_SINGLE_TYPE
          signature = self.TX.generate_signature(self.PRIVATE_KEY)
          self.TX.sign(signature=signature)
  
          self.assertEqual(self.TX.signed_tx, self.SIGNED_TX)
  
      def test_from_raw(self):
          tx = MinterTx.from_raw(raw_tx=self.SIGNED_TX)
  
          self.assertEqual(tx.pub_key, self.TX.pub_key)
          self.assertEqual(tx.coin, self.TX.coin)
          self.assertEqual(tx.value, self.TX.value)
  
  
  class TestMinterEditCandidateTx(unittest.TestCase):
  
      def setUp(self):
          self.FROM = 'Mxa879439b0a29ecc7c5a0afe54b9eb3c22dbde8d9'
          self.PRIVATE_KEY = 'a3fb55450f53dbbf4f2494280188f7f0cd51a7b51ec27ed49ed364d920e326ba'
          self.SIGNED_TX = 'f8a80102018a4d4e54000000000000000eb84df84ba04ae1ee73e6136c85b0ca933a9a1347758a334885f10b3238398a67ac2eb153b89489e5dc185e6bab772ac8e00cf3fb3f4cb0931c4794e731fcddd37bb6e72286597d22516c8ba3ddffa0808001b845f8431ca0421470f27f78231b669c1bf1fcc56168954d64fbb7dc3ff021bab01311fab6eaa075e86365d98c87e806fcbc5c542792f569e19d8ae7af671d9ba4679acc86d35e'
          self.TX = MinterEditCandidateTx(**{
              'nonce': 1,
              'chain_id': MinterTx.TESTNET_CHAIN_ID,
              'gas_coin': 'MNT',
              'pub_key': 'Mp4ae1ee73e6136c85b0ca933a9a1347758a334885f10b3238398a67ac2eb153b8',
              'reward_address': 'Mx89e5dc185e6bab772ac8e00cf3fb3f4cb0931c47',
              'owner_address': 'Mxe731fcddd37bb6e72286597d22516c8ba3ddffa0'
          })
  
      def test_valid_tx(self):
          """
          Is tx instance of needed TX class.
          """
  
          self.assertIsInstance(self.TX, MinterEditCandidateTx)
  
      def test_sign_tx(self):
          """
          Sign transaction and check signed transaction
          """
          self.TX.sign(self.PRIVATE_KEY)
  
          self.assertEqual(self.TX.signed_tx, self.SIGNED_TX)
  
      def test_sign_with_signature(self):
          self.TX.signature_type = MinterTx.SIGNATURE_SINGLE_TYPE
          signature = self.TX.generate_signature(self.PRIVATE_KEY)
          self.TX.sign(signature=signature)
  
          self.assertEqual(self.TX.signed_tx, self.SIGNED_TX)
  
      def test_from_raw(self):
          tx = MinterTx.from_raw(raw_tx=self.SIGNED_TX)
  
          self.assertEqual(tx.from_mx, self.FROM)
          self.assertEqual(tx.pub_key, self.TX.pub_key)
          self.assertEqual(tx.reward_address, self.TX.reward_address)
          self.assertEqual(tx.owner_address, self.TX.owner_address)
  
  
  class TestMinterMultiSendCoinTx(unittest.TestCase):
  
      def setUp(self):
          self.FROM = 'Mx31e61a05adbd13c6b625262704bc305bf7725026'
          self.PRIVATE_KEY = '07bc17abdcee8b971bb8723e36fe9d2523306d5ab2d683631693238e0f9df142'
          self.SIGNED_TX = 'f8b30102018a4d4e54000000000000000db858f856f854e98a4d4e540000000000000094fe60014a6e9ac91618f5d1cab3fd58cded61ee9988016345785d8a0000e98a4d4e540000000000000094ddab6281766ad86497741ff91b6b48fe85012e3c8802c68af0bb140000808001b845f8431ca0b15dcf2e013df1a2aea02e36a17af266d8ee129cdcb3e881d15b70c9457e7571a0226af7bdaca9d42d6774c100b22e0c7ba4ec8dd664d17986318e905613013283'
          self.TX = MinterMultiSendCoinTx(**{
              'nonce': 1,
              'chain_id': MinterTx.TESTNET_CHAIN_ID,
              'gas_coin': 'MNT',
              'txs': [
                  {
                      'coin': 'MNT',
                      'to': 'Mxfe60014a6e9ac91618f5d1cab3fd58cded61ee99',
                      'value': 0.1
                  },
                  {
                      'coin': 'MNT',
                      'to': 'Mxddab6281766ad86497741ff91b6b48fe85012e3c',
                      'value': 0.2
                  }
              ]
          })
  
      def test_valid_tx(self):
          """
          Is tx instance of needed TX class.
          """
  
          self.assertIsInstance(self.TX, MinterMultiSendCoinTx)
  
      def test_sign_tx(self):
          """
          Sign transaction and check signed transaction
          """
          self.TX.sign(self.PRIVATE_KEY)
  
          self.assertEqual(self.TX.signed_tx, self.SIGNED_TX)
  
      def test_from_raw(self):
          tx = MinterTx.from_raw(raw_tx=self.SIGNED_TX)
  
          self.assertEqual(tx.from_mx, self.FROM)
  
      def test_sign_with_signature(self):
          self.TX.signature_type = MinterTx.SIGNATURE_SINGLE_TYPE
          signature = self.TX.generate_signature(self.PRIVATE_KEY)
          self.TX.sign(signature=signature)
  
          self.assertEqual(self.TX.signed_tx, self.SIGNED_TX)
  
  
  class TestTxFees(unittest.TestCase):
  
      def setUp(self):
          self.TO = 'Mx31e61a05adbd13c6b625262704bc305bf7725026'
          self.PRIVATE_KEY = '07bc17abdcee8b971bb8723e36fe9d2523306d5ab2d683631693238e0f9df142'
          self.TX_PAYLOAD_UTF = '🔳'  # 4 bytes
          self.EXPECTED_SEND_COIN_FEE = 18000000000000000
  
          self.MULTISEND_RECIPIENTS = [
              {
                  'coin': 'MNT',
                  'to': 'Mxfe60014a6e9ac91618f5d1cab3fd58cded61ee99',
                  'value': 0.1
              },
              {
                  'coin': 'MNT',
                  'to': 'Mxddab6281766ad86497741ff91b6b48fe85012e3c',
                  'value': 0.2
              }
          ]
          self.EXPECTED_MULTISEND_FEE = 15000000000000000
  
      def test_payload_fee(self):
          tx = MinterSendCoinTx(**{
              'nonce': 1,
              'chain_id': MinterTx.TESTNET_CHAIN_ID,
              'gas_coin': 'MNT',
              'to': self.TO,
              'coin': 'MNT',
              'value': 1,
              'payload': self.TX_PAYLOAD_UTF
          })
          tx.sign(self.PRIVATE_KEY)
          actual_fee = tx.get_fee()
          self.assertEqual(self.EXPECTED_SEND_COIN_FEE, actual_fee)
  
      def test_multisend_fee(self):
          tx = MinterMultiSendCoinTx(**{
              'nonce': 1,
              'chain_id': MinterTx.TESTNET_CHAIN_ID,
              'gas_coin': 'MNT',
              'txs': self.MULTISEND_RECIPIENTS
          })
          tx.sign(self.PRIVATE_KEY)
          actual_fee = tx.get_fee()
          self.assertEqual(self.EXPECTED_MULTISEND_FEE, actual_fee)
  
  
  class TestMinterSendMultisigTx(unittest.TestCase):
  
      def setUp(self):
          self.PRIVATE_KEYS = [
              'b354c3d1d456d5a1ddd65ca05fd710117701ec69d82dac1858986049a0385af9',
              '38b7dfb77426247aed6081f769ed8f62aaec2ee2b38336110ac4f7484478dccb',
              '94c0915734f92dd66acfdc48f82b1d0b208efd544fe763386160ec30c968b4af'
          ]
          self.TO = 'Mxd82558ea00eb81d35f2654953598f5d51737d31d'
          self.FROM = 'Mxdb4f4b6942cb927e8d7e3a1f602d0f1fb43b5bd2'
          self.SIGNED_TX = 'f901270102018a4d4e540000000000000001aae98a4d4e540000000000000094d82558ea00eb81d35f2654953598f5d51737d31d880de0b6b3a7640000808002b8e8f8e694db4f4b6942cb927e8d7e3a1f602d0f1fb43b5bd2f8cff8431ca0a116e33d2fea86a213577fc9dae16a7e4cadb375499f378b33cddd1d4113b6c1a021ee1e9eb61bbd24233a0967e1c745ab23001cf8816bb217d01ed4595c6cb2cdf8431ca0f7f9c7a6734ab2db210356161f2d012aa9936ee506d88d8d0cba15ad6c84f8a7a04b71b87cbbe7905942de839211daa984325a15bdeca6eea75e5d0f28f9aaeef8f8431ba0d8c640d7605034eefc8870a6a3d1c22e2f589a9319288342632b1c4e6ce35128a055fe3f93f31044033fe7b07963d547ac50bccaac38a057ce61665374c72fb454'
          self.TX = MinterSendCoinTx(**{
              'nonce': 1,
              'chain_id': MinterTx.TESTNET_CHAIN_ID,
              'gas_coin': 'MNT',
              'to': self.TO,
              'coin': 'MNT',
              'value': 1
          })
  
      def test_valid_tx(self):
          """
          Is tx instance of needed TX class.
          """
  
          self.assertIsInstance(self.TX, MinterSendCoinTx)
  
      def test_sign_tx(self):
          """
          Sign transaction and check signed transaction
          """
          self.TX.sign(private_key=self.PRIVATE_KEYS, ms_address=self.FROM)
  
          self.assertEqual(self.TX.signed_tx, self.SIGNED_TX)
  
      def test_from_raw(self):
          tx = MinterTx.from_raw(self.SIGNED_TX)
  
          self.assertEqual(tx.from_mx, self.FROM)
          self.assertEqual(tx.to, self.TX.to)
          self.assertEqual(tx.coin, self.TX.coin)
          self.assertEqual(tx.value, self.TX.value)
  
      def test_add_signature(self):
          # Sign tx with 2 of 3 private keys
          self.TX.sign(private_key=self.PRIVATE_KEYS[:2], ms_address=self.FROM)
          # Add signature by 3rd private key
          self.TX = MinterTx.add_signature(self.TX.signed_tx, self.PRIVATE_KEYS[2])
  
          self.assertEqual(self.TX.signed_tx, self.SIGNED_TX)
  
      def test_sign_with_signature(self):
          # Set signature type for transaction
          self.TX.signature_type = MinterTx.SIGNATURE_MULTI_TYPE
  
          # Generate signatures
          signatures = []
          for pk in self.PRIVATE_KEYS:
              signature = self.TX.generate_signature(private_key=pk)
              signatures.append(signature)
  
          # Sign transaction with signatures
          self.TX.sign(signature=signatures, ms_address=self.FROM)
  
          self.assertEqual(self.TX.signed_tx, self.SIGNED_TX)
  
      def test_sign_with_pk_and_signature(self):
          # Set signature type for transaction
          self.TX.signature_type = MinterTx.SIGNATURE_MULTI_TYPE
  
          # Generate 1 signature
          signatures = []
          for pk in self.PRIVATE_KEYS:
              signatures.append(self.TX.generate_signature(private_key=pk))
  
          # Sign transaction with pks and signature
          self.TX.sign(private_key=self.PRIVATE_KEYS[:2], signature=signatures[2], ms_address=self.FROM)
          self.assertEqual(self.TX.signed_tx, self.SIGNED_TX)
  
          self.TX.sign(private_key=self.PRIVATE_KEYS[0], signature=signatures[1:], ms_address=self.FROM)
          self.assertEqual(self.TX.signed_tx, self.SIGNED_TX)
  
  
  class TestPayloadsFromRaw(unittest.TestCase):
      def setUp(self):
          self.TO = 'Mxd82558ea00eb81d35f2654953598f5d51737d31d'
          self.FROM = 'Mx31e61a05adbd13c6b625262704bc305bf7725026'
          self.PK = '07bc17abdcee8b971bb8723e36fe9d2523306d5ab2d683631693238e0f9df142'
          self.TX = MinterSendCoinTx(
              nonce=1, gas_coin='mnt', to=self.TO, coin='mnt', value=1
          )
          self.TX_DECODED = None
  
      def sign_and_decode(self, payload):
          self.TX.payload = payload
          self.TX.sign(private_key=self.PK)
          self.TX_DECODED = MinterTx.from_raw(self.TX.signed_tx)
  
      def test_hex_like(self):
          payload = 'fff'
          self.sign_and_decode(payload)
  
          self.assertEqual(payload, self.TX_DECODED.payload)
          self.assertEqual(self.FROM, self.TX_DECODED.from_mx)
  
      def test_str_bytes(self):
          payload = '🔳'
          self.sign_and_decode(payload)
  
          self.assertEqual(payload, self.TX_DECODED.payload)
          self.assertEqual(self.FROM, self.TX_DECODED.from_mx)
  
      def test_raw_bytes(self):
          payload = b'\xff\xff\xff'
          self.sign_and_decode(payload)
  
          self.assertEqual(payload, self.TX_DECODED.payload)
          self.assertEqual(self.FROM, self.TX_DECODED.from_mx)
  
  
  class TestFromBase64(unittest.TestCase):
      def setUp(self):
          self.B64_TXS = [
              '+Hw8AQGKQklQAAAAAAAAAAKi4YpPTEJJVFgAAAAAiQHluPqP4qwAAIpMRU1PTgAAAAAAgICAAbhF+EMboPtT5w1Brh5BO66qs75e1sOj9Ka4KfxGQDOFsQssgNn/oAeDnTkaMj685tdWvWa6rUmViaCB+KerPBDHUE7O731j',
              '+H+DBJaHAQGKQklQAAAAAAAAAAGi4YpCSVAAAAAAAAAAlJXK8ve/qfgqz5QEbX52KCQKOQ/bgICAAbhF+EMcoFVh1TOlkwUHmSpEvOQprRnZgnpSeIFxXn15fApbl28qoFR5GhbH34BiCmpwqY+Qs4xI5DjfE9PNfVYEZ7axgyvc',
              '+IeCGxkBAYpCSVAAAAAAAAAAAavqikNPTlNVTEdBTUWUm7rikGga0Jtdjuse5KRJp2SOn8WJAaBVaQ2duAAAgIABuEX4QxygBQd9EAxqcsKigdqsvCEVA5GapLPxdlbZ/DYkC3RXpYOgJ2QuKIW1U/yrTVec56v06V42VwaO2VRqGvuJVLkojvU=',
              '+HqCMGYBAYpCSVAAAAAAAAAAA57dikJJUAAAAAAAAACKQ0VOVEFVUlVTAIZa8xB6QACAgAG4RfhDG6A+PinAE4fNMpPwC8U8/DbHNSIERcWDE9rridQ1DyECAaBiGkXNmAgUnYK2VjJjMLJGWLN4T3jz/2KylTFZqXNM5Q==',
              '+H6CBYcBAYpCSVAAAAAAAAAAAqLhikJJUAAAAAAAAACJARWORgkT0AAAilRBUFRBUAAAAACAgIABuEX4Qxug8tXe0wJ61FNJq+p/KEVsTE044Cq5mqtnD55xyUM2niigCPjkKq+K5Rabeghgyf7+zxjOhykruz0dQOoZR5GzbZ8=',
              '+JKB2AEBikJJUAAAAAAAAAAHt/agd/cYNBCOm15lI3o5JjYxtPmanVhDehOFyTDBPuHU4qaKT05MWTEAAAAAAIm+S9/Lh9P4ZoqAgAG4RfhDG6AVkWCf6F/LQlIUjBFQFCcfAgWxhRBTs7ZdLDLOaUQntaB/C/kHw/fRLDH/ZMM5hdZpx87pZZfTRTuQ6Peda7ParA==',
              '+IRVAQGKQklQAAAAAAAAAAGq6YpCSVAAAAAAAAAAlG3tXZ5JAX3uqMMYO7aKsxx9JGTxiIrHIwSJ6AAAgIABuEX4QxugLtA0N8YgapJtAF4/oq4mgnDeTAFy64tAfhlY2POh4fmgTB1pdMhcBzpSiPqUTVPTCn+xwAxpTD8eQsV5+ZWEM40=',
              '+JKCTDIBAYpCSVAAAAAAAAAAB7b1oGKbVSjwnRx0qD0YQU8uQmPhSFDEej+sP4VfIAERERERikJJUAAAAAAAAACIRWORgkT0AACAgAG4RfhDG6BbXtr6FKf4Ifdlji3nCSqUQ3OEfReYBUfa71+zNb0wh6AEZSWMY7CGXvh3Rqjjiam9IT3NL7gvI/wrqxSrFkxj/g==',
              '+JOCB6IBAYpCSVAAAAAAAAAAB7f2oGKbVSjwnRx0qD0YQU8uQmPhSFDEej+sP4VfIAERERERikJJUAAAAAAAAACJFa8deLWMQAAAgIABuEX4Qxyg3MYUWNZZPy1k4ikM97HJ7RJuLCHyteqUymPVQ+r+qJygcN2yKmUK9adEaqjQRNEHesgRE+dAlamHu2Bd7OE4zwI=',
              '+JOCAZIBAYpCSVAAAAAAAAAAB7f2oGKbVSjwnRx0qD0YQU8uQmPhSFDEej+sP4VfIAERERERikJJUAAAAAAAAACJBbEq76+oBAAAgIABuEX4QxygLl0jQ98RtdXCkIKDYce9OD11tpA4kmAtPLXIGkeycAKgGRsYDVVx+SD98N4zKByD2H+w0yToFuZk8gN2PtWVNpQ=',
              '+IQJAQGKQklQAAAAAAAAAAGq6YpCSVAAAAAAAAAAlJ9/UFrwbYh8dflHt3kRDT99fUG/iJNP9bP1XNAAgIABuEX4QxugOu3JcCce9OO5rpWDVsQpGk+gwTLbt3p8qu2YM7Tg1UGgF8Ez00im24HKFlJM2DWoUSJ3G1BjzREg1AGG6dP1s1s=',
              '+H6CB1UBAYpCSVAAAAAAAAAAAqLhikJJUAAAAAAAAACJEENWGogpMAAAikNFTlRBVVJVUwCAgIABuEX4QxugfLaJkvWttDTqA9EelJ+9RQ8anWwngbIkeOuQydh0RI2gB0JC+oxPrSmB8dZmazeh3ot2Ff6bE2czGfwgPu7ZpCg=',
              '+PaCAw8BAYpCSVAAAAAAAAAAAavqikJJUAAAAAAAAACUvW+bnucw5qCqmK4SHaLeJ1gp4YSJYadP9azWWcAAuG5CaXBleC5uZXQgLSBTdWNjZXNzIEJpcCB3aXRoZHJhd2FsICMxMzczOC4gT3VyIGN1cnJlbnQgZXhjaGFuZ2UgcmF0ZXMgZm9yIDEgQklQOiAwLjAxNDckIC8gMC4wMTUzJC4gRm9sbG93IHVzLoABuEX4Qxug7zYujmw36ehtj+scZxn+Zlpj3NrtUp924DwBS9+hkJagQtz8zLrB4jgzLnFtDv1F0t1gKQnpU6PyTYGuicMMRe0=',
              '+H+DBJaLAQGKQklQAAAAAAAAAAGi4YpCSVAAAAAAAAAAlJXK8ve/qfgqz5QEbX52KCQKOQ/bgICAAbhF+EMboKGqlP2cC2tqtsnntOBRAg9XNsVBBb5wLBjCPlp5RuBaoDLYDXbDwKQz/ONyYoDV9AUI0C7wCME+T/gGeR1BEdCu',
              '+JOCARABAYpCSVAAAAAAAAAAB7f2oEiBrRZ8pftYhjIoQfmS1ortiU/8tYq8CA6K07FW8QRbikJJUAAAAAAAAACJA9NIdC2o2QDmgIABuEX4QxugGdqhQ+dkzUft+Pc5/A0TYUXcZLGDLA8C/5Q2GzNhRoygaAxGtwGHh9VCrOUVsUCvxOyMSZkMqIbC2i7LVKNY6qU=',
              '+IQJAQGKQklQAAAAAAAAAAGq6YpCSVAAAAAAAAAAlJ9/UFrwbYh8dflHt3kRDT99fUG/iJb2P7XLwAAAgIABuEX4QxygHiZ64dA9EZbsmjLMtDWPvs/Sn4vLjTeCjAizxgEyFhegG9HDwfYDX249KO/kIVXnOsUUBTA1u6KvsImtRTYwyA0=',
              '+H6CB1YBAYpCSVAAAAAAAAAAAqLhikJJUAAAAAAAAACJEENWGogpMAAAik9ORUJJUAAAAACAgIABuEX4Qxug81K8K87BiQpmawv8wBT/8wJA7xexSiStKlH+ijGE+/agCOLB7aqTVi62WHw2BgRBIlYMICc3LOSqsWE6lFku3Ew=',
              '+IaCAwQBAYpCSVAAAAAAAAAAAarpikZBTENPTgAAAACUhfwWxlBErQ8ZAvfDq2FnB0UsxeaIDeC2s6dkAACAgAG4RfhDG6C1m77cTSA1qllKv8FOW3/BaIO3lVQtrVclDUd5ay3NpaBPHg/nkVgAfN63rRKBYiNZBb+4sa4tVjSLlL2v6yVB5w==',
              '+IMrAQGKQklQAAAAAAAAAAKp6IpCSVAAAAAAAAAAiAr2pNB8jwAAikVDT05BAAAAAACITCl3L4h8OpGAgAG4RfhDG6DX7yY6y9xkV640fWT9EMcIH/WDrPu3Y4hX9zpESaijPKBVP7Z56G2J1urB3QZq9cl7AaYbE7EZeAMWsCsidQGXvg==',
              '+IUBAQGKQklQAAAAAAAAAAGr6opCSVAAAAAAAAAAlK/SZxtm+xqSGATRe5jj+eCa+bhmiXPriL12u+CcAICAAbhF+EMboJioZmk/kgs9vAcJcvM8VwmoRuws0s02eMT9yMqNr5s7oBk5m7YSzSIKDjRQYRjyaktm+zMQI4JluYnQVSOpbVkt'
          ]
  
      @staticmethod
      def base64ToHex(b64str):
          b64_bytes = b64str.encode()
          tx_bytes = base64.b64decode(b64_bytes)
  
          return tx_bytes.hex()
  
      def test_txs(self):
          for index, b64_tx in enumerate(self.B64_TXS):
              try:
                  raw_tx = self.base64ToHex(b64_tx)
                  MinterTx.from_raw(raw_tx)
              except Exception as e:
                  self.fail(f'Tx #{index} from base64 failed: {e.__str__()}')
  
  
  if __name__ == '__main__':
      unittest.main()
  