Repository: pybitcash/bitcash (language: python)

Issue:
Cash Tokens support CHIP-2022-02-CashTokens
Would like to request support for Cash Tokens CHIP-2022-02-CashTokens

https://github.com/bitjson/cashtokens
Adds P2SH32 output support
P2SH32 is being worked on for May 2023 upgrade. This PR adds P2SH32 output support.

TODO:

- [x] [Check if OP_Hash256 or OP_SHA256 is used for hashing. ](https://bitcoincashresearch.org/t/chip-2022-05-pay-to-script-hash-32-p2sh32-for-bitcoin-cash/806/3)
- [x] Add test for P2SH32 output.
Adds Cashtoken support
Fixes #121, builds on #119.

Adds Cashtoken support to Bitcash.

- [x] Unspent are aware of cashtoken
- [x] Cashtoken handling class
- [x] Sanitized outputs are aware of cashtokens
- [x] wallets are aware of cashtokens
- [x] wallets can generate cashtoken tx
- [x] wallets can generate cashtokens
- [x] cashaddress signals cashtoken support
- [x] wallets signal cashtoken support 
- [x] add test vectors for cashtoken prefix and token aware cashaddress
- [x] add cashtoken documentation


Discussion / hints:

Fix patch:
diff --git a/HISTORY.rst b/HISTORY.rst
index d16a46f5..5838e592 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -16,9 +16,13 @@ Unreleased (see `master <https://github.com/ofek/bitcash>`_)
 - NetworkAPI.get_tx_amount() is now working and properly handles
   backends returning string or decimal values.
 
-- Wallets can pay to script hash. However, P2SH utxo spending is still
+- Wallets can pay to script hash (P2SH20 and P2SH32). However, P2SH utxo spending is still
   not supported.
 
+- Wallets support CashTokens.
+
+- ChainGraph API support added, with default networks for mainnet and testnet.
+
 - Supports CashAddress URIs.
 
 0.5.2 (2018-05-16)
diff --git a/bitcash/cashaddress.py b/bitcash/cashaddress.py
index 21b023a1..509df652 100644
--- a/bitcash/cashaddress.py
+++ b/bitcash/cashaddress.py
@@ -1,4 +1,7 @@
+import io
 from bitcash.exceptions import InvalidAddress
+from bitcash.op import OpCodes
+from bitcash.utils import varint_to_int
 
 CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
 
@@ -74,21 +77,89 @@ def prefix_expand(prefix):
 
 
 class Address:
+    """
+    Class to handle CashAddr.
+
+    :param version: Version of CashAddr
+    :type version: ``str``
+    :param payload: Payload of CashAddr as int list of the bytearray
+    :type payload: ``list`` of ``int``
+    """
+
     VERSIONS = {
-        "P2SH": {"prefix": "bitcoincash", "version_bit": 8, "network": "mainnet"},
+        "P2SH20": {"prefix": "bitcoincash", "version_bit": 8, "network": "mainnet"},
+        "P2SH32": {"prefix": "bitcoincash", "version_bit": 11, "network": "mainnet"},
         "P2PKH": {"prefix": "bitcoincash", "version_bit": 0, "network": "mainnet"},
-        "P2SH-TESTNET": {"prefix": "bchtest", "version_bit": 8, "network": "testnet"},
+        "P2SH20-TESTNET": {"prefix": "bchtest", "version_bit": 8, "network": "testnet"},
+        "P2SH32-TESTNET": {
+            "prefix": "bchtest",
+            "version_bit": 11,
+            "network": "testnet",
+        },
         "P2PKH-TESTNET": {"prefix": "bchtest", "version_bit": 0, "network": "testnet"},
-        "P2SH-REGTEST": {"prefix": "bchreg", "version_bit": 8, "network": "regtest"},
+        "P2SH20-REGTEST": {"prefix": "bchreg", "version_bit": 8, "network": "regtest"},
+        "P2SH32-REGTEST": {"prefix": "bchreg", "version_bit": 11, "network": "regtest"},
         "P2PKH-REGTEST": {"prefix": "bchreg", "version_bit": 0, "network": "regtest"},
+        "P2SH20-CATKN": {
+            "prefix": "bitcoincash",
+            "version_bit": 24,
+            "network": "mainnet",
+        },
+        "P2SH32-CATKN": {
+            "prefix": "bitcoincash",
+            "version_bit": 27,
+            "network": "mainnet",
+        },
+        "P2PKH-CATKN": {
+            "prefix": "bitcoincash",
+            "version_bit": 16,
+            "network": "mainnet",
+        },
+        "P2SH20-CATKN-TESTNET": {
+            "prefix": "bchtest",
+            "version_bit": 24,
+            "network": "testnet",
+        },
+        "P2SH32-CATKN-TESTNET": {
+            "prefix": "bchtest",
+            "version_bit": 27,
+            "network": "testnet",
+        },
+        "P2PKH-CATKN-TESTNET": {
+            "prefix": "bchtest",
+            "version_bit": 16,
+            "network": "testnet",
+        },
+        "P2SH20-CATKN-REGTEST": {
+            "prefix": "bchreg",
+            "version_bit": 24,
+            "network": "regtest",
+        },
+        "P2SH32-CATKN-REGTEST": {
+            "prefix": "bchreg",
+            "version_bit": 27,
+            "network": "regtest",
+        },
+        "P2PKH-CATKN-REGTEST": {
+            "prefix": "bchreg",
+            "version_bit": 16,
+            "network": "regtest",
+        },
     }
 
     VERSION_SUFFIXES = {"bitcoincash": "", "bchtest": "-TESTNET", "bchreg": "-REGTEST"}
 
-    ADDRESS_TYPES = {0: "P2PKH", 8: "P2SH"}
+    ADDRESS_TYPES = {
+        0: "P2PKH",
+        8: "P2SH20",
+        11: "P2SH32",
+        16: "P2PKH-CATKN",
+        24: "P2SH20-CATKN",
+        27: "P2SH32-CATKN",
+    }
 
     def __init__(self, version, payload):
-        if not version in Address.VERSIONS:
+        if version not in Address.VERSIONS:
             raise ValueError("Invalid address version provided")
 
         self.version = version
@@ -115,14 +186,111 @@ def __eq__(self, other):
             )
 
     def cash_address(self):
+        """
+        Generate CashAddr of the Address
+
+        :rtype: ``str``
+        """
         version_bit = Address.VERSIONS[self.version]["version_bit"]
         payload = [version_bit] + self.payload
         payload = convertbits(payload, 8, 5)
         checksum = calculate_checksum(self.prefix, payload)
         return self.prefix + ":" + b32encode(payload + checksum)
 
+    @property
+    def scriptcode(self):
+        """
+        Generate the locking script of the Address
+
+        :rtype: ``bytes``
+        """
+        if "P2PKH" in self.version:
+            return (
+                OpCodes.OP_DUP.binary
+                + OpCodes.OP_HASH160.binary
+                + OpCodes.OP_DATA_20.binary
+                + bytes(self.payload)
+                + OpCodes.OP_EQUALVERIFY.binary
+                + OpCodes.OP_CHECKSIG.binary
+            )
+        if "P2SH20" in self.version:
+            return (
+                OpCodes.OP_HASH160.binary
+                + OpCodes.OP_DATA_20.binary
+                + bytes(self.payload)
+                + OpCodes.OP_EQUAL.binary
+            )
+        if "P2SH32" in self.version:
+            return (
+                OpCodes.OP_HASH256.binary
+                + OpCodes.OP_DATA_32.binary
+                + bytes(self.payload)
+                + OpCodes.OP_EQUAL.binary
+            )
+
+    @classmethod
+    def from_script(cls, scriptcode):
+        """
+        Generate Address from a locking script
+
+        :param scriptcode: The locking script
+        :type scriptcode: ``bytes``
+        :returns: Instance of :class:~bitcash.cashaddress.Address
+        """
+        # cashtoken suffix
+        catkn = ""
+        if scriptcode.startswith(OpCodes.OP_TOKENPREFIX.binary):
+            catkn = "-CATKN"
+            stream = io.BytesIO(scriptcode[33:])
+
+            token_bitfield = stream.read(1).hex()
+            # 4 bit prefix
+            _ = bin(int(token_bitfield[0], 16))[2:]
+            _ = "0" * (4 - len(_)) + _
+            prefix_structure = [bit == "1" for bit in _]
+            if prefix_structure[1]:
+                # has commitment length
+                length = varint_to_int(stream)
+                _ = stream.read(length)
+            if prefix_structure[3]:
+                # has amount
+                _ = varint_to_int(stream)
+            # only use locking script for the rest
+            scriptcode = stream.read()
+
+        # P2PKH
+        if len(scriptcode) == 25:
+            if scriptcode.startswith(
+                OpCodes.OP_DUP.binary
+                + OpCodes.OP_HASH160.binary
+                + OpCodes.OP_DATA_20.binary
+            ) and scriptcode.endswith(
+                OpCodes.OP_EQUALVERIFY.binary + OpCodes.OP_CHECKSIG.binary
+            ):
+                return cls("P2PKH" + catkn, list(scriptcode[3:23]))
+        # P2SH20
+        if len(scriptcode) == 23:
+            if scriptcode.startswith(
+                OpCodes.OP_HASH160.binary + OpCodes.OP_DATA_20.binary
+            ) and scriptcode.endswith(OpCodes.OP_EQUAL.binary):
+                return cls("P2SH20" + catkn, list(scriptcode[2:22]))
+        # P2SH32
+        if len(scriptcode) == 35:
+            if scriptcode.startswith(
+                OpCodes.OP_HASH256.binary + OpCodes.OP_DATA_32.binary
+            ) and scriptcode.endswith(OpCodes.OP_EQUAL.binary):
+                return cls("P2SH32" + catkn, list(scriptcode[2:34]))
+        raise ValueError("Unknown script")
+
     @staticmethod
     def from_string(address):
+        """
+        Generate Address from a cashadress string
+
+        :param scriptcode: The cashaddress string
+        :type scriptcode: ``str``
+        :returns: Instance of :class:~bitcash.cashaddress.Address
+        """
         try:
             address = str(address)
         except Exception:
diff --git a/bitcash/cashtoken.py b/bitcash/cashtoken.py
new file mode 100644
index 00000000..4897d173
--- /dev/null
+++ b/bitcash/cashtoken.py
@@ -0,0 +1,642 @@
+import io
+
+from bitcash.network.rates import currency_to_satoshi_cached
+from bitcash.cashaddress import Address
+from bitcash.network.meta import Unspent
+from bitcash.utils import int_to_varint, varint_to_int
+from bitcash.op import OpCodes
+from bitcash.exceptions import InsufficientFunds, InvalidCashToken, InvalidAddress
+
+
+COMMITMENT_LENGTH = 40
+
+
+def _calculate_dust_value(
+    address, category_id, nft_capability, nft_commitment, token_amount
+):
+    """
+    Calculates dust value for output
+
+    :param address: CashAddr address
+    :type address: ``str``
+    :param category_id: Category hex of the cashtoken
+    :type category_id: ``str``
+    :param nft_capability: Capability of the non-fungible token
+    :type nft_capability: ``str``
+    :param nft_commitment: Commitment bytes of the non-fungible token
+    :type nft_commitment: ``bytes``
+    :param token_amount: Fungible token amount of the cashtoken
+    :type token_amount: ``int``
+    :returns: None
+    """
+    output = Address.from_string(address).scriptcode + generate_cashtoken_prefix(
+        category_id, nft_capability, nft_commitment, token_amount
+    )
+    return 444 + (8 + len(int_to_varint(len(output))) + len(output)) * 3
+
+
+def verify_cashtoken_output_data(
+    category_id=None, nft_capability=None, nft_commitment=None, token_amount=None
+):
+    """
+    Verifies cashtoken data for an output
+
+    :param category_id: Category hex of the cashtoken
+    :type category_id: ``str``
+    :param nft_capability: Capability of the non-fungible token
+    :type nft_capability: ``str``
+    :param nft_commitment: Commitment bytes of the non-fungible token
+    :type nft_commitment: ``bytes``
+    :param token_amount: Fungible token amount of the cashtoken
+    :type token_amount: ``int``
+    :returns: None
+    """
+    if category_id is None:
+        if nft_capability is not None or token_amount is not None:
+            raise InvalidCashToken("category_id missing")
+    else:
+        if token_amount is None and nft_capability is None:
+            raise InvalidCashToken("CashToken must have either amount or capability")
+
+    if nft_capability is not None and nft_capability not in Unspent.NFT_CAPABILITY:
+        raise InvalidCashToken(f"nft capability not in {Unspent.NFT_CAPABILITY}")
+    if nft_commitment is not None:
+        if nft_capability is None:
+            raise InvalidCashToken("nft commitment found without nft capability")
+        if not isinstance(nft_commitment, bytes):
+            raise ValueError("expected nft_commitment as bytes")
+        if len(nft_commitment) > COMMITMENT_LENGTH or len(nft_commitment) == 0:
+            raise InvalidCashToken(
+                f"0 < valid nft commitment length"
+                f" <= {COMMITMENT_LENGTH}, received"
+                f" length: {len(nft_commitment)}"
+            )
+    if token_amount is not None and (
+        token_amount > 9223372036854775807 or token_amount < 1
+    ):
+        raise InvalidCashToken("1 <= valid token amount <= 9223372036854775807")
+
+
+def parse_cashtoken_prefix(script):
+    """
+    Parses cashtoken prefix
+
+    :param script: Token prefix with OP_TOKENPREFIX
+    :type script: ``bytes``
+    :returns: Tuple of category_id, nft_capability, nft_commitment, token_amount
+    :rtype: ``tuple``
+    """
+    # Assumes valid script
+    category_id = None
+    nft_capability = None
+    nft_commitment = None
+    token_amount = None
+
+    has_commitment_length = False
+    has_nft = False
+    has_amount = False
+
+    # make bytestream
+    stream = io.BytesIO(script)
+
+    if stream.read(1) != OpCodes.OP_TOKENPREFIX.binary:
+        # no token info available
+        return (category_id, nft_capability, nft_commitment, token_amount)
+
+    # OP_HASH256 byte order
+    category_id = stream.read(32)[::-1].hex()
+
+    token_bitfield = stream.read(1).hex()
+    # 4 bit prefix
+    _ = bin(int(token_bitfield[0], 16))[2:]
+    _ = "0" * (4 - len(_)) + _
+    prefix_structure = [bit == "1" for bit in _]
+    if prefix_structure[1]:
+        has_commitment_length = True
+    if prefix_structure[2]:
+        has_nft = True
+    if prefix_structure[3]:
+        has_amount = True
+
+    nft_capability_bit = int(token_bitfield[1], 16)
+    if has_nft:
+        nft_capability = Unspent.NFT_CAPABILITY[nft_capability_bit]
+    if has_commitment_length:
+        commitment_length = varint_to_int(stream)
+        nft_commitment = stream.read(commitment_length)
+    if has_amount:
+        token_amount = varint_to_int(stream)
+
+    return (category_id, nft_capability, nft_commitment, token_amount)
+
+
+def generate_cashtoken_prefix(
+    category_id=None, nft_capability=None, nft_commitment=None, token_amount=None
+):
+    """
+    Generates cashtoken prefix from cashtoken data
+
+    :param category_id: Category hex of the cashtoken
+    :type category_id: ``str``
+    :param nft_capability: Capability of the non-fungible token
+    :type nft_capability: ``str``
+    :param nft_commitment: Commitment bytes of the non-fungible token
+    :type nft_commitment: ``bytes``
+    :param token_amount: Fungible token amount of the cashtoken
+    :type token_amount: ``int``
+    :returns: Cahstoken prefix
+    :rtype: ``bytes``
+    """
+    if category_id is None:
+        return b""
+
+    # OP_HASH256 byte order
+    script = OpCodes.OP_TOKENPREFIX.binary + bytes.fromhex(category_id)[::-1]
+    prefix_structure = 0
+    if nft_commitment is not None:
+        prefix_structure += 4
+    if nft_capability is not None:
+        prefix_structure += 2
+    if token_amount is not None:
+        prefix_structure += 1
+    nft_capability = (
+        0 if nft_capability is None else Unspent.NFT_CAPABILITY.index(nft_capability)
+    )
+    # token bitfield
+    token_bitfield = hex(prefix_structure)[2:] + hex(nft_capability)[2:]
+    script += bytes.fromhex(token_bitfield)
+    if nft_commitment is not None:
+        script += int_to_varint(len(nft_commitment))
+        script += nft_commitment
+    if token_amount is not None:
+        script += int_to_varint(token_amount)
+
+    return script
+
+
+def prepare_output(output):
+    """
+    Prepares output for sending transaction
+
+    :param output: Output tuple of format: (destination address, amount, currency) or
+                   (destination address, amount, currency, category_id, nft_capability,
+                   nft_commitment, token_amount)
+    :type output: ``tuple``
+    :returns: Prepared output tuple of format (scriptcode with token prefix, amount in
+              satoshis, category_id, nft_capability, nft_commitment, token_amount)
+    :rtype: ``tuple``
+    """
+    if len(output) == 3:
+        output = (*output, None, None, None, None)
+    elif len(output) == 6 and isinstance(output[0], bytes):
+        # already prepared
+        return output
+    elif len(output) != 7:
+        raise RuntimeError(
+            "Output does not follow output format: (address, amount, currency) or "
+            "(address, amount, currency, category_id, nft_capability, nft_commitment, "
+            "token_amount)"
+        )
+
+    (
+        dest,
+        amount,
+        currency,
+        category_id,
+        nft_capability,
+        nft_commitment,
+        token_amount,
+    ) = output
+
+    if not isinstance(dest, Address):
+        dest = Address.from_string(dest)
+
+    amount = currency_to_satoshi_cached(amount, currency)
+
+    # check dust limit
+    dust = _calculate_dust_value(output[0], *output[3:])
+    if amount < dust:
+        raise InsufficientFunds(f"{amount=} less than {dust=} limit")
+
+    # verify valid cashtokens
+    verify_cashtoken_output_data(
+        category_id, nft_capability, nft_commitment, token_amount
+    )
+
+    # check for CashToken signal
+    if "CATKN" not in dest.version and category_id is not None:
+        raise InvalidAddress(
+            f"{dest.cash_address()} does not signal CashToken support."
+        )
+
+    return (
+        (
+            generate_cashtoken_prefix(
+                category_id, nft_capability, nft_commitment, token_amount
+            )
+            + dest.scriptcode
+        ),
+        amount,
+        category_id,
+        nft_capability,
+        nft_commitment,
+        token_amount,
+    )
+
+
+class Unspents:
+    """
+    Class to count Unspents with cashtokens
+    Incoming data is assumed to be valid, tests are performed when making
+    outputs
+
+    >>> unspents.tokendata = {
+            "category_id": {           (string) token id hex
+                "token_amount": "xxx", (int) fungible amount
+                "nft" : [{
+                  "capability": "xxx", (string) one of "none", "mutable",
+                                        "minting"
+                  "commitment": b"xxx" (bytes) NFT commitment
+                }]
+            }
+        }
+    """
+
+    def __init__(self, unspents=None):
+        self.amount = 0
+        self.tokendata = {}
+        # unspent txid that are valid genesis unspent
+        self.genesis_unspent_txid = []
+        if unspents is not None:
+            for unspent in unspents:
+                self.add_unspent(unspent)
+
+    def to_dict(self):
+        return {"amount": self.amount, "tokendata": self.tokendata}
+
+    @classmethod
+    def from_dict(cls, dict_):
+        instance = cls([])
+        instance.amount = dict_["amount"]
+        instance.tokendata = dict_["tokendata"]
+        return instance
+
+    def add_unspent(self, unspent):
+        """
+        Adds unspent
+
+        :param unspent: An instance of Unspent to add
+        :type unspent: Unspent
+        :returns: None
+        """
+        self.amount += unspent.amount
+        if unspent.has_cashtoken:
+            categorydata = self.tokendata.get(unspent.category_id, {})
+            if unspent.has_amount:
+                categorydata["token_amount"] = (
+                    categorydata.get("token_amount", 0) + unspent.token_amount
+                )
+            if unspent.has_nft:
+                nftdata = {"capability": unspent.nft_capability}
+                if unspent.nft_commitment is not None:
+                    nftdata["commitment"] = unspent.nft_commitment
+                categorydata["nft"] = categorydata.get("nft", []) + [nftdata]
+            self.tokendata.update({unspent.category_id: categorydata})
+
+        # possible cashtoken genesis unspent
+        if unspent.txindex == 0:
+            self.genesis_unspent_txid.append(unspent.txid)
+
+    def get_outputs(self, leftover):
+        """
+        Return sanitized outputs for the remaining cashtokens
+
+        :param leftover: Leftover address to add the outputs
+        :type leftover: ``str``
+        :rtype: tuple(``list``, ``int``)  # (outputs, leftover_amount)
+        """
+        outputs = []
+
+        amount = self.amount
+
+        for category_id, value in self.tokendata.items():
+            token_amount = None
+            if "token_amount" in value:
+                token_amount = value["token_amount"]
+            if "nft" in value:
+                for i, nft in enumerate(value["nft"]):
+                    nft_capability = nft["capability"]
+                    nft_commitment = nft.get("commitment", None)
+                    dust_value = _calculate_dust_value(
+                        leftover,
+                        category_id,
+                        nft_capability,
+                        nft_commitment,
+                        token_amount,
+                    )
+                    outputs.append(
+                        prepare_output(
+                            (
+                                leftover,
+                                dust_value,
+                                "satoshi",
+                                category_id,
+                                nft_capability,
+                                nft_commitment,
+                                token_amount,
+                            )
+                        )
+                    )
+                    # add token to first nft
+                    token_amount = None
+                    amount -= dust_value
+            elif token_amount is not None:
+                # token_amount but no nft
+                dust_value = _calculate_dust_value(
+                    leftover, category_id, None, None, token_amount
+                )
+                outputs.append(
+                    prepare_output(
+                        (
+                            leftover,
+                            dust_value,
+                            "satoshi",
+                            category_id,
+                            None,
+                            None,
+                            token_amount,
+                        )
+                    )
+                )
+                amount -= dust_value
+
+        if len(outputs) == 0:
+            # no tokendata
+            if amount > 0:
+                # add leftover amount
+                outputs.append(prepare_output((leftover, amount, "satoshi")))
+        else:
+            if amount < 0:
+                raise InsufficientFunds("Not enough sats")
+            # add leftover amount to last out
+            last_out = list(outputs[-1])
+            last_out[1] += amount
+            outputs[-1] = tuple(last_out)
+
+        return outputs, amount
+
+    def subtract_output(self, output):
+        """
+        Subtract output from cumulative unspent BCH and cashtoken amounts
+
+        :param output: Prepared output tuple of format (scriptcode with token prefix,
+                       amount in satoshis, category_id, nft_capability, nft_commitment,
+                       token_amount)
+        :type output: ``tuple``
+        :returns: None
+        """
+        output = prepare_output(output)
+        _, amount, category_id, nft_capability, nft_commitment, token_amount = output
+        if self.amount < amount:
+            raise InsufficientFunds("Not enough amount")
+        self.amount -= amount
+
+        if category_id is not None:
+            if category_id in self.genesis_unspent_txid:
+                # new token generated
+                # only amount to be subtracted, the cashtoken doesn't exist in UTXO
+                return
+            if category_id not in self.tokendata.keys():
+                raise InsufficientFunds("unspent category_id does not exist")
+            categorydata = self.tokendata[category_id]
+            if token_amount is not None:
+                categorydata = _subtract_token_amount(categorydata, token_amount)
+            if nft_capability is not None:
+                nft = [nft_capability, nft_commitment or "None"]
+                categorydata = _subtract_nft(categorydata, nft)
+
+            # update tokendata
+            if categorydata == {}:
+                self.tokendata.pop(category_id)
+            else:
+                self.tokendata.update({category_id: categorydata})
+
+
+def _subtract_token_amount(categorydata, token_amount):
+    if "token_amount" not in categorydata:
+        raise InsufficientFunds("No token amount")
+    if categorydata["token_amount"] < token_amount:
+        raise InsufficientFunds("Not enough token amount")
+    categorydata["token_amount"] -= token_amount
+
+    if "token_amount" in categorydata and categorydata["token_amount"] == 0:
+        categorydata.pop("token_amount")
+    return categorydata
+
+
+def _subtract_nft(categorydata, nft):
+    """
+    nft: [capability, commitment]
+    """
+    if "nft" not in categorydata:
+        raise InsufficientFunds("No nft found")
+    # if immutable nft is asked, then immutable nft is spent
+    # then a mutable nft is made to immutable, then minting
+    # mints new nft.
+    # if mutable nft is asked, then mutable nft is spent, then
+    # minting mints new nft.
+    # if minting nft is asked, then minting nft mints new.
+
+    if nft[0] in ["none"]:
+        # immutable
+        try:
+            return _subtract_immutable_nft(categorydata, nft[1])
+        except InsufficientFunds:
+            pass
+
+    if nft[0] in ["none", "mutable"]:
+        try:
+            return _subtract_mutable_nft(categorydata)
+        except InsufficientFunds:
+            pass
+
+    if nft[0] in ["none", "mutable", "minting"]:
+        try:
+            return _subtract_minting_nft(categorydata)
+        except InsufficientFunds:
+            # none found
+            raise InsufficientFunds("No capable nft found")
+
+
+def _sanitize(categorydata):
+    if "nft" in categorydata and len(categorydata["nft"]) == 0:
+        categorydata.pop("nft")
+    return categorydata
+
+
+def _subtract_immutable_nft(categorydata, commitment):
+    nft_capabilities = [_["capability"] for _ in categorydata["nft"]]
+    nft_commitments = [_.get("commitment", "None") for _ in categorydata["nft"]]
+
+    # find an immutable to send
+    for i in range(len(categorydata["nft"])):
+        if nft_capabilities[i] == "none" and nft_commitments[i] == commitment:
+            # found immutable with same commitment
+            categorydata["nft"].pop(i)
+            return _sanitize(categorydata)
+
+    raise InsufficientFunds("No immutable nft")
+
+
+def _subtract_mutable_nft(categorydata):
+    nft_capabilities = [_["capability"] for _ in categorydata["nft"]]
+    # find a mutable to send
+    for i in range(len(categorydata["nft"])):
+        if nft_capabilities[i] == "mutable":
+            # found mutable
+            categorydata["nft"].pop(i)
+            return _sanitize(categorydata)
+
+    raise InsufficientFunds("No mutable nft")
+
+
+def _subtract_minting_nft(categorydata):
+    nft_capabilities = [_["capability"] for _ in categorydata["nft"]]
+    # find a minting to mint
+    for i in range(len(categorydata["nft"])):
+        if nft_capabilities[i] == "minting":
+            # found minting
+            return categorydata
+
+    raise InsufficientFunds("No minting nft")
+
+
+def select_cashtoken_utxo(unspents, outputs):
+    """
+    Function to select unspents that cover cashtokens of prepared outputs
+
+    :param unspents: List of unspents to select from
+    :type unspents: ``list``
+    :param outputs: List of prepared outputs to cover cashtokens of
+    :type outputs: ``list``
+    :returns: Tuple of leftover unspents and unspents used to cover given outputs
+    :rtype: ``tuple``
+    """
+    unspents_used = []
+    outputs = [prepare_output(output) for output in outputs]
+
+    # if category id is txid of genesis unspent, then the unspent is mandatory
+    mandatory_unspent_indices = set()
+    genesis_unspent_txid = {
+        unspent.txid: i for i, unspent in enumerate(unspents) if unspent.txindex == 0
+    }
+
+    # tokendata in outputs
+    tokendata = {}
+
+    # calculate needed cashtokens
+    for output in outputs:
+        category_id, nft_capability, nft_commitment, token_amount = output[2:]
+        if category_id is not None:
+            if category_id in genesis_unspent_txid.keys():
+                indx = genesis_unspent_txid[category_id]
+                mandatory_unspent_indices.add(indx)
+                # not count cashtoken from genesis tx
+                # the category id won't be in utxo
+                continue
+            categorydata = tokendata.get(category_id, {})
+            if token_amount is not None:
+                categorydata["token_amount"] = (
+                    categorydata.get("token_amount", 0) + token_amount
+                )
+            if nft_capability is not None:
+                nftdata = {"capability": nft_capability}
+                if nft_commitment is not None:
+                    nftdata["commitment"] = nft_commitment
+                categorydata["nft"] = categorydata.get("nft", []) + [nftdata]
+            tokendata.update({category_id: categorydata})
+
+    # add mandatory unspents, for genesis cashtoken
+    for id_ in sorted(mandatory_unspent_indices)[::-1]:
+        unspents_used.append(unspents.pop(id_))
+
+    # add utxo that can fund the output tokendata
+    # split unspent with cashtoken from rest
+    unspents_cashtoken = []
+    pop_ids = []
+    for i, unspent in enumerate(unspents):
+        if unspent.has_cashtoken:
+            unspents_cashtoken.append(unspent)
+            pop_ids.append(i)
+    for id_ in sorted(pop_ids)[::-1]:
+        unspents.pop(id_)
+
+    # sort and use required cashtoken unspents
+    # cashtokens are selected with the same criteria as utxo selection for BCH
+    # small token_amount is spent first, and for nft the order is to spend an
+    # immutable if possible, or then spend a mutable with mutation or then
+    # finally use a minting token to mint the output nft.
+    unspents_cashtoken = sorted(unspents_cashtoken)
+    pop_ids = []
+    for i, unspent in enumerate(unspents_cashtoken):
+        unspent_used = False
+
+        categorydata = tokendata.get(unspent.category_id, {})
+        # check token_amount
+        if unspent.has_amount and "token_amount" in categorydata:
+            unspent_used = True
+            categorydata["token_amount"] -= unspent.token_amount
+            if categorydata["token_amount"] <= 0:
+                categorydata.pop("token_amount")
+
+        # check nft
+        if unspent.has_nft and "nft" in categorydata:
+            categorydata, nft_used = _subtract_nft_output(unspent, categorydata)
+            if nft_used:
+                unspent_used = True
+
+        if not unspent_used:
+            continue
+
+        # use unspent
+        unspents_used.append(unspent)
+        pop_ids.append(i)
+        # update tokendata
+        if categorydata == {}:
+            tokendata.pop(unspent.category_id)
+        else:
+            tokendata.update({unspent.category_id: categorydata})
+    for id_ in sorted(pop_ids)[::-1]:
+        unspents_cashtoken.pop(id_)
+
+    # sort the rest unspents and fund the bch amount
+    # __gt__ and __eq__ will sort them with no cashtoken unspents first
+    unspents = sorted(unspents + unspents_cashtoken)
+    return unspents, unspents_used
+
+
+def _subtract_nft_output(unspent, categorydata):
+    if unspent.nft_capability == "minting":
+        # minting pays all
+        categorydata.pop("nft")
+        return _sanitize(categorydata), True
+    elif unspent.nft_capability == "mutable":
+        # pays first mutable, or first immutable
+        for i, nft in enumerate(categorydata["nft"]):
+            if nft["capability"] == "mutable":
+                categorydata["nft"].pop(i)
+                return _sanitize(categorydata), True
+        else:
+            for i, nft in enumerate(categorydata["nft"]):
+                if nft["capability"] == "none":
+                    categorydata["nft"].pop(i)
+                    return _sanitize(categorydata), True
+    else:  # immutable
+        nft_commitment = unspent.nft_commitment or "None"
+        for i, nft in enumerate(categorydata["nft"]):
+            if nft["capability"] == "none" and nft_commitment == nft.get(
+                "commitment", "None"
+            ):
+                categorydata["nft"].pop(i)
+                return _sanitize(categorydata), True
+    return categorydata, False
diff --git a/bitcash/exceptions.py b/bitcash/exceptions.py
index 476834fe..5efbe450 100644
--- a/bitcash/exceptions.py
+++ b/bitcash/exceptions.py
@@ -12,3 +12,7 @@ class InvalidNetwork(Exception):
 
 class InvalidEndpointURLProvided(Exception):
     pass
+
+
+class InvalidCashToken(ValueError):
+    pass
diff --git a/bitcash/format.py b/bitcash/format.py
index a13e5d56..3d87fa6b 100644
--- a/bitcash/format.py
+++ b/bitcash/format.py
@@ -4,7 +4,7 @@
 from bitcash.cashaddress import Address
 from bitcash.crypto import ripemd160_sha256
 from bitcash.curve import x_to_y
-from bitcash.exceptions import InvalidAddress
+from bitcash.op import OpCodes
 
 MAIN_PUBKEY_HASH = b"\x00"
 MAIN_SCRIPT_HASH = b"\x05"
@@ -160,3 +160,93 @@ def coords_to_public_key(x, y, compressed=True):
 
 def point_to_public_key(point, compressed=True):
     return coords_to_public_key(point.x, point.y, compressed)
+
+
+def address_to_cashtokenaddress(address):
+    """
+    Converts regular cashaddress to cashtoken signalling address
+
+    :param address: Cashaddress
+    :type address: ``str``
+    :returns: Cashtoken signalling cashaddress
+    :rtype: ``str``
+    """
+    address = Address.from_string(address)
+    if "CATKN" in address.version:
+        return address.cash_address()
+    version = address.version.split("-")
+    version.insert(1, "CATKN")
+    address.version = "-".join(version)
+    return address.cash_address()
+
+
+def cashtokenaddress_to_address(address):
+    """
+    Converts cashtoken signalling cashaddress to regular cashaddress
+
+    :param address: Cashtoken signalling cashaddress
+    :type address: ``str``
+    :returns: Cashaddress
+    :rtype: ``str``
+    """
+    address = Address.from_string(address)
+    if "CATKN" not in address.version:
+        return address.cash_address()
+    version = address.version.split("-")
+    version.pop(1)
+    address.version = "-".join(version)
+    return address.cash_address()
+
+
+def hex_to_asm(data):
+    def _add_value(next_len, indx):
+        next_len *= 2  # hex byte
+        # !TODO: add Signature hash type delineation
+        value = data[indx : indx + next_len]
+        if len(value) != next_len:
+            raise RuntimeError("Data ended prematurely")
+        indx += next_len
+        return value, indx
+
+    indx = 0
+    out = []
+    while indx < len(data):
+        op_code = data[indx : indx + 2]
+        op_code = OpCodes(int(op_code, 16))
+        if op_code == OpCodes.OP_PUSHDATA1:
+            indx += 2
+            next_len = int(data[indx : indx + 2], 16)
+            indx += 2
+            value, indx = _add_value(next_len, indx)
+        elif op_code == OpCodes.OP_PUSHDATA2:
+            indx += 2
+            a = data[indx : indx + 2]
+            indx += 2
+            b = data[indx : indx + 2]
+            next_len = int(b + a, 16)
+            indx += 2
+            value, indx = _add_value(next_len, indx)
+        elif op_code == OpCodes.OP_PUSHDATA4:
+            indx += 2
+            a = data[indx : indx + 2]
+            indx += 2
+            b = data[indx : indx + 2]
+            indx += 2
+            c = data[indx : indx + 2]
+            indx += 2
+            d = data[indx : indx + 2]
+            next_len = int(d + c + b + a, 16)
+            indx += 2
+            value, indx = _add_value(next_len, indx)
+        elif op_code.name.startswith("OP_DATA"):
+            next_len = int(data[indx : indx + 2], 16)
+            indx += 2
+            value, indx = _add_value(next_len, indx)
+            if next_len <= 8:
+                # !TODO: check implementation
+                value = str(int.from_bytes(bytes.fromhex(value), "little"))
+        else:
+            indx += 2
+            value = op_code.name
+        out.append(value)
+    return " ".join(out)
diff --git a/bitcash/network/APIs/BitcoinDotComAPI.py b/bitcash/network/APIs/BitcoinDotComAPI.py
index 67e185a0..d73cb3fa 100644
--- a/bitcash/network/APIs/BitcoinDotComAPI.py
+++ b/bitcash/network/APIs/BitcoinDotComAPI.py
@@ -2,8 +2,10 @@
 from decimal import Decimal
 from bitcash.exceptions import InvalidEndpointURLProvided
 from bitcash.network import currency_to_satoshi
+from bitcash.network.APIs import BaseAPI
 from bitcash.network.meta import Unspent
 from bitcash.network.transaction import Transaction, TxPart
+from bitcash.format import cashtokenaddress_to_address
 
 # This class is the interface for Bitcash to interact with
 # Bitcoin.com based RESTful interfaces.
@@ -12,7 +14,7 @@
 # TODO: Refactor constant above into a 'constants.py' file
 
 
-class BitcoinDotComAPI:
+class BitcoinDotComAPI(BaseAPI):
     """rest.bitcoin.com API"""
 
     def __init__(self, network_endpoint: str):
@@ -22,7 +24,8 @@ def __init__(self, network_endpoint: str):
             assert network_endpoint[-4:] == "/v2/"
         except AssertionError:
             raise InvalidEndpointURLProvided(
-                f"Provided endpoint '{network_endpoint}' is not a valid URL for a Bitcoin.com-based REST endpoint"
+                f"Provided endpoint '{network_endpoint}' is not a valid URL for a "
+                f"Bitcoin.com-based REST endpoint"
             )
 
         self.network_endpoint = network_endpoint
@@ -53,6 +56,7 @@ def make_endpoint_url(self, path):
         return self.network_endpoint + self.PATHS[path]
 
     def get_balance(self, address, *args, **kwargs):
+        address = cashtokenaddress_to_address(address)
         api_url = self.make_endpoint_url("address").format(address)
         r = session.get(api_url, *args, **kwargs)
         r.raise_for_status()
@@ -60,6 +64,7 @@ def get_balance(self, address, *args, **kwargs):
         return data["balanceSat"] + data["unconfirmedBalanceSat"]
 
     def get_transactions(self, address, *args, **kwargs):
+        address = cashtokenaddress_to_address(address)
         api_url = self.make_endpoint_url("address").format(address)
         r = session.get(api_url, *args, **kwargs)
         r.raise_for_status()
@@ -73,14 +78,30 @@ def get_transaction(self, txid, *args, **kwargs):
 
         tx = Transaction(
             response["txid"],
-            response["blockheight"],
-            (Decimal(response["valueIn"]) * BCH_TO_SAT_MULTIPLIER).normalize(),
-            (Decimal(response["valueOut"]) * BCH_TO_SAT_MULTIPLIER).normalize(),
-            (Decimal(response["fees"]) * BCH_TO_SAT_MULTIPLIER).normalize(),
+            response.get("blockheight", None),
+            int(
+                (
+                    Decimal(response["valueIn"]) * BCH_TO_SAT_MULTIPLIER
+                ).to_integral_value()
+            ),
+            int(
+                (
+                    Decimal(response["valueOut"]) * BCH_TO_SAT_MULTIPLIER
+                ).to_integral_value()
+            ),
+            int(
+                (Decimal(response["fees"]) * BCH_TO_SAT_MULTIPLIER).to_integral_value()
+            ),
         )
 
         for txin in response["vin"]:
-            part = TxPart(txin["cashAddress"], txin["value"], txin["scriptSig"]["asm"])
+            part = TxPart(
+                txin["cashAddress"],
+                int(
+                    (Decimal(txin["value"]) * BCH_TO_SAT_MULTIPLIER).to_integral_value()
+                ),
+                asm=txin["scriptSig"]["asm"],
+            )
             tx.add_input(part)
 
         for txout in response["vout"]:
@@ -91,10 +112,29 @@ def get_transaction(self, txid, *args, **kwargs):
             ):
                 addr = txout["scriptPubKey"]["cashAddrs"][0]
 
+            category_id = None
+            nft_capability = None
+            nft_commitment = None
+            token_amount = None
+            if "tokenData" in txout:
+                token_data = txout["tokenData"]
+                category_id = token_data["category"]
+                token_amount = int(token_data["amount"]) or None
+                if "nft" in token_data:
+                    nft_capability = token_data["nft"]["capability"]
+                    nft_commitment = token_data["nft"]["commitment"] or None
             part = TxPart(
                 addr,
-                (Decimal(txout["value"]) * BCH_TO_SAT_MULTIPLIER).normalize(),
-                txout["scriptPubKey"]["asm"],
+                int(
+                    (
+                        Decimal(txout["value"]) * BCH_TO_SAT_MULTIPLIER
+                    ).to_integral_value()
+                ),
+                category_id,
+                nft_capability,
+                nft_commitment,
+                token_amount,
+                asm=txout["scriptPubKey"]["asm"],
             )
             tx.add_output(part)
 
@@ -105,15 +145,57 @@ def get_tx_amount(self, txid, txindex, *args, **kwargs):
         r = session.get(api_url, *args, **kwargs)
         r.raise_for_status()
         response = r.json(parse_float=Decimal)
-        return (
-            Decimal(response["vout"][txindex]["value"]) * BCH_TO_SAT_MULTIPLIER
-        ).normalize()
+        return int(
+            (
+                Decimal(response["vout"][txindex]["value"]) * BCH_TO_SAT_MULTIPLIER
+            ).to_integral_value()
+        )
 
     def get_unspent(self, address, *args, **kwargs):
+        return self._get_unspent_cashtoken(address, *args, **kwargs)
+        address = cashtokenaddress_to_address(address)
+        api_url = self.make_endpoint_url("unspent").format(address)
+        r = session.get(api_url, *args, **kwargs)
+        r.raise_for_status()
+        unspents = []
+        for tx in r.json()["utxos"]:
+            category_id = None
+            nft_capability = None
+            nft_commitment = None
+            token_amount = None
+            if "tokenData" in tx:
+                token_data = tx["tokenData"]
+                category_id = token_data["category"]
+                token_amount = int(token_data["amount"]) or None
+                if "nft" in token_data:
+                    nft_capability = token_data["nft"]["capability"]
+                    _ = token_data["nft"]["commitment"]
+                    nft_commitment = bytes.fromhex(_) or None
+            unspents.append(
+                Unspent(
+                    currency_to_satoshi(tx["amount"], "bch"),
+                    tx["confirmations"],
+                    r.json()["scriptPubKey"],
+                    tx["txid"],
+                    tx["vout"],
+                    category_id,
+                    nft_capability,
+                    nft_commitment,
+                    token_amount,
+                )
+            )
+        return unspents
+
+    def _get_unspent_cashtoken(self, address, *args, **kwargs):
+        """
+        Makeshift function to get cashtoken info in unspents by querying tx details.
+        Should be deprecated once BitcoinDotComAPI supports cashtokens in unspents
+        """
+        address = cashtokenaddress_to_address(address)
         api_url = self.make_endpoint_url("unspent").format(address)
         r = session.get(api_url, *args, **kwargs)
         r.raise_for_status()
-        return [
+        unspents = [
             Unspent(
                 currency_to_satoshi(tx["amount"], "bch"),
                 tx["confirmations"],
@@ -123,6 +205,23 @@ def get_unspent(self, address, *args, **kwargs):
             )
             for tx in r.json()["utxos"]
         ]
+        api_url = self.make_endpoint_url("tx-details").format("")
+        r = session.post(
+            api_url, {"txids": [unspent.txid for unspent in unspents]}, *args, **kwargs
+        )
+        r.raise_for_status()
+        response = r.json(parse_float=Decimal)
+        for i, unspent in enumerate(unspents):
+            txout = response[i]["vout"][unspent.txindex]
+            if "tokenData" in txout:
+                token_data = txout["tokenData"]
+                unspent.category_id = token_data["category"]
+                unspent.token_amount = int(token_data["amount"]) or None
+                if "nft" in token_data:
+                    unspent.nft_capability = token_data["nft"]["capability"]
+                    _ = bytes.fromhex(token_data["nft"]["commitment"])
+                    unspent.nft_commitment = _ or None
+        return unspents
 
     def get_raw_transaction(self, txid, *args, **kwargs):
         api_url = self.make_endpoint_url("tx-details").format(txid)
diff --git a/bitcash/network/APIs/ChaingraphAPI.py b/bitcash/network/APIs/ChaingraphAPI.py
new file mode 100644
index 00000000..a07ccfed
--- /dev/null
+++ b/bitcash/network/APIs/ChaingraphAPI.py
@@ -0,0 +1,454 @@
+from bitcash.network.http import session
+from bitcash.exceptions import InvalidEndpointURLProvided
+from bitcash.network.APIs import BaseAPI
+from bitcash.network.meta import Unspent
+from bitcash.network.transaction import Transaction, TxPart
+from bitcash.cashaddress import Address
+
+
+class ChaingraphAPI(BaseAPI):
+    """ChaingraphAPI API, chaingraph.cash
+
+    :param network_endpoint: The url for the network endpoint
+    :type network_endpoint: ``str``
+    :param node_like: node name to match for with "_like" string comparison expression
+    :type node_like: ``str``
+    """
+
+    def __init__(self, network_endpoint: str, node_like: str = None):
+        try:
+            assert isinstance(network_endpoint, str)
+        except AssertionError:
+            raise InvalidEndpointURLProvided(
+                f"Provided endpoint '{network_endpoint}' is not a valid URL"
+                f" for a Chaingraph-based endpoint"
+            )
+
+        self.network_endpoint = network_endpoint
+        if node_like is None:
+            self.node_like = "%"
+        else:
+            self.node_like = node_like
+
+    # Default endpoints to use for this interface
+    DEFAULT_ENDPOINTS = {
+        "mainnet": [
+            ("https://demo.chaingraph.cash/v1/graphql", "%mainnet"),
+            ("https://gql.chaingraph.pat.mn/v1/graphql", "%mainnet"),
+        ],
+        "testnet": [
+            ("https://demo.chaingraph.cash/v1/graphql", "%testnet"),
+            ("https://gql.chaingraph.pat.mn/v1/graphql", "%testnet"),
+        ],
+        "regtest": [],
+    }
+
+    def send_request(self, json_request, *args, **kwargs):
+        """Send json request and return receiving json"""
+        r = session.post(self.network_endpoint, json=json_request, *args, **kwargs)
+        r.raise_for_status()
+        json = r.json()
+        if "errors" in json:
+            raise RuntimeError(json)
+        return json
+
+    @classmethod
+    def get_default_endpoints(cls, network):
+        return cls.DEFAULT_ENDPOINTS[network]
+
+    def get_balance(self, address, *args, **kwargs):
+        json_request = {
+            "query": """
+query GetUTXO($lb: _text, $node: String!) {
+  search_output(
+    args: { locking_bytecode_hex: $lb }
+    where: {
+      _not: { spent_by: {} }
+      _or: [
+        {
+          transaction: {
+            node_validations: { node: { name: { _like: $node } } }
+          }
+        }
+        {
+          transaction: {
+            block_inclusions: {
+              block: { accepted_by: { node: { name: { _like: $node } } } }
+            }
+          }
+        }
+      ]
+    }
+  ) {
+    value_satoshis
+  }
+}
+""",
+            "variables": {
+                "lb": f"{{{Address.from_string(address).scriptcode.hex()}}}",
+                "node": self.node_like,
+            },
+        }
+        json = self.send_request(json_request, *args, **kwargs)
+        data = json["data"]["search_output"]
+        return sum([int(_["value_satoshis"]) for _ in data])
+
+    def get_transactions(self, address, *args, **kwargs):
+        json_request = {
+            "query": """
+query GetOutputs($lb: _text!, $node: String!) {
+  block(
+    limit: 1
+    order_by: { height: desc }
+    where: { accepted_by: { node: { name: { _like: $node } } } }
+  ) {
+    height
+  }
+  search_output(
+    args: { locking_bytecode_hex: $lb }
+    where: {
+      _or: [
+        {
+          transaction: {
+            node_validations: { node: { name: { _like: $node } } }
+          }
+        }
+        {
+          transaction: {
+            block_inclusions: {
+              block: { accepted_by: { node: { name: { _like: $node } } } }
+            }
+          }
+        }
+      ]
+    }
+  ) {
+    transaction_hash
+    transaction {
+      block_inclusions {
+        block {
+          height
+        }
+      }
+    }
+    spent_by {
+      transaction {
+        hash
+        block_inclusions {
+          block {
+            height
+          }
+        }
+      }
+    }
+  }
+}
+""",
+            "variables": {
+                "lb": f"{{{Address.from_string(address).scriptcode.hex()}}}",
+                "node": self.node_like,
+            },
+        }
+        json = self.send_request(json_request, *args, **kwargs)
+        blockheight = int(json["data"]["block"][0]["height"])
+        transactions = []
+        for output in json["data"]["search_output"]:
+            # outputs
+            block_inclusions = output["transaction"]["block_inclusions"]
+            if len(block_inclusions) == 0:
+                # assume next block confirmation,
+                # only needed to sort transactions
+                height = blockheight + 1
+            else:
+                height = int(block_inclusions[0]["block"]["height"])
+            transactions.append((output["transaction_hash"][2:], height))
+            # inputs
+            if len(output["spent_by"]) == 0:
+                # unspent
+                continue
+            input_ = output["spent_by"][0]["transaction"]
+            block_inclusions = input_["block_inclusions"]
+            if len(block_inclusions) == 0:
+                height = blockheight + 1
+            else:
+                height = int(block_inclusions[0]["block"]["height"])
+            transactions.append((input_["hash"][2:], height))
+        # sort by block height
+        transactions.sort(key=lambda x: x[1])
+        transactions = [_[0] for _ in transactions][::-1]
+        # remove duplicates, when address pays itself, spending tx and locking
+        # tx are same transactions
+        transactions = sorted(set(transactions), key=lambda x: transactions.index(x))
+        return transactions
+
+    def get_transaction(self, txid, *args, **kwargs):
+        response = self.get_raw_transaction(txid, *args, **kwargs)
+
+        block_inclusions = response["block_inclusions"]
+        if len(block_inclusions) == 0:
+            height = None
+        else:
+            height = int(block_inclusions[0]["block"]["height"])
+
+        tx = Transaction(
+            response["hash"][2:],
+            height,
+            int(response["input_value_satoshis"]),
+            int(response["output_value_satoshis"]),
+            int(response["fee_satoshis"]),
+        )
+
+        for part_name in ["inputs", "outputs"]:
+            for txpart in response[part_name]:
+                sats = int(txpart["value_satoshis"])
+                data_hex = txpart[
+                    "{}locking_bytecode".format("un" if part_name == "inputs" else "")
+                ][2:]
+                # switching to outpoint for inputs
+                if part_name == "inputs":
+                    txpart = txpart["outpoint"]
+                try:
+                    scriptcode = bytes.fromhex(txpart["locking_bytecode"][2:])
+                    cashaddress = Address.from_script(scriptcode)
+                    cashaddress = cashaddress.cash_address()
+                except ValueError:
+                    cashaddress = None
+                part = TxPart(cashaddress, sats, data_hex=data_hex)
+                # adding token data
+                token_category = txpart["token_category"]
+                if token_category:
+                    part.category_id = token_category[2:]
+                part.nft_capability = txpart["nonfungible_token_capability"]
+                nft_commitment = txpart["nonfungible_token_commitment"]
+                if nft_commitment:
+                    part.nft_commitment = bytes.fromhex(nft_commitment[2:]) or None
+                token_amount = txpart["fungible_token_amount"]
+                if token_amount:
+                    part.token_amount = int(token_amount) or None
+                # adding to transaction
+                if part_name == "inputs":
+                    tx.add_input(part)
+                else:
+                    tx.add_output(part)
+
+        return tx
+
+    def get_tx_amount(self, txid, txindex, *args, **kwargs):
+        json_request = {
+            "query": """
+query GetOutput($tx: bytea!, $txind: bigint!, $node: String!) {
+  output(
+    where: {
+      transaction_hash: { _eq: $tx }
+      output_index: { _eq: $txind }
+      _or: [
+        {
+          transaction: {
+            block_inclusions: {
+              block: { accepted_by: { node: { name: { _like: $node } } } }
+            }
+          }
+        }
+        {
+          transaction: {
+            node_validations: { node: { name: { _like: $node } } }
+          }
+        }
+      ]
+    }
+  ) {
+    value_satoshis
+  }
+}
+""",
+            "variables": {"tx": f"\\x{txid}", "txind": txindex, "node": self.node_like},
+        }
+        json = self.send_request(json_request, *args, **kwargs)
+        if len(json["data"]["output"]) == 0:
+            raise RuntimeError(f"Output {txid}:{txindex} does not exist")
+        return int(json["data"]["output"][0]["value_satoshis"])
+
+    def get_unspent(self, address, *args, **kwargs):
+        json_request = {
+            "query": """
+query GetUTXO($lb: _text!, $node: String!) {
+  block(
+    limit: 1
+    order_by: { height: desc }
+    where: { accepted_by: { node: { name: { _like: $node } } } }
+  ) {
+    height
+  }
+  search_output(
+    args: { locking_bytecode_hex: $lb }
+    where: {
+      _not: { spent_by: {} }
+      _or: [
+        {
+          transaction: {
+            node_validations: { node: { name: { _like: $node } } }
+          }
+        }
+        {
+          transaction: {
+            block_inclusions: {
+              block: { accepted_by: { node: { name: { _like: $node } } } }
+            }
+          }
+        }
+      ]
+    }
+  ) {
+    transaction_hash
+    output_index
+    value_satoshis
+    token_category
+    fungible_token_amount
+    nonfungible_token_capability
+    nonfungible_token_commitment
+    locking_bytecode
+    transaction {
+      block_inclusions {
+        block {
+          height
+        }
+      }
+    }
+  }
+}
+""",
+            "variables": {
+                "lb": f"{{{Address.from_string(address).scriptcode.hex()}}}",
+                "node": self.node_like,
+            },
+        }
+        data = self.send_request(json_request, *args, **kwargs)["data"]
+        blockheight = int(data["block"][0]["height"])
+        unspents = []
+        for utxo in data["search_output"]:
+            block_inclusions = utxo["transaction"]["block_inclusions"]
+            if len(block_inclusions) == 0:
+                # unconfirmed
+                confirmations = 0
+            else:
+                confirmations = (
+                    -int(block_inclusions[0]["block"]["height"]) + blockheight + 1
+                )
+            token_category = utxo["token_category"]
+            if token_category:
+                token_category = token_category[2:]
+            nft_commitment = utxo["nonfungible_token_commitment"]
+            if nft_commitment:
+                nft_commitment = bytes.fromhex(nft_commitment[2:]) or None
+            token_amount = utxo["fungible_token_amount"]
+            if token_amount:
+                token_amount = int(token_amount)
+            # add unspent
+            unspents.append(
+                Unspent(
+                    int(utxo["value_satoshis"]),
+                    confirmations,
+                    utxo["locking_bytecode"][2:],
+                    utxo["transaction_hash"][2:],
+                    int(utxo["output_index"]),
+                    token_category,
+                    utxo["nonfungible_token_capability"],
+                    nft_commitment or None,  # b"" is None
+                    token_amount or None,  # 0 amount is None
+                )
+            )
+        return unspents
+
+    def get_raw_transaction(self, txid, *args, **kwargs):
+        json_request = {
+            "query": """
+query GetTransactionDetails($tx: bytea!, $node: String!) {
+  transaction(
+    where: {
+      hash: { _eq: $tx }
+      _or: [
+        {
+          block_inclusions: {
+            block: { accepted_by: { node: { name: { _like: $node } } } }
+          }
+        }
+        { node_validations: { node: { name: { _like: $node } } } }
+      ]
+    }
+  ) {
+    hash
+    fee_satoshis
+    input_value_satoshis
+    output_value_satoshis
+    block_inclusions {
+      block {
+        height
+      }
+    }
+    inputs(order_by: { input_index: asc }) {
+      value_satoshis
+      unlocking_bytecode
+      outpoint {
+        locking_bytecode
+        token_category
+        nonfungible_token_capability
+        nonfungible_token_commitment
+        fungible_token_amount
+      }
+    }
+    outputs(order_by: { output_index: asc }) {
+      value_satoshis
+      locking_bytecode
+      token_category
+      nonfungible_token_capability
+      nonfungible_token_commitment
+      fungible_token_amount
+    }
+  }
+}
+""",
+            "variables": {"tx": f"\\x{txid}", "node": self.node_like},
+        }
+        json = self.send_request(json_request, *args, **kwargs)
+        if len(json["data"]["transaction"]) == 0:
+            raise RuntimeError(f"Transaction {txid} does not exist")
+        return json["data"]["transaction"][0]
+
+    def broadcast_tx(self, tx_hex, *args, **kwargs):  # pragma: no cover
+        json_request = {
+            "query": """
+query GetNodeId($node: String!){
+  node (
+    where: {name: {_like: $node}}
+  ){
+    internal_id
+  }
+}
+""",
+            "variables": {"node": self.node_like},
+        }
+        node_ids = self.send_request(json_request, *args, **kwargs)["data"]["node"]
+
+        json_request = {
+            "query": """
+mutation BroadcastTx($tx_hex: String!, $node: bigint!){
+  send_transaction (
+    request: { encoded_hex: $tx_hex, node_internal_id:$node}
+  ){
+    validation_success
+    validation_error_message
+    transmission_success
+    transmission_error_message
+  }
+}
+""",
+            "variables": {"tx_hex": tx_hex, "node": None},
+        }
+        for node_id in [_["internal_id"] for _ in node_ids]:
+            json_request["variables"]["node"] = node_id
+            json = self.send_request(json_request, *args, **kwargs)["data"][
+                "send_transaction"
+            ]
+            if json["transmission_success"] and json["validation_success"]:
+                return True
+        return False
diff --git a/bitcash/network/APIs/__init__.py b/bitcash/network/APIs/__init__.py
index e69de29b..be4cce0e 100644
--- a/bitcash/network/APIs/__init__.py
+++ b/bitcash/network/APIs/__init__.py
@@ -0,0 +1,98 @@
+from abc import ABC, abstractmethod
+
+
+class BaseAPI(ABC):
+    """
+    Abstract class for API classes
+
+    :param network_endpoint: Network endpoint to send requests
+    :type network_endpoint: ``str``
+    """
+
+    def __init__(self, network_endpoint: str):
+        self.network_endpoint = network_endpoint
+
+    @abstractmethod
+    def get_default_endpoints(self, network):
+        """
+        Return default endpoints for a network
+
+        :param network: network in ["mainnet", "testnet", "regtest"]
+        :type network: ``str``
+        :returns: List of endpoints
+        :rtype: ``list`` of ``str``
+        """
+
+    @abstractmethod
+    def get_balance(self, address, *args, **kwargs):
+        """
+        Returns balance of an address
+
+        :param address: Cashaddress of the locking script
+        :type address: ``str``
+        :returns: BCH amount in satoshis
+        :rtype: ``int``
+        """
+
+    @abstractmethod
+    def get_transactions(self, address, *args, **kwargs):
+        """Gets the ID of all transactions related to an address.
+
+        :param address: The address in question.
+        :type address: ``str``
+        :rtype: ``list`` of ``str``
+        """
+
+    @abstractmethod
+    def get_tx_amount(self, txid, txindex, *args, **kwargs):
+        """Gets the amount of a given transaction output.
+
+        :param txid: The transaction id in question.
+        :type txid: ``str``
+        :param txindex: The transaction index in question.
+        :type txindex: ``int``
+        :rtype: ``Decimal``
+        """
+
+    @abstractmethod
+    def get_transaction(self, txid, *args, **kwargs):
+        """
+        Returns transaction data of a transaction
+
+        :param txid: Transaction id hex
+        :type txid: ``str``
+        :returns: Instance of class Transaction
+        :rtype: ``Transaction``
+        """
+
+    @abstractmethod
+    def get_unspent(self, address, *args, **kwargs):
+        """
+        Returns list of unspent outputs associated with an address
+
+        :param address: Cashaddress of the locking script
+        :type address: ``str``
+        :returns: List of unspents
+        :rtype: ``list``
+        """
+
+    @abstractmethod
+    def get_raw_transaction(self, txid, *args, **kwargs):
+        """Gets the raw, unparsed transaction details.
+
+        :param txid: The transaction id in question.
+        :type txid: ``str``
+        :rtype: ``Transaction``
+        """
+
+    @abstractmethod
+    def broadcast_tx(self, tx_hex, *args, **kwargs):
+        """
+        Broadcast a raw transaction
+
+        :param tx_hex: The hex representaion of the transaction to be
+                       broadcasted.
+        :type tx_hex: ``str``
+        :return: Boolean indicating if the tx is broadcasted
+        :rtype: ``bool``
+        """
diff --git a/bitcash/network/meta.py b/bitcash/network/meta.py
index 34ca12a1..ab1fd7fb 100644
--- a/bitcash/network/meta.py
+++ b/bitcash/network/meta.py
@@ -4,37 +4,126 @@
 
 
 class Unspent:
-    """Represents an unspent transaction output (UTXO)."""
+    """
+    Represents an unspent transaction output (UTXO) with CashToken
 
-    __slots__ = ("amount", "confirmations", "script", "txid", "txindex")
+    :param amount: Amount in satoshi
+    :type amount: ``int``
+    :param confirmations: Number of confirmations of the UTXO
+    :type confirmations: ``int``
+    :param script: locking bytecode hex of the UTXO, with no cashtoken prefix
+    :type script: ``str``
+    :param txid: txid hex of the transaction of UTXO
+    :type txid: ``str``
+    :param txindex: transaction output index of UTXO
+    :type txindex: ``int``
+    :param category_id: category_id of cashtoken attached to the UTXO
+    :type category_id: ``str``
+    :param nft_capability: nft_capability of the cashtoken attached
+    :type nft_capability: ``str``
+    :param nft_commitment: nft_commitment of the cashtoken attached
+    :type nft_commitment: ``bytes``
+    :param token_amount: fungible token amount of the cashtoken attached
+    :type token_amount: ``int``
+    """
 
-    def __init__(self, amount, confirmations, script, txid, txindex):
+    __slots__ = (
+        "amount",
+        "confirmations",
+        "script",
+        "txid",
+        "txindex",
+        "category_id",
+        "nft_capability",
+        "nft_commitment",
+        "token_amount",
+    )
+
+    NFT_CAPABILITY = ["none", "mutable", "minting"]
+
+    def __init__(
+        self,
+        amount,
+        confirmations,
+        script,
+        txid,
+        txindex,
+        category_id=None,
+        nft_capability=None,
+        nft_commitment=None,
+        token_amount=None,
+    ):
         self.amount = amount
         self.confirmations = confirmations
         self.script = script
         self.txid = txid
         self.txindex = txindex
+        self.category_id = category_id
+        self.nft_capability = nft_capability
+        self.nft_commitment = nft_commitment
+        self.token_amount = token_amount
 
     def to_dict(self):
-        return {attr: getattr(self, attr) for attr in Unspent.__slots__}
+        dict_ = {attr: getattr(self, attr) for attr in Unspent.__slots__}
+        # save nft_commitment as hex
+        if dict_["nft_commitment"] is not None:
+            dict_["nft_commitment"] = dict_["nft_commitment"].hex()
+        return dict_
 
     @classmethod
     def from_dict(cls, d):
+        # convert nft_commitment to bytes
+        if d["nft_commitment"] is not None:
+            d["nft_commitment"] = bytes.fromhex(d["nft_commitment"])
         return Unspent(**{attr: d[attr] for attr in Unspent.__slots__})
 
+    @property
+    def has_nft(self):
+        return self.nft_capability is not None
+
+    @property
+    def has_amount(self):
+        return self.token_amount is not None
+
+    @property
+    def has_cashtoken(self):
+        return self.has_amount or self.has_nft
+
     def __eq__(self, other):
-        return (
-            self.amount == other.amount
-            and self.script == other.script
-            and self.txid == other.txid
-            and self.txindex == other.txindex
-        )
+        return self.to_dict() == other.to_dict()
+
+    def __gt__(self, other):
+        """
+        Method to help sorting of Unspents during spending
+        """
+        if self.has_nft:
+            if not other.has_nft:
+                return True
+            if Unspent.NFT_CAPABILITY.index(
+                self.nft_capability
+            ) > Unspent.NFT_CAPABILITY.index(other.nft_capability):
+                return True
+            if Unspent.NFT_CAPABILITY.index(
+                self.nft_capability
+            ) < Unspent.NFT_CAPABILITY.index(other.nft_capability):
+                return False
+        elif other.has_nft:
+            return False
+        if self.has_amount:
+            if not other.has_amount:
+                return True
+            if self.token_amount > other.token_amount:
+                return True
+            if self.token_amount < other.token_amount:
+                return False
+        elif other.has_amount:
+            return False
+        return self.amount > other.amount
 
     def __repr__(self):
-        return (
-            f"Unspent(amount={repr(self.amount)}, "
-            f"confirmations={repr(self.confirmations)}, "
-            f"script={repr(self.script)}, "
-            f"txid={repr(self.txid)}, "
-            f"txindex={repr(self.txindex)})"
-        )
+        var_list = [
+            f"{key}={repr(value)}"
+            for key, value in self.to_dict().items()
+            if value is not None
+        ]
+        return "Unspent({})".format(", ".join(var_list))
diff --git a/bitcash/network/services.py b/bitcash/network/services.py
index 8a3b4487..66d71cc3 100644
--- a/bitcash/network/services.py
+++ b/bitcash/network/services.py
@@ -3,9 +3,13 @@
 
 # Import supported endpoint APIs
 from bitcash.network.APIs.BitcoinDotComAPI import BitcoinDotComAPI
+from bitcash.network.APIs.ChaingraphAPI import ChaingraphAPI
 
 # Dictionary of supported endpoint APIs
-ENDPOINT_ENV_VARIABLES = {"BITCOINCOM": BitcoinDotComAPI}
+ENDPOINT_ENV_VARIABLES = {
+    "CHAINGRAPH": ChaingraphAPI,
+    "BITCOINCOM": BitcoinDotComAPI,
+}
 
 # Default API call total time timeout
 DEFAULT_TIMEOUT = 5
@@ -34,28 +38,70 @@ def get_endpoints_for(network):
 
     endpoints = []
     for endpoint in ENDPOINT_ENV_VARIABLES.keys():
-        if os.getenv(f"{endpoint}_API_{network}".upper()):
-            endpoints.append(
-                ENDPOINT_ENV_VARIABLES[endpoint](
-                    os.getenv(f"{endpoint}_API_{network}".upper())
+        if endpoint == "CHAINGRAPH":
+            if os.getenv(f"{endpoint}_API".upper()):
+                endpoints.append(
+                    ENDPOINT_ENV_VARIABLES[endpoint](
+                        os.getenv(f"{endpoint}_API".upper()),
+                        os.getenv(f"{endpoint}_API_{network}".upper()),
+                    )
                 )
-            )
-        elif os.getenv(f"{endpoint}_API_{network}_1".upper()):
-            counter = 1
-            finished = False
-            while not finished:
-                next_endpoint = os.getenv(f"{endpoint}_API_{network}_{counter}".upper())
-                if next_endpoint:
-                    endpoints.append(ENDPOINT_ENV_VARIABLES[endpoint](next_endpoint))
-                    counter += 1
-                else:
-                    finished = True
+            elif os.getenv(f"{endpoint}_API_1".upper()):
+                counter = 1
+                finished = False
+                while not finished:
+                    next_endpoint = os.getenv(f"{endpoint}_API_{counter}".upper())
+                    next_pattern = os.getenv(
+                        f"{endpoint}_API_{network}_{counter}".upper()
+                    )
+                    if next_endpoint:
+                        endpoints.append(
+                            ENDPOINT_ENV_VARIABLES[endpoint](
+                                next_endpoint, next_pattern
+                            )
+                        )
+                        counter += 1
+                    else:
+                        finished = True
+            else:
+                defaults_endpoints = ENDPOINT_ENV_VARIABLES[
+                    endpoint
+                ].get_default_endpoints(network)
+                for each in defaults_endpoints:
+                    if hasattr(each, "__iter__") and not isinstance(each, str):
+                        endpoints.append(ENDPOINT_ENV_VARIABLES[endpoint](*each))
+                    else:
+                        endpoints.append(ENDPOINT_ENV_VARIABLES[endpoint](each))
         else:
-            defaults_endpoints = ENDPOINT_ENV_VARIABLES[endpoint].get_default_endpoints(
-                network
-            )
-            for each in defaults_endpoints:
-                endpoints.append(ENDPOINT_ENV_VARIABLES[endpoint](each))
+            if os.getenv(f"{endpoint}_API_{network}".upper()):
+                endpoints.append(
+                    ENDPOINT_ENV_VARIABLES[endpoint](
+                        os.getenv(f"{endpoint}_API_{network}".upper())
+                    )
+                )
+            elif os.getenv(f"{endpoint}_API_{network}_1".upper()):
+                counter = 1
+                finished = False
+                while not finished:
+                    next_endpoint = os.getenv(
+                        f"{endpoint}_API_{network}_{counter}".upper()
+                    )
+                    if next_endpoint:
+                        endpoints.append(
+                            ENDPOINT_ENV_VARIABLES[endpoint](next_endpoint)
+                        )
+                        counter += 1
+                    else:
+                        finished = True
+            else:
+                defaults_endpoints = ENDPOINT_ENV_VARIABLES[
+                    endpoint
+                ].get_default_endpoints(network)
+                for each in defaults_endpoints:
+                    if hasattr(each, "__iter__") and not isinstance(each, str):
+                        endpoints.append(ENDPOINT_ENV_VARIABLES[endpoint](*each))
+                    else:
+                        endpoints.append(ENDPOINT_ENV_VARIABLES[endpoint](each))
 
     return endpoints
 
@@ -85,7 +131,6 @@ def get_balance(cls, address, network="mainnet"):
         :raises ConnectionError: If all API services fail.
         :rtype: ``int``
         """
-
         for endpoint in get_endpoints_for(network):
             try:
                 return endpoint.get_balance(address, timeout=DEFAULT_TIMEOUT)
@@ -103,7 +148,6 @@ def get_transactions(cls, address, network="mainnet"):
         :raises ConnectionError: If all API services fail.
         :rtype: ``list`` of ``str``
         """
-
         for endpoint in get_endpoints_for(network):
             try:
                 return endpoint.get_transactions(address, timeout=DEFAULT_TIMEOUT)
@@ -197,6 +241,11 @@ def broadcast_tx(cls, tx_hex, network="mainnet"):  # pragma: no cover
         success = None
 
         for endpoint in get_endpoints_for(network):
+            _ = [end[0] for end in ChaingraphAPI.get_default_endpoints(network)]
+            if endpoint in _ and network == "mainnet":
+                # Default chaingraph endpoints do not indicate failed broadcast
+                # no other testnet api
+                continue
             try:
                 success = endpoint.broadcast_tx(tx_hex, timeout=DEFAULT_TIMEOUT)
                 if not success:
diff --git a/bitcash/network/transaction.py b/bitcash/network/transaction.py
index a98efb75..7d16bf1f 100644
--- a/bitcash/network/transaction.py
+++ b/bitcash/network/transaction.py
@@ -1,3 +1,6 @@
+from bitcash.format import hex_to_asm
+
+
 class Transaction:
     """
     Representation of a transaction returned from the network.
@@ -17,6 +20,20 @@ def __init__(self, txid, block, amount_in, amount_out, amount_fee):
         self.inputs = []
         self.outputs = []
 
+    def to_dict(self):
+        return {
+            "txid": self.txid,
+            "block": self.block,
+            "amount_in": self.amount_in,
+            "amount_out": self.amount_out,
+            "amount_fee": self.amount_fee,
+            "inputs": [input_.to_dict() for input_ in self.inputs],
+            "outputs": [output.to_dict() for output in self.outputs],
+        }
+
+    def __eq__(self, other):
+        return self.to_dict() == other.to_dict()
+
     def add_input(self, part):
         self.inputs.append(part)
 
@@ -42,17 +59,45 @@ class TxPart:
     Representation of a single input or output.
     """
 
-    def __init__(self, address, amount, asm=None):
+    def __init__(
+        self,
+        address,
+        amount,
+        category_id=None,
+        nft_capability=None,
+        nft_commitment=None,
+        token_amount=None,
+        asm=None,
+        data_hex=None,
+    ):
         self.address = address
         self.amount = amount
+        self.category_id = category_id
+        self.nft_capability = nft_capability
+        self.nft_commitment = nft_commitment
+        self.token_amount = token_amount
         self.op_return = None
 
+        if data_hex is not None:
+            asm = hex_to_asm(data_hex)
+
         if address is None and asm is not None:
             if asm.startswith("OP_RETURN "):
                 self.op_return = asm[10:]
             elif asm.startswith("return ["):
                 self.op_return = asm[8:-1]
 
+    def to_dict(self):
+        return {
+            "address": self.address,
+            "amount": self.amount,
+            "category_id": self.category_id,
+            "nft_capability": self.nft_capability,
+            "nft_commitment": self.nft_commitment,
+            "token_amount": self.token_amount,
+            "op_return": self.op_return,
+        }
+
     def message(self):
         """Attempt to decode the op_return value (if there is one) as a UTF-8 string."""
 
diff --git a/bitcash/op.py b/bitcash/op.py
new file mode 100644
index 00000000..f2669870
--- /dev/null
+++ b/bitcash/op.py
@@ -0,0 +1,267 @@
+from enum import IntEnum
+
+
+# Derived from Bitcoin Cash Node src/script/script.h
+# as implemented in Electron cash wallet, electroncash/bitcoin.py
+# ref: reference.cash/protocol/blockchain/script
+class OpCodes(IntEnum):
+    # push value
+    OP_0 = 0x00
+    OP_FALSE = OP_0
+    OP_PUSHDATA1 = 0x4C
+    OP_PUSHDATA2 = 0x4D
+    OP_PUSHDATA4 = 0x4E
+    OP_1NEGATE = 0x4F
+    OP_RESERVED = 0x50
+    OP_1 = 0x51
+    OP_TRUE = OP_1
+    OP_2 = 0x52
+    OP_3 = 0x53
+    OP_4 = 0x54
+    OP_5 = 0x55
+    OP_6 = 0x56
+    OP_7 = 0x57
+    OP_8 = 0x58
+    OP_9 = 0x59
+    OP_10 = 0x5A
+    OP_11 = 0x5B
+    OP_12 = 0x5C
+    OP_13 = 0x5D
+    OP_14 = 0x5E
+    OP_15 = 0x5F
+    OP_16 = 0x60
+    OP_DATA_1 = 0x01
+    OP_DATA_2 = 0x02
+    OP_DATA_3 = 0x03
+    OP_DATA_4 = 0x04
+    OP_DATA_5 = 0x05
+    OP_DATA_6 = 0x06
+    OP_DATA_7 = 0x07
+    OP_DATA_8 = 0x08
+    OP_DATA_9 = 0x09
+    OP_DATA_10 = 0x0A
+    OP_DATA_11 = 0x0B
+    OP_DATA_12 = 0x0C
+    OP_DATA_13 = 0x0D
+    OP_DATA_14 = 0x0E
+    OP_DATA_15 = 0x0F
+    OP_DATA_16 = 0x10
+    OP_DATA_17 = 0x11
+    OP_DATA_18 = 0x12
+    OP_DATA_19 = 0x13
+    OP_DATA_20 = 0x14
+    OP_DATA_21 = 0x15
+    OP_DATA_22 = 0x16
+    OP_DATA_23 = 0x17
+    OP_DATA_24 = 0x18
+    OP_DATA_25 = 0x19
+    OP_DATA_26 = 0x1A
+    OP_DATA_27 = 0x1B
+    OP_DATA_28 = 0x1C
+    OP_DATA_29 = 0x1D
+    OP_DATA_30 = 0x1E
+    OP_DATA_31 = 0x1F
+    OP_DATA_32 = 0x20
+    OP_DATA_33 = 0x21
+    OP_DATA_34 = 0x22
+    OP_DATA_35 = 0x23
+    OP_DATA_36 = 0x24
+    OP_DATA_37 = 0x25
+    OP_DATA_38 = 0x26
+    OP_DATA_39 = 0x27
+    OP_DATA_40 = 0x28
+    OP_DATA_41 = 0x29
+    OP_DATA_42 = 0x2A
+    OP_DATA_43 = 0x2B
+    OP_DATA_44 = 0x2C
+    OP_DATA_45 = 0x2D
+    OP_DATA_46 = 0x2E
+    OP_DATA_47 = 0x2F
+    OP_DATA_48 = 0x30
+    OP_DATA_49 = 0x31
+    OP_DATA_50 = 0x32
+    OP_DATA_51 = 0x33
+    OP_DATA_52 = 0x34
+    OP_DATA_53 = 0x35
+    OP_DATA_54 = 0x36
+    OP_DATA_55 = 0x37
+    OP_DATA_56 = 0x38
+    OP_DATA_57 = 0x39
+    OP_DATA_58 = 0x3A
+    OP_DATA_59 = 0x3B
+    OP_DATA_60 = 0x3C
+    OP_DATA_61 = 0x3D
+    OP_DATA_62 = 0x3E
+    OP_DATA_63 = 0x3F
+    OP_DATA_64 = 0x40
+    OP_DATA_65 = 0x41
+    OP_DATA_66 = 0x42
+    OP_DATA_67 = 0x43
+    OP_DATA_68 = 0x44
+    OP_DATA_69 = 0x45
+    OP_DATA_70 = 0x46
+    OP_DATA_71 = 0x47
+    OP_DATA_72 = 0x48
+    OP_DATA_73 = 0x49
+    OP_DATA_74 = 0x4A
+    OP_DATA_75 = 0x4B
+
+    # control
+    OP_NOP = 0x61
+    OP_VER = 0x62
+    OP_IF = 0x63
+    OP_NOTIF = 0x64
+    OP_VERIF = 0x65
+    OP_VERNOTIF = 0x66
+    OP_ELSE = 0x67
+    OP_ENDIF = 0x68
+    OP_VERIFY = 0x69
+    OP_RETURN = 0x6A
+
+    # stack ops
+    OP_TOALTSTACK = 0x6B
+    OP_FROMALTSTACK = 0x6C
+    OP_2DROP = 0x6D
+    OP_2DUP = 0x6E
+    OP_3DUP = 0x6F
+    OP_2OVER = 0x70
+    OP_2ROT = 0x71
+    OP_2SWAP = 0x72
+    OP_IFDUP = 0x73
+    OP_DEPTH = 0x74
+    OP_DROP = 0x75
+    OP_DUP = 0x76
+    OP_NIP = 0x77
+    OP_OVER = 0x78
+    OP_PICK = 0x79
+    OP_ROLL = 0x7A
+    OP_ROT = 0x7B
+    OP_SWAP = 0x7C
+    OP_TUCK = 0x7D
+
+    # splice ops
+    OP_CAT = 0x7E
+    OP_SPLIT = 0x7F  # after monolith upgrade (May 2018)
+    OP_NUM2BIN = 0x80  # after monolith upgrade (May 2018)
+    OP_BIN2NUM = 0x81  # after monolith upgrade (May 2018)
+    OP_SIZE = 0x82
+
+    # bit logic
+    OP_INVERT = 0x83
+    OP_AND = 0x84
+    OP_OR = 0x85
+    OP_XOR = 0x86
+    OP_EQUAL = 0x87
+    OP_EQUALVERIFY = 0x88
+    OP_RESERVED1 = 0x89
+    OP_RESERVED2 = 0x8A
+
+    # numeric
+    OP_1ADD = 0x8B
+    OP_1SUB = 0x8C
+    OP_2MUL = 0x8D
+    OP_2DIV = 0x8E
+    OP_NEGATE = 0x8F
+    OP_ABS = 0x90
+    OP_NOT = 0x91
+    OP_0NOTEQUAL = 0x92
+
+    OP_ADD = 0x93
+    OP_SUB = 0x94
+    OP_MUL = 0x95
+    OP_DIV = 0x96
+    OP_MOD = 0x97
+    OP_LSHIFT = 0x98
+    OP_RSHIFT = 0x99
+
+    OP_BOOLAND = 0x9A
+    OP_BOOLOR = 0x9B
+    OP_NUMEQUAL = 0x9C
+    OP_NUMEQUALVERIFY = 0x9D
+    OP_NUMNOTEQUAL = 0x9E
+    OP_LESSTHAN = 0x9F
+    OP_GREATERTHAN = 0xA0
+    OP_LESSTHANOREQUAL = 0xA1
+    OP_GREATERTHANOREQUAL = 0xA2
+    OP_MIN = 0xA3
+    OP_MAX = 0xA4
+
+    OP_WITHIN = 0xA5
+
+    # crypto
+    OP_RIPEMD160 = 0xA6
+    OP_SHA1 = 0xA7
+    OP_SHA256 = 0xA8
+    OP_HASH160 = 0xA9
+    OP_HASH256 = 0xAA
+    OP_CODESEPARATOR = 0xAB
+    OP_CHECKSIG = 0xAC
+    OP_CHECKSIGVERIFY = 0xAD
+    OP_CHECKMULTISIG = 0xAE
+    OP_CHECKMULTISIGVERIFY = 0xAF
+
+    # expansion
+    OP_NOP1 = 0xB0
+    OP_CHECKLOCKTIMEVERIFY = 0xB1
+    OP_NOP2 = OP_CHECKLOCKTIMEVERIFY
+    OP_CHECKSEQUENCEVERIFY = 0xB2
+    OP_NOP3 = OP_CHECKSEQUENCEVERIFY
+    OP_NOP4 = 0xB3
+    OP_NOP5 = 0xB4
+    OP_NOP6 = 0xB5
+    OP_NOP7 = 0xB6
+    OP_NOP8 = 0xB7
+    OP_NOP9 = 0xB8
+    OP_NOP10 = 0xB9
+
+    # More crypto
+    OP_CHECKDATASIG = 0xBA
+    OP_CHECKDATASIGVERIFY = 0xBB
+
+    # additional byte string operations
+    OP_REVERSEBYTES = 0xBC
+
+    # Native Introspection opcodes
+    OP_INPUTINDEX = 0xC0
+    OP_ACTIVEBYTECODE = 0xC1
+    OP_TXVERSION = 0xC2
+    OP_TXINPUTCOUNT = 0xC3
+    OP_TXOUTPUTCOUNT = 0xC4
+    OP_TXLOCKTIME = 0xC5
+    OP_UTXOVALUE = 0xC6
+    OP_UTXOBYTECODE = 0xC7
+    OP_OUTPOINTTXHASH = 0xC8
+    OP_OUTPOINTINDEX = 0xC9
+    OP_INPUTBYTECODE = 0xCA
+    OP_INPUTSEQUENCENUMBER = 0xCB
+    OP_OUTPUTVALUE = 0xCC
+    OP_OUTPUTBYTECODE = 0xCD
+
+    # CashTokens opcodes
+    OP_UTXOTOKENCATEGORY = 0xCE
+    OP_UTXOTOKENCOMMITMENT = 0xCF
+    OP_UTXOTOKENAMOUNT = 0xD0
+    OP_OUTPUTTOKENCATEGORY = 0xD1
+    OP_OUTPUTTOKENCOMMITMENT = 0xD2
+    OP_OUTPUTTOKENAMOUNT = 0xD3
+    OP_TOKENPREFIX = 0xEF
+
+    @property
+    def binary(self):
+        """
+        Adds easy way to convert to binary
+
+        >>> OpCodes.OP_0.b
+        b"\x00"
+        """
+        return self.value.to_bytes(1, "little")
+
+    @property
+    def hex(self):
+        """
+        Adds easy way to convert to hex
+        >>> OpCodes.OP_0.h
+        "00"
+        """
+        # converty from binary to preserve 8 bit hex
+        return self.b.hex()
diff --git a/bitcash/transaction.py b/bitcash/transaction.py
index 75a5075c..c8cce796 100644
--- a/bitcash/transaction.py
+++ b/bitcash/transaction.py
@@ -1,10 +1,16 @@
 import logging
 from collections import namedtuple
+from copy import deepcopy
 
 from bitcash.crypto import double_sha256, sha256
 from bitcash.exceptions import InsufficientFunds
-from bitcash.format import Address
-from bitcash.network.rates import currency_to_satoshi_cached
+from bitcash.cashtoken import (
+    prepare_output,
+    Unspents,
+    select_cashtoken_utxo,
+    generate_cashtoken_prefix,
+)
+from bitcash.op import OpCodes
 from bitcash.utils import (
     bytes_to_hex,
     chunk_data,
@@ -26,31 +32,19 @@
 HASH_TYPE = 0x41.to_bytes(4, byteorder="little")
 ##
 
-OP_0 = b"\x00"
-OP_CHECKLOCKTIMEVERIFY = b"\xb1"
-OP_CHECKSIG = b"\xac"
-OP_DUP = b"v"
-OP_EQUAL = b"\x87"
-OP_EQUALVERIFY = b"\x88"
-OP_HASH160 = b"\xa9"
-OP_PUSH_20 = b"\x14"
-OP_RETURN = b"\x6a"
-OP_PUSHDATA1 = b"\x4c"
-OP_PUSHDATA2 = b"\x4d"
-OP_PUSHDATA4 = b"\x4e"
-
 MESSAGE_LIMIT = 220
 
 
 class TxIn:
-    __slots__ = ("script", "script_len", "txid", "txindex", "amount")
+    __slots__ = ("script", "script_len", "txid", "txindex", "amount", "token_prefix")
 
-    def __init__(self, script, script_len, txid, txindex, amount):
+    def __init__(self, script, script_len, txid, txindex, amount, token_prefix=b""):
         self.script = script
         self.script_len = script_len
         self.txid = txid
         self.txindex = txindex
         self.amount = amount
+        self.token_prefix = token_prefix
 
     def __eq__(self, other):
         return (
@@ -59,15 +53,19 @@ def __eq__(self, other):
             and self.txid == other.txid
             and self.txindex == other.txindex
             and self.amount == other.amount
+            and self.token_prefix == other.token_prefix
         )
 
+    def to_dict(self):
+        return {attr: getattr(self, attr) for attr in TxIn.__slots__}
+
     def __repr__(self):
         return (
             f"TxIn({repr(self.script)}, "
             f"{repr(self.script_len)}, "
             f"{repr(self.txid)}, "
             f"{repr(self.txindex)}, "
-            f"{repr(self.amount)})"
+            f"{repr(self.amount)}, {repr(self.token_prefix)})"
         )
 
 
@@ -78,76 +76,43 @@ def calc_txid(tx_hex):
     return bytes_to_hex(double_sha256(hex_to_bytes(tx_hex))[::-1])
 
 
-def estimate_tx_fee(
-    n_in, n_out_p2pkh, n_out_p2sh, satoshis, compressed, op_return_size=0
-):
+def estimate_tx_fee(n_in, output_script_list, satoshis, compressed):
     if not satoshis:
         return 0
 
-    n_out = n_out_p2sh + n_out_p2pkh
+    n_out = len(output_script_list)
 
     estimated_size = (
-        4
-        + n_in * (148 if compressed else 180)  # version
+        4  # version
         + len(int_to_unknown_bytes(n_in, byteorder="little"))
-        # excluding op_return outputs, dealt with separately
-        + n_out_p2pkh * 34
-        + n_out_p2sh * 32
+        + n_in * (148 if compressed else 180)
         + len(int_to_unknown_bytes(n_out, byteorder="little"))
-        # grand total size of op_return outputs(s) and related field(s)
-        + op_return_size
+        + n_out * 9  # satoshi_value + script_len
+        + sum([len(script) for script in output_script_list])
         + 4  # time lock
     )
 
     estimated_fee = estimated_size * satoshis
 
-    logging.debug(
-        f"Estimated fee: {estimated_fee}" f" satoshis for {estimated_size} bytes"
-    )
+    logging.debug(f"Estimated fee: {estimated_fee} satoshis for {estimated_size} bytes")
 
     return estimated_fee
 
 
-def get_op_return_size(message, custom_pushdata=False):
-    # calculate op_return size for each individual message
-    if custom_pushdata is False:
-        op_return_size = (
-            8  # int64_t amount 0x00000000
-            + len(OP_RETURN)  # 1 byte
-            + len(
-                get_op_pushdata_code(message)
-            )  # 1 byte if <75 bytes, 2 bytes if OP_PUSHDATA1...
-            + len(message)  # Max 220 bytes at present
-        )
-
-    if custom_pushdata is True:
-        op_return_size = (
-            8  # int64_t amount 0x00000000
-            + len(OP_RETURN)  # 1 byte
-            + len(
-                message
-            )  # Unsure if Max size will be >220 bytes due to extra OP_PUSHDATA codes...
-        )
-
-    # "Var_Int" that preceeds OP_RETURN - 0xdf is max value with current 220 byte limit (so only adds 1 byte)
-    op_return_size += len(int_to_varint(op_return_size))
-    return op_return_size
-
-
 def get_op_pushdata_code(dest):
     length_data = len(dest)
     if length_data <= 0x4C:  # (https://en.bitcoin.it/wiki/Script)
         return length_data.to_bytes(1, byteorder="little")
     elif length_data <= 0xFF:
-        return OP_PUSHDATA1 + length_data.to_bytes(
+        return OpCodes.OP_PUSHDATA1.binary + length_data.to_bytes(
             1, byteorder="little"
         )  # OP_PUSHDATA1 format
     elif length_data <= 0xFFFF:
-        return OP_PUSHDATA2 + length_data.to_bytes(
+        return OpCodes.OP_PUSHDATA2.binary + length_data.to_bytes(
             2, byteorder="little"
         )  # OP_PUSHDATA2 format
     else:
-        return OP_PUSHDATA4 + length_data.to_bytes(
+        return OpCodes.OP_PUSHDATA4.binary + length_data.to_bytes(
             4, byteorder="little"
         )  # OP_PUSHDATA4 format
 
@@ -167,26 +132,19 @@ def sanitize_tx_data(
 
     fee is in satoshis per byte.
     """
-
+    unspents = deepcopy(unspents)
     outputs = outputs.copy()
 
-    for i, output in enumerate(outputs):
-        dest, amount, currency = output
-        dest = Address.from_string(dest)
-
-        if "P2PKH" not in dest.version and "P2SH" not in dest.version:
-            # Bitcash currently only supports P2PKH, P2SH transaction outputs
-            # others will raise ValueError
-            raise ValueError("Bitcash currently only supports" " P2PKH/P2SH outputs")
-
-        outputs[i] = (dest, currency_to_satoshi_cached(amount, currency))
-
     if not unspents:
         raise ValueError("Transactions must have at least one unspent.")
 
+    for i, output in enumerate(outputs):
+        # (script, satoshi value, category_id, nft_capability, nft_commitment,
+        # token_amount)
+        outputs[i] = prepare_output(output)
+
     # Temporary storage so all outputs precede messages.
     messages = []
-    total_op_return_size = 0
 
     if message and (custom_pushdata is False):
         try:
@@ -197,124 +155,106 @@ def sanitize_tx_data(
         message_chunks = chunk_data(message, MESSAGE_LIMIT)
 
         for message in message_chunks:
-            messages.append((message, 0))
-            total_op_return_size += get_op_return_size(message, custom_pushdata=False)
+            script = OpCodes.OP_RETURN.binary + get_op_pushdata_code(message) + message
+            messages.append((script, 0, None, None, None, None))
 
     elif message and (custom_pushdata is True):
         if len(message) >= 220:
             # FIXME add capability for >220 bytes for custom pushdata elements
-            raise ValueError(
-                "Currently cannot exceed 220 " "bytes with custom_pushdata."
-            )
+            raise ValueError("Currently cannot exceed 220 bytes with custom_pushdata.")
         else:
-            messages.append((message, 0))
-            total_op_return_size += get_op_return_size(message, custom_pushdata=True)
-
-    # Include return address in fee estimate.
-    total_in = 0
-    num_p2pkh_outputs = sum(["P2PKH" in out[0].version for out in outputs])
-    # Bitcash only supports P2PKH utxos, return address is added as P2PKH
-    num_p2pkh_outputs += 1
-    # counting P2SH outs, will adjust fee estimate
-    num_p2sh_outputs = sum(["P2SH" in out[0].version for out in outputs])
-    sum_outputs = sum(out[1] for out in outputs)
+            # manual control over number of bytes in each batch of pushdata
+            if type(message) != bytes:
+                raise TypeError("custom pushdata must be of type: bytes")
+            else:
+                script = OpCodes.OP_RETURN.binary + message
+            messages.append((script, 0, None, None, None, None))
+
+    # counting outs, will adjust fee estimate
+    output_script_list = [_[0] for _ in outputs]
+    output_script_list += [_[0] for _ in messages]
 
     if combine:
+        cashtoken = Unspents(unspents)
+        for output in outputs:
+            cashtoken.subtract_output(output)
+        leftover_outputs, leftover_amount = cashtoken.get_outputs(leftover)
+        output_script_list += [_[0] for _ in leftover_outputs]
         # calculated_fee is in total satoshis.
         calculated_fee = estimate_tx_fee(
             len(unspents),
-            num_p2pkh_outputs,
-            num_p2sh_outputs,
+            output_script_list,
             fee,
             compressed,
-            total_op_return_size,
         )
-        total_out = sum_outputs + calculated_fee
-        unspents = unspents.copy()
-        total_in += sum(unspent.amount for unspent in unspents)
+        if calculated_fee > leftover_amount:
+            raise InsufficientFunds("leftover balance cannot cover fee")
+        if calculated_fee:
+            last_out = list(leftover_outputs[-1])
+            last_out[1] -= calculated_fee
+            leftover_outputs[-1] = tuple(last_out)
 
-    else:
-        unspents = sorted(unspents, key=lambda x: x.amount)
-
-        index = 0
+        outputs += leftover_outputs
 
+    else:
+        unspents, unspents_used = select_cashtoken_utxo(unspents, outputs)
+
+        error = None
+        # the first unspent is added regardless because of how selection is,
+        # easiest is to pop the last unspent used and add to unspents searched
+        if len(unspents_used) > 0:
+            unspents = [unspents_used[-1]] + unspents
+            unspents_used = unspents_used[:-1]
+        cashtoken = Unspents(unspents_used)
         for index, unspent in enumerate(unspents):
-            total_in += unspent.amount
+            cashtoken.add_unspent(unspent)
+            test_token = deepcopy(cashtoken)
+            try:
+                for output in outputs:
+                    test_token.subtract_output(output)
+                (leftover_outputs, leftover_amount) = test_token.get_outputs(leftover)
+            except InsufficientFunds as err:
+                error = err
+                continue
+
+            output_script_list += [_[0] for _ in leftover_outputs]
+
             calculated_fee = estimate_tx_fee(
-                len(unspents[: index + 1]),
-                num_p2pkh_outputs,
-                num_p2sh_outputs,
+                len(unspents[: index + 1]) + len(unspents_used),
+                output_script_list,
                 fee,
                 compressed,
-                total_op_return_size,
             )
-            total_out = sum_outputs + calculated_fee
-
-            if total_in >= total_out:
+            if calculated_fee < leftover_amount:
                 break
+        else:
+            raise InsufficientFunds(error or f"{cashtoken.amount} is insufficient")
 
-        unspents[:] = unspents[: index + 1]
-
-    remaining = total_in - total_out
+        if calculated_fee:
+            last_out = list(leftover_outputs[-1])
+            last_out[1] -= calculated_fee
+            leftover_outputs[-1] = tuple(last_out)
 
-    if remaining > 0:
-        outputs.append((Address.from_string(leftover), remaining))
-    elif remaining < 0:
-        raise InsufficientFunds(
-            f"Balance {total_in} is less than " f"{total_out} (including fee)."
-        )
+        unspents[:] = unspents_used + unspents[: index + 1]
+        outputs += leftover_outputs
 
     outputs.extend(messages)
 
     return unspents, outputs
 
 
-def construct_output_block(outputs, custom_pushdata=False):
+def construct_output_block(outputs):
     output_block = b""
 
     for data in outputs:
-        dest, amount = data
-
-        # Real recipient
-        if amount:
-            if isinstance(dest, str):
-                dest = Address.from_string(dest)
-            if "P2PKH" in dest.version:
-                script = (
-                    OP_DUP
-                    + OP_HASH160
-                    + OP_PUSH_20
-                    + bytes(dest.payload)
-                    + OP_EQUALVERIFY
-                    + OP_CHECKSIG
-                )
-            elif "P2SH" in dest.version:
-                script = OP_HASH160 + OP_PUSH_20 + bytes(dest.payload) + OP_EQUAL
-            else:
-                raise ValueError(
-                    "Bitcash currently only supports" " P2PKH/P2SH outputs"
-                )
-
-            output_block += amount.to_bytes(8, byteorder="little")
-
-        # Blockchain storage
-        else:
-            if custom_pushdata is False:
-                script = OP_RETURN + get_op_pushdata_code(dest) + dest
+        script, amount, _, _, _, _ = data
 
-                output_block += b"\x00\x00\x00\x00\x00\x00\x00\x00"
+        output_block += amount.to_bytes(8, byteorder="little")
 
-            elif custom_pushdata is True:
-                # manual control over number of bytes in each batch of pushdata
-                if type(dest) != bytes:
-                    raise TypeError("custom pushdata must be of type: bytes")
-                else:
-                    script = OP_RETURN + dest
-
-                output_block += b"\x00\x00\x00\x00\x00\x00\x00\x00"
-
-        # Script length in wiki is "Var_int" but there's a note of "modern BitcoinQT" using a more compact "CVarInt"
-        # CVarInt is what I believe we have here - No changes made. If incorrect - only breaks if 220 byte limit is increased.
+        # Script length in wiki is "Var_int" but there's a note of
+        # "modern BitcoinQT" using a more compact "CVarInt"
+        # CVarInt is what I believe we have here - No changes made.
+        # If incorrect - only breaks if 220 byte limit is increased.
         output_block += int_to_unknown_bytes(len(script), byteorder="little")
         output_block += script
 
@@ -333,13 +273,10 @@ def construct_input_block(inputs):
     return input_block
 
 
-def create_p2pkh_transaction(private_key, unspents, outputs, custom_pushdata=False):
+def create_p2pkh_transaction(private_key, unspents, outputs):
     public_key = private_key.public_key
     public_key_len = len(public_key).to_bytes(1, byteorder="little")
 
-    scriptCode = private_key.scriptcode
-    scriptCode_len = int_to_varint(len(scriptCode))
-
     version = VERSION_1
     lock_time = LOCK_TIME
     # sequence = SEQUENCE
@@ -347,18 +284,25 @@ def create_p2pkh_transaction(private_key, unspents, outputs, custom_pushdata=Fal
     input_count = int_to_unknown_bytes(len(unspents), byteorder="little")
     output_count = int_to_unknown_bytes(len(outputs), byteorder="little")
 
-    output_block = construct_output_block(outputs, custom_pushdata=custom_pushdata)
+    output_block = construct_output_block(outputs)
 
     # Optimize for speed, not memory, by pre-computing values.
     inputs = []
     for unspent in unspents:
         script = hex_to_bytes(unspent.script)
-        script_len = int_to_unknown_bytes(len(script), byteorder="little")
+        script_len = int_to_varint(len(script))
+        # get cashtoken prefix
+        token_prefix = generate_cashtoken_prefix(
+            unspent.category_id,
+            unspent.nft_capability,
+            unspent.nft_commitment,
+            unspent.token_amount,
+        )
         txid = hex_to_bytes(unspent.txid)[::-1]
         txindex = unspent.txindex.to_bytes(4, byteorder="little")
         amount = unspent.amount.to_bytes(8, byteorder="little")
 
-        inputs.append(TxIn(script, script_len, txid, txindex, amount))
+        inputs.append(TxIn(script, script_len, txid, txindex, amount, token_prefix))
 
     hashPrevouts = double_sha256(b"".join([i.txid + i.txindex for i in inputs]))
     hashSequence = double_sha256(b"".join([SEQUENCE for i in inputs]))
@@ -372,8 +316,9 @@ def create_p2pkh_transaction(private_key, unspents, outputs, custom_pushdata=Fal
             + hashSequence
             + txin.txid
             + txin.txindex
-            + scriptCode_len
-            + scriptCode
+            + txin.token_prefix
+            + txin.script_len
+            + txin.script
             + txin.amount
             + SEQUENCE
             + hashOutputs
diff --git a/bitcash/utils.py b/bitcash/utils.py
index e50ff470..6fa13fea 100644
--- a/bitcash/utils.py
+++ b/bitcash/utils.py
@@ -50,3 +50,21 @@ def int_to_varint(val):
         return b"\xfe" + val.to_bytes(4, "little")
     else:
         return b"\xff" + val.to_bytes(8, "little")
+
+
+def varint_to_int(val):
+    """
+    Converts varint to int from incoming bytestream.
+
+    :param val: the bytecode starting with varint
+    :type val: ``io.BytesIO``
+    :returns: ``int``
+    """
+    start_byte = val.read(1)
+    if start_byte == b"\xff":
+        return int.from_bytes(val.read(8), "little")
+    if start_byte == b"\xfe":
+        return int.from_bytes(val.read(4), "little")
+    if start_byte == b"\xfd":
+        return int.from_bytes(val.read(2), "little")
+    return int.from_bytes(start_byte, "little")
diff --git a/bitcash/wallet.py b/bitcash/wallet.py
index 65aa5cd4..6c41570c 100644
--- a/bitcash/wallet.py
+++ b/bitcash/wallet.py
@@ -1,6 +1,7 @@
 import json
 
 from bitcash.crypto import ECPrivateKey
+from bitcash.cashtoken import Unspents
 from bitcash.curve import Point
 from bitcash.exceptions import InvalidNetwork
 from bitcash.format import (
@@ -9,19 +10,12 @@
     public_key_to_coords,
     wif_to_bytes,
     address_to_public_key_hash,
+    address_to_cashtokenaddress,
 )
 from bitcash.network import NetworkAPI, satoshi_to_currency_cached
 from bitcash.network.meta import Unspent
-from bitcash.transaction import (
-    calc_txid,
-    create_p2pkh_transaction,
-    sanitize_tx_data,
-    OP_CHECKSIG,
-    OP_DUP,
-    OP_EQUALVERIFY,
-    OP_HASH160,
-    OP_PUSH_20,
-)
+from bitcash.op import OpCodes
+from bitcash.transaction import calc_txid, create_p2pkh_transaction, sanitize_tx_data
 
 
 NETWORKS = {"main": "mainnet", "test": "testnet", "regtest": "regtest"}
@@ -165,6 +159,7 @@ def __init__(self, wif=None, network="main"):
         else:
             raise InvalidNetwork
         self.balance = 0
+        self.cashtoken_balance = {}
         self.unspents = []
         self.transactions = []
 
@@ -178,15 +173,20 @@ def address(self):
 
         return self._address
 
+    @property
+    def cashtoken_address(self):
+        """The public address you share with others to receive cashtokens."""
+        return address_to_cashtokenaddress(self.address)
+
     @property
     def scriptcode(self):
         self._scriptcode = (
-            OP_DUP
-            + OP_HASH160
-            + OP_PUSH_20
+            OpCodes.OP_DUP.binary
+            + OpCodes.OP_HASH160.binary
+            + OpCodes.OP_DATA_20.binary
             + address_to_public_key_hash(self.address)
-            + OP_EQUALVERIFY
-            + OP_CHECKSIG
+            + OpCodes.OP_EQUALVERIFY.binary
+            + OpCodes.OP_CHECKSIG.binary
         )
         return self._scriptcode
 
@@ -213,12 +213,19 @@ def get_balance(self, currency="satoshi"):
         :type currency: ``str``
         :rtype: ``str``
         """
-        self.unspents[:] = NetworkAPI.get_unspent(
-            self.address, network=NETWORKS[self._network]
-        )
-        self.balance = sum(unspent.amount for unspent in self.unspents)
+        _ = self.get_unspents()
         return self.balance_as(currency)
 
+    def get_cashtokenbalance(self):
+        """Fetches the current cashtoken balance by calling
+        :func:`~bitcash.PrivateKey.get_balance` and returns it as
+        a token dictionary.
+
+        :rtype: ``dict``
+        """
+        _ = self.get_unspents()
+        return self.cashtoken_balance
+
     def get_unspents(self):
         """Fetches all available unspent transaction outputs.
 
@@ -227,7 +234,9 @@ def get_unspents(self):
         self.unspents[:] = NetworkAPI.get_unspent(
             self.address, network=NETWORKS[self._network]
         )
-        self.balance = sum(unspent.amount for unspent in self.unspents)
+        _ = Unspents(self.unspents)
+        self.balance = _.amount
+        self.cashtoken_balance = _.tokendata
         return self.unspents
 
     def get_transactions(self):
@@ -257,6 +266,17 @@ def create_transaction(
                         be either an int, float, or string as long as it is
                         a valid input to ``decimal.Decimal``. The currency
                         must be :ref:`supported <supported currencies>`.
+                        To send CashToken, the list of output is made in the
+                        form ``(destination, amount, currency, category_id,
+                        nft_capability, nft_commitment, token_amount)``. The category_id
+                        is hex of tx-id as ``str``. The nft_capability is the capability
+                        of non-fungible token in ("none", "mutable", "minting"). The
+                        nft_commitment is the commitment of the non-fungible token in
+                        ``bytes``.
+                        The CashToken property nft_capability, nft_commitment, or
+                        the token_amount can be None if not to be sent. If
+                        category_id is tx-id of unspent with tx-index 0, then
+                        tx is treated as a genesis tx.
         :type outputs: ``list`` of ``tuple``
         :param fee: The number of satoshi per byte to pay to miners. By default
                     Bitcash will poll `<https://bitcoincashfees.earn.com>`_ and use a fee
@@ -283,7 +303,7 @@ def create_transaction(
         """
 
         unspents, outputs = sanitize_tx_data(
-            unspents or self.unspents,
+            unspents or self.get_unspents(),
             outputs,
             fee or DEFAULT_FEE,
             leftover or self.address,
@@ -293,9 +313,7 @@ def create_transaction(
             custom_pushdata=custom_pushdata,
         )
 
-        return create_p2pkh_transaction(
-            self, unspents, outputs, custom_pushdata=custom_pushdata
-        )
+        return create_p2pkh_transaction(self, unspents, outputs)
 
     def send(
         self,
@@ -315,6 +333,17 @@ def send(
                         be either an int, float, or string as long as it is
                         a valid input to ``decimal.Decimal``. The currency
                         must be :ref:`supported <supported currencies>`.
+                        To send CashToken, the list of output is made in the
+                        form ``(destination, amount, currency, category_id,
+                        nft_capability, nft_commitment, token_amount)``. The category_id
+                        is hex of tx-id as ``str``. The nft_capability is the capability
+                        of non-fungible token in ("none", "mutable", "minting"). The
+                        nft_commitment is the commitment of the non-fungible token in
+                        ``bytes``.
+                        The CashToken property nft_capability, nft_commitment, or
+                        the token_amount can be None if not to be sent. If
+                        category_id is tx-id of unspent with tx-index 0, then
+                        tx is treated as a genesis tx.
         :type outputs: ``list`` of ``tuple``
         :param fee: The number of satoshi per byte to pay to miners. By default
                     Bitcash will poll `<https://bitcoincashfees.earn.com>`_ and use a fee
@@ -374,6 +403,17 @@ def prepare_transaction(
                         be either an int, float, or string as long as it is
                         a valid input to ``decimal.Decimal``. The currency
                         must be :ref:`supported <supported currencies>`.
+                        To send CashToken, the list of output is made in the
+                        form ``(destination, amount, currency, category_id,
+                        nft_capability, nft_commitment, token_amount)``. The category_id
+                        is hex of tx-id as ``str``. The nft_capability is the capability
+                        of non-fungible token in ("none", "mutable", "minting"). The
+                        nft_commitment is the commitment of the non-fungible token in
+                        ``bytes``.
+                        The CashToken property nft_capability, nft_commitment, or
+                        the token_amount can be None if not to be sent. If
+                        category_id is tx-id of unspent with tx-index 0, then
+                        tx is treated as a genesis tx.
         :type outputs: ``list`` of ``tuple``
         :param compressed: Whether or not the ``address`` corresponds to a
                            compressed public key. This influences the fee.
@@ -411,6 +451,14 @@ def prepare_transaction(
             compressed=compressed,
         )
 
+        outputs = list(map(list, outputs))
+        for output in outputs:
+            # script
+            output[0] = output[0].hex()
+            # nft_commitment
+            if output[4] is not None:
+                output[4] = output[4].hex()
+
         data = {
             "unspents": [unspent.to_dict() for unspent in unspents],
             "outputs": outputs,
@@ -431,6 +479,13 @@ def sign_transaction(self, tx_data):  # pragma: no cover
 
         unspents = [Unspent.from_dict(unspent) for unspent in data["unspents"]]
         outputs = data["outputs"]
+        for output in outputs:
+            # script
+            output[0] = bytes.fromhex(output[0])
+            # nft_commitment
+            if output[4] is not None:
+                output[4] = bytes.fromhex(output[4])
+        outputs = list(map(tuple, outputs))
 
         return create_p2pkh_transaction(self, unspents, outputs)
 
diff --git a/docs/source/_static/cashtoken-creation.svg b/docs/source/_static/cashtoken-creation.svg
new file mode 100644
index 00000000..4c0dbe29
--- /dev/null
+++ b/docs/source/_static/cashtoken-creation.svg
@@ -0,0 +1,1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-miterlimit:3" viewBox="0 0 1440 1080"><path d="M0 0h1440v1080H0z" style="fill:#fff"/><path d="M325 891.96h834M560.11 840.94v102.63M804.57 840.65v102.63" style="fill:none;stroke:#ebebeb;stroke-width:2px"/><path d="M668.55 657.55H496.23a12.73 12.73 0 0 0-12.62 12.83v25.65c0 7.08 5.66 12.82 12.62 12.82h172.32M280.9 637.42h172.32c6.97 0 12.62-5.74 12.62-12.82v-25.65c0-7.08-5.65-12.83-12.62-12.83H280.9" style="fill:none;stroke:#b4c4c9;stroke-width:2px;stroke-linecap:round;stroke-dasharray:2,4,0,0"/><path d="M667.87 586.13H495.91c-6.96 0-12.6 5.74-12.6 12.82v25.65c0 7.08 5.64 12.82 12.6 12.82h171.96" style="fill:none;stroke:#8a11b2;stroke-width:3px;stroke-miterlimit:1"/><path d="M668.55 526.9c0-3.46-2.8-6.26-6.25-6.26H286.85a6.25 6.25 0 0 0-6.25 6.25v195.85c0 3.45 2.8 6.25 6.25 6.25H662.3c3.45 0 6.25-2.8 6.25-6.25V526.89Z" style="fill:none;stroke:#073b4c;stroke-width:3px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5"/><path d="m315.06 545.92-.4 3.07h-4.16v13.82h-4v-13.82h-4.36v-3.07h12.92ZM322.88 549.5c.47 0 .9.06 1.3.17l-.62 3.73a5.49 5.49 0 0 0-1.17-.17c-.76 0-1.34.26-1.74.79-.4.53-.7 1.32-.94 2.38v6.4h-3.85v-12.93h3.37l.31 2.5c.3-.89.74-1.6 1.33-2.1a3 3 0 0 1 2.01-.77ZM335.07 559.05c0 .49.07.85.2 1.07.14.23.37.4.67.52l-.8 2.5a4.74 4.74 0 0 1-1.95-.52 2.8 2.8 0 0 1-1.17-1.35c-.84 1.3-2.14 1.95-3.9 1.95a4.2 4.2 0 0 1-3.07-1.12 3.91 3.91 0 0 1-1.15-2.93c0-1.4.53-2.49 1.57-3.24 1.03-.74 2.54-1.12 4.5-1.12h1.32v-.56c0-.76-.16-1.29-.49-1.57-.32-.28-.9-.43-1.7-.43-.43 0-.94.06-1.54.19-.6.12-1.22.28-1.85.5l-.88-2.54a14.75 14.75 0 0 1 4.87-.95c1.86 0 3.21.38 4.07 1.15.87.76 1.3 1.9 1.3 3.43v5.02Zm-5.83 1.42c.88 0 1.56-.42 2.05-1.25v-2.29h-.95c-.88 0-1.53.16-1.96.46-.43.31-.65.8-.65 1.44 0 .52.13.92.4 1.2.27.3.64.44 1.11.44ZM345.72 549.45c1.12 0 2 .34 2.63 1.02.63.69.95 1.65.95 2.88v9.46h-3.85V554c0-.65-.1-1.1-.3-1.35-.21-.26-.51-.38-.92-.38-.78 0-1.53.56-2.24 1.68v8.85h-3.85v-12.94h3.36l.27 1.53a5.84 5.84 0 0 1 1.79-1.46 4.7 4.7 0 0 1 2.16-.49ZM356.76 549.45c.92 0 1.8.14 2.6.41.82.28 1.53.67 2.15 1.17l-1.42 2.17a5.94 5.94 0 0 0-3.19-1c-.5 0-.89.09-1.15.26a.8.8 0 0 0-.4.72c0 .24.05.44.17.6.13.15.37.3.75.47.37.16.95.36 1.73.59 1.35.39 2.35.9 3 1.52.67.63 1 1.49 1 2.6 0 .87-.26 1.63-.76 2.27-.5.65-1.2 1.14-2.07 1.48-.88.34-1.85.5-2.93.5s-2.1-.16-3.03-.5a7 7 0 0 1-2.38-1.42l1.88-2.1a5.52 5.52 0 0 0 3.44 1.28c.58 0 1.04-.11 1.37-.32a1 1 0 0 0 .5-.9c0-.31-.06-.55-.2-.73a1.76 1.76 0 0 0-.75-.5c-.37-.16-.96-.35-1.78-.58a6.34 6.34 0 0 1-2.87-1.56 3.46 3.46 0 0 1-.95-2.48c0-.75.21-1.42.64-2.01a4.38 4.38 0 0 1 1.86-1.42c.8-.34 1.73-.52 2.79-.52ZM374.01 559.05c0 .49.07.85.2 1.07.15.23.37.4.68.52l-.8 2.5a4.74 4.74 0 0 1-1.96-.52 2.8 2.8 0 0 1-1.17-1.35c-.84 1.3-2.14 1.95-3.9 1.95a4.2 4.2 0 0 1-3.07-1.12 3.9 3.9 0 0 1-1.14-2.93c0-1.4.52-2.49 1.56-3.24 1.04-.74 2.54-1.12 4.5-1.12h1.32v-.56c0-.76-.16-1.29-.48-1.57-.33-.28-.9-.43-1.71-.43-.42 0-.93.06-1.54.19-.6.12-1.21.28-1.85.5l-.88-2.54a14.78 14.78 0 0 1 4.88-.95c1.85 0 3.2.38 4.07 1.15.86.76 1.29 1.9 1.29 3.43v5.02Zm-5.83 1.42c.88 0 1.56-.42 2.05-1.25v-2.29h-.95c-.87 0-1.53.16-1.96.46-.43.31-.65.8-.65 1.44 0 .52.14.92.4 1.2.28.3.64.44 1.12.44ZM382.69 549.45c.89 0 1.7.13 2.4.39.72.26 1.4.66 2.03 1.2l-1.66 2.29a4.05 4.05 0 0 0-2.46-.93c-.86 0-1.5.32-1.95.95-.44.63-.66 1.66-.66 3.07 0 1.37.22 2.33.66 2.9.44.57 1.07.85 1.9.85.44 0 .84-.07 1.2-.2.36-.14.79-.37 1.29-.67l1.68 2.38a6.8 6.8 0 0 1-4.36 1.54 6.65 6.65 0 0 1-3.41-.84 5.67 5.67 0 0 1-2.22-2.36 7.74 7.74 0 0 1-.78-3.57c0-1.37.26-2.58.78-3.64a5.9 5.9 0 0 1 5.56-3.36ZM396.87 562.2a6.75 6.75 0 0 1-3.5 1.02c-2.84-.02-4.25-1.58-4.25-4.68v-6h-1.83v-2.67h1.83v-2.8l3.85-.45v3.25h2.97l-.41 2.68h-2.56v5.94c0 .6.1 1.03.3 1.3.19.25.5.38.92.38.44 0 .9-.13 1.39-.41l1.29 2.44ZM402.01 549.87v12.94h-3.85v-12.94h3.85Zm-1.95-6.83c.67 0 1.22.2 1.65.62.43.42.64.94.64 1.57 0 .64-.21 1.16-.64 1.58-.43.41-.98.62-1.65.62-.66 0-1.2-.21-1.63-.62a2.1 2.1 0 0 1-.63-1.58c0-.63.2-1.15.63-1.57.42-.41.97-.62 1.63-.62ZM410.64 549.45c1.98 0 3.53.6 4.65 1.82 1.12 1.2 1.68 2.9 1.68 5.08 0 1.38-.25 2.58-.76 3.62a5.65 5.65 0 0 1-2.2 2.4c-.95.57-2.07.85-3.37.85-1.97 0-3.52-.6-4.64-1.82-1.13-1.2-1.7-2.9-1.7-5.08 0-1.38.26-2.59.77-3.62a5.66 5.66 0 0 1 2.2-2.4 6.45 6.45 0 0 1 3.37-.85Zm0 2.83a1.9 1.9 0 0 0-1.76.98 6.19 6.19 0 0 0-.58 3.06c0 1.42.19 2.45.57 3.1.38.65.97.97 1.77.97.78 0 1.36-.33 1.75-.98.4-.66.59-1.68.59-3.06 0-1.42-.2-2.45-.58-3.1a1.9 1.9 0 0 0-1.76-.97ZM426.84 549.45c1.13 0 2 .34 2.64 1.02.63.69.95 1.65.95 2.88v9.46h-3.85V554c0-.65-.1-1.1-.3-1.35-.21-.26-.52-.38-.92-.38-.78 0-1.53.56-2.24 1.68v8.85h-3.85v-12.94h3.36l.27 1.53a5.83 5.83 0 0 1 1.79-1.46 4.7 4.7 0 0 1 2.15-.49ZM439.18 545.92h4v16.89h-4zM451.02 545.92c2.65 0 4.77.6 6.37 1.79 1.6 1.2 2.4 3.38 2.4 6.57 0 3.13-.78 5.34-2.34 6.61-1.56 1.28-3.58 1.92-6.06 1.92h-5.07v-16.9h4.7Zm-.7 2.9v11.08h1.3c1.32 0 2.32-.4 3-1.23.69-.82 1.03-2.28 1.03-4.4a8.8 8.8 0 0 0-.51-3.36c-.34-.8-.8-1.34-1.4-1.64a4.7 4.7 0 0 0-2.16-.45h-1.27ZM463.52 558.8c.6 0 1.12.22 1.55.65.43.43.65.95.65 1.55 0 .62-.22 1.14-.65 1.57-.43.43-.95.65-1.55.65-.62 0-1.14-.22-1.57-.65a2.14 2.14 0 0 1-.65-1.57c0-.6.22-1.12.65-1.55.43-.43.95-.64 1.57-.64Zm0-8.42c.6 0 1.12.21 1.55.64.43.43.65.95.65 1.55 0 .62-.22 1.14-.65 1.57-.43.43-.95.65-1.55.65-.62 0-1.14-.22-1.57-.65a2.14 2.14 0 0 1-.65-1.57c0-.6.22-1.12.65-1.55.43-.43.95-.64 1.57-.64Z" style="fill:#073b4c;fill-rule:nonzero"/><path d="M526.45 602.73h-18.1v18.09h18.1v-18.09Zm-9.05 4.1c1.12 0 1.96.42 2.54 1.28.58.87.86 2.08.86 3.65 0 1.58-.28 2.8-.86 3.67a2.85 2.85 0 0 1-2.54 1.3 2.85 2.85 0 0 1-2.54-1.3 6.6 6.6 0 0 1-.86-3.67c0-1.57.29-2.78.86-3.64a2.86 2.86 0 0 1 2.54-1.3Zm0 8.35c.48 0 .83-.26 1.05-.78.22-.51.33-1.4.33-2.64 0-.5-.02-.94-.04-1.32l-2.17 4.48c.18.17.46.26.83.26Zm0-6.8c-.48 0-.83.27-1.05.79a7.19 7.19 0 0 0-.34 2.6c0 .78.03 1.42.09 1.9l2.3-4.82a.9.9 0 0 0-.4-.36 1.5 1.5 0 0 0-.6-.1Z" style="fill:#8a11b2"/><path d="M540.31 609c-.56.2-1.4.29-2.52.29.54.24.94.54 1.2.9.25.35.38.8.38 1.34 0 .57-.14 1.07-.42 1.51-.28.44-.68.78-1.21 1.04a4.3 4.3 0 0 1-2.9.24.75.75 0 0 0-.37.64c0 .41.35.61 1.05.61h1.34c.63 0 1.19.1 1.67.32.47.2.84.5 1.1.88.27.37.4.8.4 1.27 0 .88-.37 1.56-1.12 2.05a5.9 5.9 0 0 1-3.22.73c-1.01 0-1.8-.1-2.38-.31-.57-.21-.98-.51-1.22-.9-.25-.4-.37-.9-.37-1.52h1.9c0 .3.05.55.17.72.11.18.32.31.62.4.3.09.74.13 1.31.13.8 0 1.37-.1 1.7-.3.32-.2.49-.48.49-.85a.89.89 0 0 0-.38-.77 1.88 1.88 0 0 0-1.1-.27h-1.32c-.82 0-1.44-.16-1.86-.47a1.46 1.46 0 0 1-.62-1.2c0-.31.09-.6.27-.9.18-.28.43-.52.75-.72a2.89 2.89 0 0 1-1.16-1 2.7 2.7 0 0 1-.37-1.45 2.95 2.95 0 0 1 1.74-2.74 4.31 4.31 0 0 1 1.86-.38c.92.02 1.66-.05 2.23-.2a9.35 9.35 0 0 0 1.83-.77l.53 1.67Zm-4.56.72c-.47 0-.84.15-1.1.45-.28.3-.4.7-.4 1.2 0 .54.13.95.4 1.26.28.3.65.46 1.14.46.5 0 .88-.15 1.15-.45.26-.3.4-.73.4-1.28 0-1.1-.53-1.64-1.59-1.64ZM548.4 612.68c0 .1-.01.4-.05.85h-5.46c.07.85.29 1.45.66 1.81.37.36.87.55 1.48.55.38 0 .75-.07 1.09-.2.34-.12.7-.31 1.08-.58l.87 1.2a5 5 0 0 1-3.22 1.17c-1.33 0-2.35-.4-3.07-1.22a4.84 4.84 0 0 1-1.07-3.32c0-.89.15-1.68.46-2.4a3.57 3.57 0 0 1 3.4-2.26c1.22 0 2.16.4 2.83 1.17.67.77 1 1.85 1 3.23Zm-2.09-.61c0-1.52-.56-2.29-1.7-2.29-.5 0-.9.2-1.2.57-.29.38-.46.99-.52 1.82h3.42v-.1ZM554.93 608.29c.78 0 1.39.23 1.82.7.43.46.65 1.11.65 1.94v6.3h-2.1v-5.97c0-.51-.1-.87-.28-1.08-.18-.21-.44-.31-.8-.31-.36 0-.68.1-.97.33-.3.23-.58.55-.85.98v6.05h-2.1v-8.7h1.82l.16 1.14a3.23 3.23 0 0 1 2.65-1.38ZM566.99 612.68l-.05.85h-5.46c.06.85.28 1.45.65 1.81.38.36.87.55 1.49.55.38 0 .74-.07 1.08-.2.34-.12.7-.31 1.09-.58l.87 1.2a5 5 0 0 1-3.22 1.17c-1.33 0-2.35-.4-3.07-1.22a4.84 4.84 0 0 1-1.08-3.32c0-.89.15-1.68.46-2.4a3.56 3.56 0 0 1 3.4-2.26c1.22 0 2.16.4 2.83 1.17.67.77 1 1.85 1 3.23Zm-2.1-.61c0-1.52-.56-2.29-1.69-2.29-.51 0-.91.2-1.2.57-.3.38-.47.99-.52 1.82h3.42v-.1ZM571.63 608.29c1.17 0 2.2.34 3.09 1.03l-.83 1.24a4.09 4.09 0 0 0-2.18-.71c-.42 0-.74.08-.97.24a.74.74 0 0 0-.35.63c0 .2.05.36.15.5.1.13.28.25.53.37.26.11.64.24 1.15.38.94.25 1.64.59 2.1 1 .45.42.68 1 .68 1.75 0 .86-.35 1.54-1.06 2.03-.7.49-1.57.73-2.61.73-.71 0-1.36-.1-1.95-.33a4.73 4.73 0 0 1-1.52-.9l1.05-1.19c.76.57 1.55.86 2.37.86a2 2 0 0 0 1.13-.28.88.88 0 0 0 .42-.77c0-.26-.06-.46-.16-.6a1.3 1.3 0 0 0-.56-.4c-.27-.11-.69-.25-1.26-.42a4.2 4.2 0 0 1-1.95-1.01 2.24 2.24 0 0 1-.63-1.62c0-.48.14-.92.42-1.3.28-.38.67-.68 1.18-.9a4.4 4.4 0 0 1 1.76-.33ZM578.81 608.53v8.7h-2.1v-8.7h2.1Zm-1.07-4.4c.4 0 .72.12.97.37.24.24.37.55.37.9 0 .37-.13.67-.37.91-.25.25-.57.37-.97.37-.38 0-.7-.12-.94-.37a1.21 1.21 0 0 1-.37-.9c0-.36.12-.67.37-.91.25-.25.56-.37.94-.37ZM584.1 608.29c1.16 0 2.2.34 3.08 1.03l-.82 1.24a4.09 4.09 0 0 0-2.19-.71c-.41 0-.74.08-.97.24a.74.74 0 0 0-.34.63c0 .2.05.36.15.5.1.13.27.25.53.37.26.11.64.24 1.14.38.95.25 1.65.59 2.1 1 .46.42.68 1 .68 1.75 0 .86-.35 1.54-1.05 2.03-.7.49-1.57.73-2.61.73-.72 0-1.37-.1-1.95-.33a4.72 4.72 0 0 1-1.52-.9l1.05-1.19c.76.57 1.54.86 2.37.86a2 2 0 0 0 1.12-.28.88.88 0 0 0 .42-.77c0-.26-.05-.46-.15-.6a1.3 1.3 0 0 0-.56-.4c-.27-.11-.7-.25-1.26-.42a4.2 4.2 0 0 1-1.96-1.01 2.24 2.24 0 0 1-.62-1.62c0-.48.14-.92.42-1.3.28-.38.67-.68 1.18-.9a4.4 4.4 0 0 1 1.75-.33ZM596.84 608.29c1.28 0 2.28.4 3 1.22a4.92 4.92 0 0 1 1.08 3.37c0 .9-.17 1.7-.5 2.4a3.75 3.75 0 0 1-3.6 2.2c-1.28 0-2.28-.4-3-1.22a4.92 4.92 0 0 1-1.1-3.38c0-.91.17-1.71.5-2.4.33-.7.8-1.23 1.42-1.62a4.08 4.08 0 0 1 2.2-.57Zm0 1.6c-1.26 0-1.9.99-1.9 2.99 0 1.03.16 1.79.48 2.27.3.5.78.74 1.4.74.63 0 1.1-.25 1.4-.74.32-.5.48-1.25.48-2.27s-.16-1.78-.47-2.27a1.54 1.54 0 0 0-1.4-.73ZM609.85 617.23h-1.83l-.11-1.21c-.32.5-.7.86-1.13 1.1-.43.24-.95.36-1.54.36-.78 0-1.38-.24-1.8-.72a2.89 2.89 0 0 1-.63-1.98v-6.25h2.1v5.99c0 .5.09.84.26 1.05.17.21.44.32.81.32.67 0 1.26-.42 1.76-1.24v-6.12h2.1v8.7ZM617.37 616.82c-.31.22-.65.39-1.03.5-.38.1-.77.16-1.16.16-.86-.01-1.5-.25-1.95-.73-.45-.48-.67-1.18-.67-2.11v-4.6h-1.36v-1.5h1.36v-1.93l2.1-.25v2.17h2.03l-.21 1.52h-1.81v4.54c0 .42.07.73.22.92.15.18.38.28.7.28.32 0 .66-.1 1.03-.32l.74 1.35ZM623.05 608.29c1.1 0 1.91.4 2.44 1.2.53.8.79 1.92.79 3.37 0 .9-.14 1.7-.4 2.4-.27.69-.67 1.23-1.19 1.63-.52.4-1.14.6-1.85.6-.92 0-1.65-.33-2.19-.96v4.06l-2.1.23v-12.29h1.84l.12 1.07a3.4 3.4 0 0 1 1.16-.98c.44-.22.9-.33 1.38-.33Zm-.8 7.58c1.22 0 1.82-1 1.82-3 0-1.06-.13-1.83-.4-2.3-.28-.47-.7-.7-1.24-.7-.35 0-.68.1-.99.32-.3.21-.57.5-.79.86v3.91c.41.6.94.9 1.6.9ZM635.3 617.23h-1.82l-.11-1.21c-.32.5-.7.86-1.13 1.1-.43.24-.95.36-1.54.36-.78 0-1.38-.24-1.8-.72a2.89 2.89 0 0 1-.63-1.98v-6.25h2.1v5.99c0 .5.09.84.26 1.05.17.21.44.32.81.32.67 0 1.26-.42 1.76-1.24v-6.12h2.1v8.7ZM642.83 616.82c-.31.22-.65.39-1.03.5-.38.1-.77.16-1.16.16-.86-.01-1.5-.25-1.95-.73-.45-.48-.67-1.18-.67-2.11v-4.6h-1.36v-1.5h1.36v-1.93l2.1-.25v2.17h2.03l-.21 1.52h-1.81v4.54c0 .42.07.73.22.92.15.18.38.28.7.28.32 0 .66-.1 1.04-.32l.74 1.35Z" style="fill:#8a11b2;fill-rule:nonzero"/><g><path d="M.3-.54c.07 0 .13.02.18.07a.3.3 0 0 1 .06.2c0 .06 0 .1-.03.15A.23.23 0 0 1 .3.01a.23.23 0 0 1-.18-.07.3.3 0 0 1-.07-.2c0-.06.01-.1.03-.15a.22.22 0 0 1 .09-.1.25.25 0 0 1 .13-.03Zm0 .1c-.08 0-.12.05-.12.17 0 .07 0 .11.03.14a.1.1 0 0 0 .08.05.1.1 0 0 0 .09-.05.26.26 0 0 0 .03-.14C.4-.33.4-.37.38-.4a.1.1 0 0 0-.09-.05Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 524.12 687.6)"/><path d="M.38-.03a.23.23 0 0 1-.13.04C.19.01.15 0 .13-.03.1-.06.09-.1.09-.16v-.28H0v-.09H.1v-.12l.13-.01v.13h.12l-.01.1H.22v.27l.01.05c0 .02.02.02.04.02s.04 0 .06-.02l.05.08Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 533.72 687.6)"/><path d="M.36-.54c.05 0 .08.01.1.04.04.03.05.07.05.12V0H.38v-.36c0-.03 0-.06-.02-.07L.32-.45a.1.1 0 0 0-.06.02.23.23 0 0 0-.06.06V0H.09v-.74L.2-.75v.28a.2.2 0 0 1 .15-.07Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 539.89 687.6)"/><path d="M.51-.28v.06H.18c0 .05.01.08.04.1.02.03.05.04.09.04a.2.2 0 0 0 .13-.05l.05.07a.3.3 0 0 1-.2.07.24.24 0 0 1-.18-.07.3.3 0 0 1-.07-.2c0-.06.01-.1.03-.15a.25.25 0 0 1 .08-.1.22.22 0 0 1 .13-.03c.07 0 .13.02.17.07.04.04.06.1.06.2ZM.38-.3c0-.1-.03-.14-.1-.14a.09.09 0 0 0-.07.03.2.2 0 0 0-.03.11h.2Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 549.44 687.6)"/><path d="M.34-.54h.05L.37-.4a.2.2 0 0 0-.05 0 .09.09 0 0 0-.07.03.26.26 0 0 0-.04.1V0H.08v-.53h.1l.02.1A.19.19 0 0 1 .26-.5a.12.12 0 0 1 .08-.03Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 558.47 687.6)"/><path d="M.3-.54c.07 0 .13.02.18.07a.3.3 0 0 1 .06.2c0 .06 0 .1-.03.15A.23.23 0 0 1 .3.01a.23.23 0 0 1-.18-.07.3.3 0 0 1-.07-.2c0-.06.01-.1.03-.15a.22.22 0 0 1 .09-.1.25.25 0 0 1 .13-.03Zm0 .1c-.08 0-.12.05-.12.17 0 .07 0 .11.03.14a.1.1 0 0 0 .08.05.1.1 0 0 0 .09-.05.26.26 0 0 0 .03-.14C.4-.33.4-.37.38-.4a.1.1 0 0 0-.09-.05Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 569.23 687.6)"/><path d="M.5 0H.39v-.07a.2.2 0 0 1-.08.06.18.18 0 0 1-.09.03.14.14 0 0 1-.11-.05.18.18 0 0 1-.04-.12v-.38H.2v.36l.01.07.06.02c.04 0 .07-.03.1-.08v-.37H.5V0Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 578.83 687.6)"/><path d="M.38-.03a.23.23 0 0 1-.13.04C.19.01.15 0 .13-.03.1-.06.09-.1.09-.16v-.28H0v-.09H.1v-.12l.13-.01v.13h.12l-.01.1H.22v.27l.01.05c0 .02.02.02.04.02s.04 0 .06-.02l.05.08Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 588.33 687.6)"/><path d="M.35-.54c.07 0 .12.02.15.07s.05.12.05.2c0 .06-.01.1-.03.15a.22.22 0 0 1-.07.1.18.18 0 0 1-.11.03.16.16 0 0 1-.14-.05V.2L.09.22v-.75h.1l.02.07a.2.2 0 0 1 .16-.08ZM.3-.08c.08 0 .11-.06.11-.18 0-.07 0-.12-.02-.15A.08.08 0 0 0 .3-.45a.1.1 0 0 0-.06.02.15.15 0 0 0-.05.05v.24c.03.04.06.06.1.06Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 594.5 687.6)"/><path d="M.5 0H.39v-.07a.2.2 0 0 1-.08.06.18.18 0 0 1-.09.03.14.14 0 0 1-.11-.05.18.18 0 0 1-.04-.12v-.38H.2v.36l.01.07.06.02c.04 0 .07-.03.1-.08v-.37H.5V0Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 604.3 687.6)"/><path d="M.38-.03a.23.23 0 0 1-.13.04C.19.01.15 0 .13-.03.1-.06.09-.1.09-.16v-.28H0v-.09H.1v-.12l.13-.01v.13h.12l-.01.1H.22v.27l.01.05c0 .02.02.02.04.02s.04 0 .06-.02l.05.08Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 613.79 687.6)"/><path d="M.24-.54a.3.3 0 0 1 .2.06l-.06.07a.25.25 0 0 0-.13-.04.1.1 0 0 0-.06.02.04.04 0 0 0-.02.03v.03l.04.03a.6.6 0 0 0 .07.02l.13.06c.03.03.04.06.04.1 0 .06-.02.1-.07.13a.27.27 0 0 1-.15.05L.1 0A.3.3 0 0 1 0-.06l.07-.07c.05.03.1.05.14.05.03 0 .05 0 .07-.02a.05.05 0 0 0 .03-.04L.3-.18.27-.2A.67.67 0 0 0 .2-.23a.25.25 0 0 1-.12-.06.14.14 0 0 1-.04-.1c0-.03 0-.06.03-.08a.16.16 0 0 1 .07-.05.27.27 0 0 1 .1-.02Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 619.95 687.6)"/></g><g><path d="M.3-.54c.07 0 .13.02.18.07a.3.3 0 0 1 .06.2c0 .06 0 .1-.03.15A.23.23 0 0 1 .3.01a.23.23 0 0 1-.18-.07.3.3 0 0 1-.07-.2c0-.06.01-.1.03-.15a.22.22 0 0 1 .09-.1.25.25 0 0 1 .13-.03Zm0 .1c-.08 0-.12.05-.12.17 0 .07 0 .11.03.14a.1.1 0 0 0 .08.05.1.1 0 0 0 .09-.05.26.26 0 0 0 .03-.14C.4-.33.4-.37.38-.4a.1.1 0 0 0-.09-.05Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 326.94 616.54)"/><path d="M.38-.03a.23.23 0 0 1-.13.04C.19.01.15 0 .13-.03.1-.06.09-.1.09-.16v-.28H0v-.09H.1v-.12l.13-.01v.13h.12l-.01.1H.22v.27l.01.05c0 .02.02.02.04.02s.04 0 .06-.02l.05.08Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 336.55 616.54)"/><path d="M.36-.54c.05 0 .08.01.1.04.04.03.05.07.05.12V0H.38v-.36c0-.03 0-.06-.02-.07L.32-.45a.1.1 0 0 0-.06.02.23.23 0 0 0-.06.06V0H.09v-.74L.2-.75v.28a.2.2 0 0 1 .15-.07Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 342.72 616.54)"/><path d="M.51-.28v.06H.18c0 .05.01.08.04.1.02.03.05.04.09.04a.2.2 0 0 0 .13-.05l.05.07a.3.3 0 0 1-.2.07.24.24 0 0 1-.18-.07.3.3 0 0 1-.07-.2c0-.06.01-.1.03-.15a.25.25 0 0 1 .08-.1.22.22 0 0 1 .13-.03c.07 0 .13.02.17.07.04.04.06.1.06.2ZM.38-.3c0-.1-.03-.14-.1-.14a.09.09 0 0 0-.07.03.2.2 0 0 0-.03.11h.2Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 352.27 616.54)"/><path d="M.34-.54h.05L.37-.4a.2.2 0 0 0-.05 0 .09.09 0 0 0-.07.03.26.26 0 0 0-.04.1V0H.08v-.53h.1l.02.1A.19.19 0 0 1 .26-.5a.12.12 0 0 1 .08-.03Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 361.3 616.54)"/><path d="M.2-.53V0H.08v-.53H.2ZM.14-.8l.06.03.02.05c0 .02 0 .04-.02.06a.08.08 0 0 1-.06.02c-.02 0-.04 0-.06-.02a.07.07 0 0 1-.02-.06c0-.02 0-.04.02-.05A.08.08 0 0 1 .14-.8Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 372.06 616.54)"/><path d="M.36-.54c.05 0 .08.01.11.04s.04.07.04.12V0H.38v-.36c0-.03 0-.06-.02-.07L.32-.45a.1.1 0 0 0-.06.02.22.22 0 0 0-.06.06V0H.09v-.53h.1l.02.07a.2.2 0 0 1 .16-.08Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 376.7 616.54)"/><path d="M.35-.54c.07 0 .12.02.15.07s.05.12.05.2c0 .06-.01.1-.03.15a.22.22 0 0 1-.07.1.18.18 0 0 1-.11.03.16.16 0 0 1-.14-.05V.2L.09.22v-.75h.1l.02.07a.2.2 0 0 1 .16-.08ZM.3-.08c.08 0 .11-.06.11-.18 0-.07 0-.12-.02-.15A.08.08 0 0 0 .3-.45a.1.1 0 0 0-.06.02.15.15 0 0 0-.05.05v.24c.03.04.06.06.1.06Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 386.25 616.54)"/><path d="M.5 0H.39v-.07a.2.2 0 0 1-.08.06.18.18 0 0 1-.09.03.14.14 0 0 1-.11-.05.18.18 0 0 1-.04-.12v-.38H.2v.36l.01.07.06.02c.04 0 .07-.03.1-.08v-.37H.5V0Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 396.06 616.54)"/><path d="M.38-.03a.23.23 0 0 1-.13.04C.19.01.15 0 .13-.03.1-.06.09-.1.09-.16v-.28H0v-.09H.1v-.12l.13-.01v.13h.12l-.01.1H.22v.27l.01.05c0 .02.02.02.04.02s.04 0 .06-.02l.05.08Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 405.54 616.54)"/><path d="M.24-.54a.3.3 0 0 1 .2.06l-.06.07a.25.25 0 0 0-.13-.04.1.1 0 0 0-.06.02.04.04 0 0 0-.02.03v.03l.04.03a.6.6 0 0 0 .07.02l.13.06c.03.03.04.06.04.1 0 .06-.02.1-.07.13a.27.27 0 0 1-.15.05L.1 0A.3.3 0 0 1 0-.06l.07-.07c.05.03.1.05.14.05.03 0 .05 0 .07-.02a.05.05 0 0 0 .03-.04L.3-.18.27-.2A.67.67 0 0 0 .2-.23a.25.25 0 0 1-.12-.06.14.14 0 0 1-.04-.1c0-.03 0-.06.03-.08a.16.16 0 0 1 .07-.05.27.27 0 0 1 .1-.02Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 411.71 616.54)"/></g><g><path d="M1158.72 684.63H986.4a12.73 12.73 0 0 0-12.62 12.82v25.65c0 7.08 5.65 12.82 12.62 12.82h172.32" style="fill:none;stroke:#b4c4c9;stroke-width:2px;stroke-linecap:round;stroke-dasharray:2,4,0,0"/><path d="M.3-.54c.07 0 .13.02.18.07a.3.3 0 0 1 .06.2c0 .06 0 .1-.03.15A.23.23 0 0 1 .3.01a.23.23 0 0 1-.18-.07.3.3 0 0 1-.07-.2c0-.06.01-.1.03-.15a.22.22 0 0 1 .09-.1.25.25 0 0 1 .13-.03Zm0 .1c-.08 0-.12.05-.12.17 0 .07 0 .11.03.14a.1.1 0 0 0 .08.05.1.1 0 0 0 .09-.05.26.26 0 0 0 .03-.14C.4-.33.4-.37.38-.4a.1.1 0 0 0-.09-.05Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 1014.29 715.04)"/><path d="M.38-.03a.23.23 0 0 1-.13.04C.19.01.15 0 .13-.03.1-.06.09-.1.09-.16v-.28H0v-.09H.1v-.12l.13-.01v.13h.12l-.01.1H.22v.27l.01.05c0 .02.02.02.04.02s.04 0 .06-.02l.05.08Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 1023.89 715.04)"/><path d="M.36-.54c.05 0 .08.01.1.04.04.03.05.07.05.12V0H.38v-.36c0-.03 0-.06-.02-.07L.32-.45a.1.1 0 0 0-.06.02.23.23 0 0 0-.06.06V0H.09v-.74L.2-.75v.28a.2.2 0 0 1 .15-.07Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 1030.06 715.04)"/><path d="M.51-.28v.06H.18c0 .05.01.08.04.1.02.03.05.04.09.04a.2.2 0 0 0 .13-.05l.05.07a.3.3 0 0 1-.2.07.24.24 0 0 1-.18-.07.3.3 0 0 1-.07-.2c0-.06.01-.1.03-.15a.25.25 0 0 1 .08-.1.22.22 0 0 1 .13-.03c.07 0 .13.02.17.07.04.04.06.1.06.2ZM.38-.3c0-.1-.03-.14-.1-.14a.09.09 0 0 0-.07.03.2.2 0 0 0-.03.11h.2Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 1039.61 715.04)"/><path d="M.34-.54h.05L.37-.4a.2.2 0 0 0-.05 0 .09.09 0 0 0-.07.03.26.26 0 0 0-.04.1V0H.08v-.53h.1l.02.1A.19.19 0 0 1 .26-.5a.12.12 0 0 1 .08-.03Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 1048.64 715.04)"/><path d="M.3-.54c.07 0 .13.02.18.07a.3.3 0 0 1 .06.2c0 .06 0 .1-.03.15A.23.23 0 0 1 .3.01a.23.23 0 0 1-.18-.07.3.3 0 0 1-.07-.2c0-.06.01-.1.03-.15a.22.22 0 0 1 .09-.1.25.25 0 0 1 .13-.03Zm0 .1c-.08 0-.12.05-.12.17 0 .07 0 .11.03.14a.1.1 0 0 0 .08.05.1.1 0 0 0 .09-.05.26.26 0 0 0 .03-.14C.4-.33.4-.37.38-.4a.1.1 0 0 0-.09-.05Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 1059.4 715.04)"/><path d="M.5 0H.39v-.07a.2.2 0 0 1-.08.06.18.18 0 0 1-.09.03.14.14 0 0 1-.11-.05.18.18 0 0 1-.04-.12v-.38H.2v.36l.01.07.06.02c.04 0 .07-.03.1-.08v-.37H.5V0Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 1069 715.04)"/><path d="M.38-.03a.23.23 0 0 1-.13.04C.19.01.15 0 .13-.03.1-.06.09-.1.09-.16v-.28H0v-.09H.1v-.12l.13-.01v.13h.12l-.01.1H.22v.27l.01.05c0 .02.02.02.04.02s.04 0 .06-.02l.05.08Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 1078.5 715.04)"/><path d="M.35-.54c.07 0 .12.02.15.07s.05.12.05.2c0 .06-.01.1-.03.15a.22.22 0 0 1-.07.1.18.18 0 0 1-.11.03.16.16 0 0 1-.14-.05V.2L.09.22v-.75h.1l.02.07a.2.2 0 0 1 .16-.08ZM.3-.08c.08 0 .11-.06.11-.18 0-.07 0-.12-.02-.15A.08.08 0 0 0 .3-.45a.1.1 0 0 0-.06.02.15.15 0 0 0-.05.05v.24c.03.04.06.06.1.06Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 1084.66 715.04)"/><path d="M.5 0H.39v-.07a.2.2 0 0 1-.08.06.18.18 0 0 1-.09.03.14.14 0 0 1-.11-.05.18.18 0 0 1-.04-.12v-.38H.2v.36l.01.07.06.02c.04 0 .07-.03.1-.08v-.37H.5V0Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 1094.47 715.04)"/><path d="M.38-.03a.23.23 0 0 1-.13.04C.19.01.15 0 .13-.03.1-.06.09-.1.09-.16v-.28H0v-.09H.1v-.12l.13-.01v.13h.12l-.01.1H.22v.27l.01.05c0 .02.02.02.04.02s.04 0 .06-.02l.05.08Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 1103.96 715.04)"/><path d="M.24-.54a.3.3 0 0 1 .2.06l-.06.07a.25.25 0 0 0-.13-.04.1.1 0 0 0-.06.02.04.04 0 0 0-.02.03v.03l.04.03a.6.6 0 0 0 .07.02l.13.06c.03.03.04.06.04.1 0 .06-.02.1-.07.13a.27.27 0 0 1-.15.05L.1 0A.3.3 0 0 1 0-.06l.07-.07c.05.03.1.05.14.05.03 0 .05 0 .07-.02a.05.05 0 0 0 .03-.04L.3-.18.27-.2A.67.67 0 0 0 .2-.23a.25.25 0 0 1-.12-.06.14.14 0 0 1-.04-.1c0-.03 0-.06.03-.08a.16.16 0 0 1 .07-.05.27.27 0 0 1 .1-.02Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 1110.12 715.04)"/></g><g><path d="M772.01 522.02h172.32c6.97 0 12.62-5.74 12.62-12.82v-25.65c0-7.08-5.65-12.82-12.62-12.82H772.01" style="fill:none;stroke:#b4c4c9;stroke-width:2px;stroke-linecap:round;stroke-dasharray:2,4,0,0"/><path d="M.3-.54c.07 0 .13.02.18.07a.3.3 0 0 1 .06.2c0 .06 0 .1-.03.15A.23.23 0 0 1 .3.01a.23.23 0 0 1-.18-.07.3.3 0 0 1-.07-.2c0-.06.01-.1.03-.15a.22.22 0 0 1 .09-.1.25.25 0 0 1 .13-.03Zm0 .1c-.08 0-.12.05-.12.17 0 .07 0 .11.03.14a.1.1 0 0 0 .08.05.1.1 0 0 0 .09-.05.26.26 0 0 0 .03-.14C.4-.33.4-.37.38-.4a.1.1 0 0 0-.09-.05Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 818.05 501.14)"/><path d="M.38-.03a.23.23 0 0 1-.13.04C.19.01.15 0 .13-.03.1-.06.09-.1.09-.16v-.28H0v-.09H.1v-.12l.13-.01v.13h.12l-.01.1H.22v.27l.01.05c0 .02.02.02.04.02s.04 0 .06-.02l.05.08Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 827.66 501.14)"/><path d="M.36-.54c.05 0 .08.01.1.04.04.03.05.07.05.12V0H.38v-.36c0-.03 0-.06-.02-.07L.32-.45a.1.1 0 0 0-.06.02.23.23 0 0 0-.06.06V0H.09v-.74L.2-.75v.28a.2.2 0 0 1 .15-.07Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 833.83 501.14)"/><path d="M.51-.28v.06H.18c0 .05.01.08.04.1.02.03.05.04.09.04a.2.2 0 0 0 .13-.05l.05.07a.3.3 0 0 1-.2.07.24.24 0 0 1-.18-.07.3.3 0 0 1-.07-.2c0-.06.01-.1.03-.15a.25.25 0 0 1 .08-.1.22.22 0 0 1 .13-.03c.07 0 .13.02.17.07.04.04.06.1.06.2ZM.38-.3c0-.1-.03-.14-.1-.14a.09.09 0 0 0-.07.03.2.2 0 0 0-.03.11h.2Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 843.38 501.14)"/><path d="M.34-.54h.05L.37-.4a.2.2 0 0 0-.05 0 .09.09 0 0 0-.07.03.26.26 0 0 0-.04.1V0H.08v-.53h.1l.02.1A.19.19 0 0 1 .26-.5a.12.12 0 0 1 .08-.03Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 852.41 501.14)"/><path d="M.2-.53V0H.08v-.53H.2ZM.14-.8l.06.03.02.05c0 .02 0 .04-.02.06a.08.08 0 0 1-.06.02c-.02 0-.04 0-.06-.02a.07.07 0 0 1-.02-.06c0-.02 0-.04.02-.05A.08.08 0 0 1 .14-.8Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 863.17 501.14)"/><path d="M.36-.54c.05 0 .08.01.11.04s.04.07.04.12V0H.38v-.36c0-.03 0-.06-.02-.07L.32-.45a.1.1 0 0 0-.06.02.22.22 0 0 0-.06.06V0H.09v-.53h.1l.02.07a.2.2 0 0 1 .16-.08Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 867.8 501.14)"/><path d="M.35-.54c.07 0 .12.02.15.07s.05.12.05.2c0 .06-.01.1-.03.15a.22.22 0 0 1-.07.1.18.18 0 0 1-.11.03.16.16 0 0 1-.14-.05V.2L.09.22v-.75h.1l.02.07a.2.2 0 0 1 .16-.08ZM.3-.08c.08 0 .11-.06.11-.18 0-.07 0-.12-.02-.15A.08.08 0 0 0 .3-.45a.1.1 0 0 0-.06.02.15.15 0 0 0-.05.05v.24c.03.04.06.06.1.06Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 877.36 501.14)"/><path d="M.5 0H.39v-.07a.2.2 0 0 1-.08.06.18.18 0 0 1-.09.03.14.14 0 0 1-.11-.05.18.18 0 0 1-.04-.12v-.38H.2v.36l.01.07.06.02c.04 0 .07-.03.1-.08v-.37H.5V0Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 887.16 501.14)"/><path d="M.38-.03a.23.23 0 0 1-.13.04C.19.01.15 0 .13-.03.1-.06.09-.1.09-.16v-.28H0v-.09H.1v-.12l.13-.01v.13h.12l-.01.1H.22v.27l.01.05c0 .02.02.02.04.02s.04 0 .06-.02l.05.08Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 896.65 501.14)"/><path d="M.24-.54a.3.3 0 0 1 .2.06l-.06.07a.25.25 0 0 0-.13-.04.1.1 0 0 0-.06.02.04.04 0 0 0-.02.03v.03l.04.03a.6.6 0 0 0 .07.02l.13.06c.03.03.04.06.04.1 0 .06-.02.1-.07.13a.27.27 0 0 1-.15.05L.1 0A.3.3 0 0 1 0-.06l.07-.07c.05.03.1.05.14.05.03 0 .05 0 .07-.02a.05.05 0 0 0 .03-.04L.3-.18.27-.2A.67.67 0 0 0 .2-.23a.25.25 0 0 1-.12-.06.14.14 0 0 1-.04-.1c0-.03 0-.06.03-.08a.16.16 0 0 1 .07-.05.27.27 0 0 1 .1-.02Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 902.82 501.14)"/></g><g><path d="M1158.72 328.13H986.75c-6.95 0-12.6 5.74-12.6 12.82v25.65c0 7.08 5.65 12.82 12.6 12.82h171.97" style="fill:none;stroke:#073b4c;stroke-width:3px;stroke-miterlimit:1"/><path d="M1129.35 344.73h18.09v18.09h-18.09z" style="fill:#8a11b2"/><path d="M1103.36 349.22v11.06h-2.07v-8.94l-2.47 1.5-.92-1.42 3.6-2.2h1.86ZM1109.63 349.02c1.3 0 2.28.5 2.95 1.48.68.99 1.01 2.4 1.01 4.26 0 1.86-.33 3.3-1 4.28a3.35 3.35 0 0 1-2.96 1.5c-1.3 0-2.28-.5-2.95-1.5-.68-.99-1.01-2.42-1.01-4.28 0-1.85.33-3.27 1-4.26a3.35 3.35 0 0 1 2.96-1.48Zm0 1.6c-.63 0-1.08.31-1.36.94-.29.63-.43 1.7-.43 3.2 0 1.51.14 2.59.43 3.22.28.64.74.96 1.36.96.63 0 1.08-.32 1.36-.95.3-.63.43-1.7.43-3.23 0-1.51-.14-2.58-.42-3.2-.29-.63-.74-.95-1.37-.95ZM1119.05 349.02c1.3 0 2.28.5 2.95 1.48.68.99 1.01 2.4 1.01 4.26 0 1.86-.33 3.3-1 4.28a3.35 3.35 0 0 1-2.96 1.5c-1.3 0-2.28-.5-2.95-1.5-.68-.99-1.01-2.42-1.01-4.28 0-1.85.33-3.27 1-4.26a3.35 3.35 0 0 1 2.96-1.48Zm0 1.6c-.62 0-1.08.31-1.36.94-.29.63-.43 1.7-.43 3.2 0 1.51.14 2.59.43 3.22.28.64.74.96 1.36.96.63 0 1.08-.32 1.37-.95.28-.63.42-1.7.42-3.23 0-1.51-.14-2.58-.42-3.2-.29-.63-.75-.95-1.37-.95Z" style="fill:#8a11b2;fill-rule:nonzero"/></g><g><path d="M1158.72 399.43H986.75c-6.95 0-12.6 5.74-12.6 12.82v25.65c0 7.08 5.65 12.82 12.6 12.82h171.97" style="fill:none;stroke:#073b4c;stroke-width:3px;stroke-miterlimit:1"/><path d="M1129.35 416.03h18.09v18.09h-18.09z" style="fill:#8a11b2"/><path d="M1113.02 422.08h-4.14v2.75c.54-.28 1.1-.42 1.67-.42.62 0 1.17.15 1.65.43.48.29.86.7 1.12 1.24.27.53.4 1.17.4 1.9a3.9 3.9 0 0 1-.5 2.01 3.5 3.5 0 0 1-1.45 1.36c-.63.32-1.35.48-2.17.48a4.48 4.48 0 0 1-3.49-1.56l1.2-1.12c.64.7 1.38 1.05 2.24 1.05.62 0 1.12-.19 1.47-.57.36-.39.54-.93.54-1.65 0-1.37-.6-2.05-1.78-2.05-.25 0-.49.03-.7.09-.23.06-.47.15-.73.29h-1.5v-5.8h6.42l-.25 1.57ZM1119.05 420.32c1.3 0 2.28.5 2.95 1.48.68.99 1.01 2.4 1.01 4.26 0 1.86-.33 3.3-1 4.28a3.35 3.35 0 0 1-2.96 1.5c-1.3 0-2.28-.5-2.95-1.5-.68-.99-1.01-2.42-1.01-4.28 0-1.85.33-3.27 1-4.26a3.35 3.35 0 0 1 2.96-1.48Zm0 1.6c-.62 0-1.08.31-1.36.94-.29.63-.43 1.7-.43 3.2 0 1.51.14 2.59.43 3.22.28.64.74.96 1.36.96.63 0 1.08-.32 1.37-.95.28-.63.42-1.7.42-3.23 0-1.51-.14-2.58-.42-3.2-.29-.63-.75-.95-1.37-.95Z" style="fill:#8a11b2;fill-rule:nonzero"/></g><g><path d="M1158.72 470.73H986.75c-6.95 0-12.6 5.74-12.6 12.82v25.65c0 7.08 5.65 12.82 12.6 12.82h171.97" style="fill:none;stroke:#073b4c;stroke-width:3px;stroke-miterlimit:1"/><path d="m1137.51 486.44 9.93 19.87h-19.86l9.93-19.87Z" style="fill:#3ab211"/><path d="M1109.47 491.62c.75 0 1.39.14 1.93.41.54.27.96.65 1.24 1.12a3 3 0 0 1 .43 1.58 4.2 4.2 0 0 1-.4 1.8 8.24 8.24 0 0 1-1.34 1.91c-.63.7-1.54 1.63-2.75 2.78h4.74l-.23 1.66h-6.9v-1.54a93.9 93.9 0 0 0 3.03-3.17 9.48 9.48 0 0 0 1.3-1.76c.25-.49.38-1 .38-1.52 0-.5-.14-.9-.44-1.18a1.58 1.58 0 0 0-1.15-.43c-.43 0-.8.1-1.13.27-.32.18-.66.48-1.01.9l-1.28-1.02a4.34 4.34 0 0 1 3.58-1.81ZM1118.68 491.62c1.3 0 2.28.5 2.95 1.48.68.99 1.01 2.4 1.01 4.26 0 1.86-.33 3.3-1 4.28a3.35 3.35 0 0 1-2.96 1.5c-1.3 0-2.28-.5-2.95-1.5-.68-.99-1.01-2.42-1.01-4.28 0-1.85.33-3.27 1-4.26a3.35 3.35 0 0 1 2.96-1.48Zm0 1.6c-.63 0-1.08.31-1.36.94-.29.63-.43 1.7-.43 3.2 0 1.51.14 2.59.43 3.22.28.64.74.96 1.36.96.63 0 1.08-.32 1.37-.95.28-.63.42-1.7.42-3.23 0-1.51-.14-2.58-.42-3.2-.29-.63-.74-.95-1.37-.95Z" style="fill:#3ab211;fill-rule:nonzero"/></g><g><path d="M1158.72 542.02H986.75c-6.95 0-12.6 5.75-12.6 12.83v25.65c0 7.08 5.65 12.82 12.6 12.82h171.97" style="fill:none;stroke:#073b4c;stroke-width:3px;stroke-miterlimit:1"/><path d="m1137.51 557.74 9.93 19.87h-19.86l9.93-19.87Z" style="fill:#3ab211"/><path d="M1111.43 568.25c1.51.68 2.27 1.66 2.27 2.96 0 .6-.17 1.15-.51 1.64-.34.48-.82.87-1.44 1.15-.62.29-1.34.43-2.16.43a5 5 0 0 1-2.12-.42 3.33 3.33 0 0 1-1.4-1.14 2.82 2.82 0 0 1-.5-1.63c0-1.27.7-2.2 2.11-2.8-1.1-.6-1.66-1.47-1.66-2.61 0-.58.16-1.1.48-1.54.33-.44.77-.78 1.32-1.02a4.88 4.88 0 0 1 3.64-.03 3 3 0 0 1 1.31.98c.32.43.49.94.49 1.53 0 1.04-.61 1.87-1.83 2.5Zm-1.8-3.85c-.49 0-.87.13-1.15.38-.28.25-.42.61-.42 1.08 0 .44.13.79.4 1.05.26.26.68.49 1.26.7l.31.11c.43-.26.73-.54.91-.83.19-.29.28-.64.28-1.04 0-.45-.14-.8-.42-1.06-.27-.26-.66-.4-1.16-.4Zm0 8.47c.61 0 1.08-.15 1.42-.46.34-.3.51-.7.51-1.2s-.15-.9-.44-1.2c-.3-.29-.82-.57-1.58-.84l-.51-.18a2.32 2.32 0 0 0-1.33 2.18c0 .53.17.95.52 1.25.35.3.83.45 1.42.45ZM1118.99 562.92c1.3 0 2.28.5 2.95 1.48.68.99 1.01 2.4 1.01 4.26 0 1.86-.33 3.3-1 4.28a3.34 3.34 0 0 1-2.96 1.5c-1.3 0-2.28-.5-2.95-1.5-.68-.99-1.01-2.42-1.01-4.28 0-1.85.33-3.27 1-4.26a3.35 3.35 0 0 1 2.96-1.48Zm0 1.6c-.63 0-1.08.31-1.36.94-.29.63-.43 1.7-.43 3.2 0 1.51.14 2.59.42 3.22.29.64.75.96 1.37.96.63 0 1.08-.32 1.36-.95.29-.63.43-1.7.43-3.23 0-1.51-.14-2.58-.42-3.2-.29-.63-.74-.95-1.37-.95Z" style="fill:#3ab211;fill-rule:nonzero"/><path d="M1083.36 567.67c0-7.67-6.24-13.9-13.91-13.9h-68.18a13.92 13.92 0 0 0 0 27.82h68.18c7.67 0 13.91-6.24 13.91-13.92Zm-1.5 0c0-6.85-5.56-12.4-12.41-12.4h-68.18a12.42 12.42 0 0 0 0 24.82h68.18c6.85 0 12.41-5.56 12.41-12.42Z" style="fill:#3ab211"/><path d="M1006.12 562.54c1.15 0 2.02.45 2.61 1.33.6.9.89 2.14.89 3.76 0 1.62-.3 2.88-.89 3.77-.6.9-1.46 1.34-2.61 1.34a2.93 2.93 0 0 1-2.61-1.34c-.6-.9-.89-2.15-.89-3.77s.3-2.87.89-3.76a2.94 2.94 0 0 1 2.61-1.33Zm0 1.61c-.5 0-.86.27-1.08.8a7.4 7.4 0 0 0-.35 2.68c0 .8.03 1.46.09 1.96l2.36-4.96a.93.93 0 0 0-.4-.37c-.16-.07-.37-.1-.62-.1Zm0 6.99c.5 0 .85-.27 1.08-.8a7.7 7.7 0 0 0 .33-2.71c0-.52-.01-.97-.04-1.36l-2.22 4.6c.18.18.47.27.85.27ZM1016.37 564.87l1.23 1.23-1.89 1.83 1.9 1.87-1.24 1.23-1.85-1.9-1.85 1.9-1.23-1.23 1.9-1.87-1.9-1.83 1.23-1.23 1.85 1.87 1.85-1.87ZM1022.92 562.54c1.15 0 2.02.45 2.61 1.33.6.9.89 2.14.89 3.76 0 1.62-.3 2.88-.89 3.77-.6.9-1.46 1.34-2.61 1.34a2.93 2.93 0 0 1-2.61-1.34c-.6-.9-.89-2.15-.89-3.77s.3-2.87.89-3.76a2.94 2.94 0 0 1 2.61-1.33Zm0 1.61c-.5 0-.86.27-1.08.8a7.4 7.4 0 0 0-.35 2.68c0 .8.03 1.46.09 1.96l2.36-4.96a.93.93 0 0 0-.4-.37c-.16-.07-.37-.1-.62-.1Zm0 6.99c.5 0 .85-.27 1.08-.8a7.7 7.7 0 0 0 .33-2.71c0-.52-.01-.97-.04-1.36l-2.22 4.6c.18.18.47.27.85.27ZM1033.03 570.82h1.8v1.68h-6.3v-1.68h2.34v-5.85l-2 1.26-.94-1.53 3.14-1.9h1.96v8.02ZM1039.72 562.54c1.15 0 2.02.45 2.61 1.33.6.9.89 2.14.89 3.76 0 1.62-.3 2.88-.89 3.77-.6.9-1.46 1.34-2.61 1.34a2.93 2.93 0 0 1-2.61-1.34c-.6-.9-.89-2.15-.89-3.77s.3-2.87.89-3.76a2.94 2.94 0 0 1 2.61-1.33Zm0 1.61c-.5 0-.86.27-1.08.8a7.4 7.4 0 0 0-.35 2.68c0 .8.03 1.46.09 1.96l2.36-4.96a.93.93 0 0 0-.4-.37c-.16-.07-.37-.1-.62-.1Zm0 6.99c.5 0 .85-.27 1.08-.8a7.7 7.7 0 0 0 .33-2.71c0-.52-.01-.97-.04-1.36l-2.22 4.6c.18.18.47.27.85.27ZM1047.78 562.54c.7 0 1.32.13 1.82.38s.88.6 1.14 1.02c.26.42.39.89.39 1.39 0 .53-.13 1.05-.37 1.54a7.5 7.5 0 0 1-1.2 1.66c-.55.61-1.34 1.37-2.35 2.27h4.14l-.24 1.7h-6.44v-1.57c1.15-1.11 2-1.98 2.58-2.6.57-.62.98-1.15 1.24-1.58.25-.43.38-.84.38-1.22 0-.4-.11-.72-.33-.94-.23-.23-.55-.34-.97-.34-.36 0-.68.08-.95.23-.27.16-.54.4-.8.75l-1.34-1.02c.38-.53.84-.94 1.38-1.23a4 4 0 0 1 1.92-.44ZM1056.52 562.54c1.15 0 2.02.45 2.61 1.33.6.9.89 2.14.89 3.76 0 1.62-.3 2.88-.89 3.77-.6.9-1.46 1.34-2.61 1.34a2.93 2.93 0 0 1-2.61-1.34c-.6-.9-.89-2.15-.89-3.77s.3-2.87.89-3.76a2.94 2.94 0 0 1 2.61-1.33Zm0 1.61c-.5 0-.86.27-1.08.8a7.4 7.4 0 0 0-.35 2.68c0 .8.03 1.46.09 1.96l2.36-4.96a.93.93 0 0 0-.4-.37c-.16-.07-.37-.1-.62-.1Zm0 6.99c.5 0 .85-.27 1.08-.8a7.7 7.7 0 0 0 .33-2.71c0-.52-.01-.97-.04-1.36l-2.22 4.6c.18.18.47.27.85.27ZM1064.53 562.54c.67 0 1.26.12 1.76.34.5.22.88.53 1.15.9.26.38.4.8.4 1.26 0 .6-.18 1.08-.53 1.47-.35.38-.84.66-1.46.85 1.53.2 2.3 1 2.3 2.4 0 .56-.16 1.06-.46 1.51-.3.46-.74.81-1.31 1.07-.57.27-1.23.4-1.99.4-.71 0-1.35-.13-1.93-.38a4.15 4.15 0 0 1-1.49-1.08l1.25-1.16c.53.61 1.2.92 2.02.92.49 0 .89-.12 1.19-.38.3-.25.44-.6.44-1.05 0-.97-.54-1.45-1.63-1.45h-.89l.26-1.51h.61c.45 0 .8-.11 1.07-.33.27-.22.4-.54.4-.95 0-.36-.13-.65-.39-.86-.26-.2-.6-.31-1.02-.31-.7 0-1.35.28-1.93.84l-1.14-1.18a4.59 4.59 0 0 1 3.32-1.32Z" style="fill:#3ab211;fill-rule:nonzero"/></g><g><path d="M1159.4 613.33H987.43c-6.95 0-12.6 5.74-12.6 12.82v25.65c0 7.08 5.65 12.83 12.6 12.83h171.97" style="fill:none;stroke:#073b4c;stroke-width:3px;stroke-miterlimit:1"/><path d="m1138.19 629.04 9.93 19.87h-19.86l9.93-19.87Z" style="fill:#3ab211"/><path d="M1119.67 634.22c1.3 0 2.28.5 2.95 1.48.68.99 1.01 2.4 1.01 4.26 0 1.86-.33 3.3-1 4.28a3.34 3.34 0 0 1-2.96 1.5c-1.3 0-2.28-.5-2.95-1.5-.68-.99-1.01-2.42-1.01-4.28 0-1.85.33-3.27 1-4.26a3.35 3.35 0 0 1 2.96-1.48Zm0 1.6c-.63 0-1.08.31-1.37.94-.28.63-.42 1.7-.42 3.2 0 1.51.14 2.59.42 3.22.29.64.75.96 1.37.96.63 0 1.08-.32 1.36-.95.29-.63.43-1.7.43-3.23 0-1.51-.14-2.58-.43-3.2-.28-.63-.73-.95-1.36-.95Z" style="fill:#3ab211;fill-rule:nonzero"/><path d="M1084.04 638.98c0-7.68-6.23-13.92-13.91-13.92h-68.18a13.92 13.92 0 0 0 0 27.83h68.18c7.68 0 13.91-6.24 13.91-13.91Zm-1.5 0c0-6.86-5.56-12.42-12.41-12.42h-68.18a12.42 12.42 0 0 0 0 24.83h68.18c6.85 0 12.41-5.56 12.41-12.41Z" style="fill:#3ab211"/><path d="M1006.8 633.84c1.15 0 2.02.45 2.61 1.33.6.9.89 2.14.89 3.76 0 1.62-.3 2.88-.89 3.77-.6.9-1.46 1.34-2.61 1.34a2.93 2.93 0 0 1-2.61-1.34c-.6-.9-.89-2.15-.89-3.77s.3-2.87.89-3.76a2.94 2.94 0 0 1 2.61-1.33Zm0 1.61c-.5 0-.86.27-1.08.8a7.43 7.43 0 0 0-.35 2.68c0 .8.03 1.46.09 1.96l2.36-4.96a.93.93 0 0 0-.4-.37c-.16-.07-.37-.1-.62-.1Zm0 6.99c.5 0 .85-.27 1.08-.8a7.7 7.7 0 0 0 .33-2.71c0-.52-.01-.97-.04-1.36l-2.22 4.6c.18.18.47.27.85.27ZM1017.04 636.17l1.23 1.23-1.89 1.83 1.9 1.87-1.24 1.23-1.85-1.9-1.85 1.9-1.23-1.23 1.9-1.87-1.9-1.83 1.23-1.23 1.85 1.87 1.85-1.87ZM1023.6 633.84c1.15 0 2.02.45 2.61 1.33.6.9.89 2.14.89 3.76 0 1.62-.3 2.88-.89 3.77-.6.9-1.46 1.34-2.61 1.34a2.93 2.93 0 0 1-2.61-1.34c-.6-.9-.89-2.15-.89-3.77s.3-2.87.89-3.76a2.94 2.94 0 0 1 2.61-1.33Zm0 1.61c-.5 0-.86.27-1.08.8a7.43 7.43 0 0 0-.35 2.68c0 .8.03 1.46.09 1.96l2.36-4.96a.93.93 0 0 0-.4-.37c-.16-.07-.37-.1-.62-.1Zm0 6.99c.5 0 .85-.27 1.08-.8a7.7 7.7 0 0 0 .33-2.71c0-.52-.01-.97-.04-1.36l-2.22 4.6c.18.18.47.27.85.27ZM1033.7 642.12h1.8v1.68h-6.3v-1.68h2.34v-5.85l-2 1.26-.94-1.53 3.14-1.9h1.96v8.02ZM1040.4 633.84c1.15 0 2.02.45 2.61 1.33.6.9.89 2.14.89 3.76 0 1.62-.3 2.88-.89 3.77-.6.9-1.46 1.34-2.61 1.34a2.93 2.93 0 0 1-2.61-1.34c-.6-.9-.89-2.15-.89-3.77s.3-2.87.89-3.76a2.94 2.94 0 0 1 2.61-1.33Zm0 1.61c-.5 0-.86.27-1.08.8a7.43 7.43 0 0 0-.35 2.68c0 .8.03 1.46.09 1.96l2.36-4.96a.93.93 0 0 0-.4-.37c-.16-.07-.37-.1-.62-.1Zm0 6.99c.5 0 .85-.27 1.08-.8a7.7 7.7 0 0 0 .33-2.71c0-.52-.01-.97-.04-1.36l-2.22 4.6c.18.18.47.27.85.27ZM1048.46 633.84c.71 0 1.32.13 1.82.38s.89.6 1.14 1.02c.26.42.39.89.39 1.39 0 .53-.12 1.05-.37 1.54-.24.5-.64 1.05-1.2 1.66-.55.61-1.34 1.37-2.35 2.27h4.14l-.24 1.7h-6.44v-1.57c1.15-1.11 2-1.98 2.58-2.6.57-.62.98-1.14 1.24-1.58.25-.43.38-.84.38-1.22 0-.4-.11-.72-.33-.94-.23-.23-.55-.34-.97-.34-.36 0-.68.08-.95.23-.27.16-.54.4-.8.75l-1.34-1.02c.38-.53.84-.94 1.38-1.23a4 4 0 0 1 1.92-.44ZM1057.2 633.84c1.15 0 2.02.45 2.61 1.33.6.9.89 2.14.89 3.76 0 1.62-.3 2.88-.89 3.77-.6.9-1.46 1.34-2.61 1.34a2.93 2.93 0 0 1-2.61-1.34c-.6-.9-.89-2.15-.89-3.77s.3-2.87.89-3.76a2.94 2.94 0 0 1 2.61-1.33Zm0 1.61c-.5 0-.86.27-1.08.8a7.43 7.43 0 0 0-.35 2.68c0 .8.03 1.46.09 1.96l2.36-4.96a.93.93 0 0 0-.4-.37c-.16-.07-.37-.1-.62-.1Zm0 6.99c.5 0 .85-.27 1.08-.8a7.7 7.7 0 0 0 .33-2.71c0-.52-.01-.97-.04-1.36l-2.22 4.6c.18.18.47.27.85.27ZM1065.2 633.84c.67 0 1.26.12 1.76.34.5.22.88.53 1.15.9.26.38.4.8.4 1.26 0 .6-.18 1.08-.53 1.47-.35.38-.84.66-1.46.85 1.53.2 2.3 1 2.3 2.4 0 .56-.16 1.06-.46 1.51-.3.46-.74.81-1.31 1.07-.57.27-1.23.4-1.99.4a4.8 4.8 0 0 1-1.93-.38 4.17 4.17 0 0 1-1.49-1.08l1.25-1.16c.53.61 1.2.92 2.02.92.5 0 .89-.12 1.19-.38.3-.25.44-.6.44-1.05 0-.97-.54-1.45-1.63-1.45h-.89l.26-1.51h.61c.45 0 .8-.11 1.07-.33.27-.22.4-.54.4-.95 0-.36-.13-.65-.39-.86-.26-.2-.6-.31-1.02-.31-.7 0-1.35.28-1.93.84l-1.14-1.18a4.6 4.6 0 0 1 3.32-1.32Z" style="fill:#3ab211;fill-rule:nonzero"/></g><g><path d="M772.01 379.43h171.97c6.95 0 12.6-5.75 12.6-12.83v-25.65c0-7.08-5.65-12.82-12.6-12.82H772" style="fill:none;stroke:#073b4c;stroke-width:3px;stroke-miterlimit:1"/><path d="m812.04 343.94 9.83 19.67H802.2l9.84-19.67Zm0 7.67c1.14 0 2 .44 2.59 1.32.59.88.88 2.13.88 3.73 0 1.61-.3 2.86-.88 3.75a2.92 2.92 0 0 1-2.6 1.32c-1.13 0-2-.44-2.59-1.32a6.73 6.73 0 0 1-.88-3.75c0-1.6.3-2.85.88-3.73a2.92 2.92 0 0 1 2.6-1.32Zm0 8.54c.49 0 .84-.26 1.07-.8.22-.52.33-1.42.33-2.7 0-.5-.01-.95-.04-1.34l-2.21 4.58c.18.17.47.26.85.26Zm0-6.94c-.5 0-.85.27-1.08.8a7.37 7.37 0 0 0-.34 2.65c0 .8.02 1.45.08 1.94l2.35-4.92a.92.92 0 0 0-.4-.37c-.16-.07-.36-.1-.61-.1Z" style="fill:#3ab211"/><path d="M834.95 351.79c-.56.2-1.4.3-2.52.3.54.24.93.54 1.2.9.25.35.38.8.38 1.33 0 .57-.14 1.08-.42 1.51-.28.44-.69.79-1.22 1.04a4.3 4.3 0 0 1-2.9.25.75.75 0 0 0-.36.64c0 .4.35.6 1.05.6h1.33c.64 0 1.2.11 1.67.32.48.2.85.5 1.11.88.26.38.4.8.4 1.27 0 .88-.38 1.56-1.12 2.05a5.9 5.9 0 0 1-3.23.73c-1 0-1.8-.1-2.37-.3-.58-.22-.99-.52-1.23-.91-.24-.4-.36-.9-.36-1.52h1.9c0 .31.05.55.16.73.12.17.33.3.63.4.3.08.74.12 1.3.12.8 0 1.37-.1 1.7-.3.33-.19.5-.47.5-.85a.89.89 0 0 0-.38-.76 1.88 1.88 0 0 0-1.1-.27h-1.32c-.82 0-1.44-.16-1.86-.48a1.45 1.45 0 0 1-.63-1.2c0-.3.1-.6.28-.89.18-.28.43-.53.74-.72a2.87 2.87 0 0 1-1.16-1.01c-.24-.4-.37-.88-.37-1.44a2.95 2.95 0 0 1 1.74-2.74 4.3 4.3 0 0 1 1.87-.39c.92.02 1.66-.05 2.23-.2a9.23 9.23 0 0 0 1.83-.77l.53 1.68Zm-4.56.72c-.47 0-.84.15-1.11.45-.27.3-.4.71-.4 1.21 0 .53.13.95.4 1.25.28.31.66.46 1.14.46.5 0 .89-.15 1.15-.45.27-.3.4-.72.4-1.27 0-1.1-.53-1.65-1.58-1.65ZM843.04 355.47l-.05.86h-5.46c.06.84.28 1.45.66 1.8.37.37.86.55 1.48.55.38 0 .74-.06 1.08-.19.34-.12.7-.32 1.09-.58l.87 1.2a5 5 0 0 1-3.23 1.17c-1.32 0-2.34-.41-3.06-1.22a4.84 4.84 0 0 1-1.08-3.32c0-.9.15-1.69.46-2.4a3.57 3.57 0 0 1 3.4-2.26c1.22 0 2.16.39 2.83 1.16.67.78 1 1.85 1 3.23Zm-2.1-.6c0-1.53-.56-2.3-1.69-2.3-.51 0-.91.2-1.2.58-.3.37-.47.98-.52 1.81h3.42v-.1ZM849.57 351.08c.77 0 1.38.24 1.81.7.44.47.65 1.12.65 1.95v6.3h-2.1v-5.97c0-.52-.1-.88-.27-1.09-.18-.2-.45-.3-.8-.3-.36 0-.69.1-.98.33-.29.22-.57.55-.85.98v6.05h-2.1v-8.7h1.82l.17 1.13a3.24 3.24 0 0 1 2.65-1.38ZM861.62 355.47l-.05.86h-5.46c.07.84.29 1.45.66 1.8.37.37.87.55 1.48.55.38 0 .75-.06 1.09-.19.34-.12.7-.32 1.08-.58l.87 1.2a5 5 0 0 1-3.22 1.17c-1.33 0-2.35-.41-3.07-1.22a4.84 4.84 0 0 1-1.08-3.32c0-.9.16-1.69.46-2.4a3.57 3.57 0 0 1 3.4-2.26c1.23 0 2.17.39 2.84 1.16.67.78 1 1.85 1 3.23Zm-2.09-.6c0-1.53-.56-2.3-1.7-2.3-.5 0-.9.2-1.2.58-.29.37-.46.98-.52 1.81h3.42v-.1ZM866.26 351.08c1.17 0 2.2.35 3.1 1.04l-.83 1.23a4.08 4.08 0 0 0-2.19-.7c-.41 0-.74.07-.97.23a.74.74 0 0 0-.34.64c0 .2.05.36.14.49.1.13.28.26.54.37.26.12.64.24 1.14.39.94.25 1.64.58 2.1 1 .45.42.68 1 .68 1.74 0 .87-.35 1.55-1.05 2.03-.7.5-1.57.74-2.62.74-.7 0-1.36-.11-1.95-.33a4.7 4.7 0 0 1-1.52-.9l1.06-1.2c.75.58 1.54.86 2.37.86a2 2 0 0 0 1.12-.28.88.88 0 0 0 .42-.77c0-.25-.05-.45-.16-.6-.1-.15-.29-.28-.55-.4-.27-.1-.7-.25-1.26-.41a4.2 4.2 0 0 1-1.96-1.01 2.24 2.24 0 0 1-.63-1.62c0-.49.14-.92.42-1.3.28-.39.68-.69 1.19-.9a4.4 4.4 0 0 1 1.75-.34ZM873.45 351.33v8.7h-2.1v-8.7h2.1Zm-1.07-4.4c.4 0 .71.11.96.36s.37.55.37.91c0 .37-.12.67-.37.9-.25.25-.57.37-.96.37-.38 0-.7-.12-.95-.36a1.21 1.21 0 0 1-.37-.9c0-.37.13-.67.37-.92.25-.25.57-.37.95-.37ZM878.73 351.08c1.17 0 2.2.35 3.09 1.04l-.82 1.23a4.08 4.08 0 0 0-2.2-.7c-.4 0-.73.07-.96.23a.73.73 0 0 0-.35.64c0 .2.05.36.15.49.1.13.28.26.54.37.25.12.63.24 1.14.39.94.25 1.64.58 2.1 1 .45.42.68 1 .68 1.74 0 .87-.35 1.55-1.05 2.03-.7.5-1.58.74-2.62.74-.71 0-1.36-.11-1.95-.33a4.72 4.72 0 0 1-1.52-.9l1.05-1.2c.76.58 1.55.86 2.37.86a2 2 0 0 0 1.13-.28.88.88 0 0 0 .42-.77c0-.25-.06-.45-.16-.6-.1-.15-.29-.28-.56-.4a11.9 11.9 0 0 0-1.26-.41 4.2 4.2 0 0 1-1.95-1.01 2.24 2.24 0 0 1-.63-1.62c0-.49.14-.92.42-1.3.28-.39.67-.69 1.18-.9a4.4 4.4 0 0 1 1.76-.34ZM890.03 351.33v8.7h-2.1v-8.7h2.1Zm-1.07-4.4c.4 0 .71.11.96.36s.37.55.37.91c0 .37-.12.67-.37.9-.25.25-.57.37-.96.37s-.7-.12-.95-.36a1.21 1.21 0 0 1-.37-.9c0-.37.12-.67.37-.92s.56-.37.95-.37ZM897.2 351.08c.77 0 1.38.24 1.81.7.44.47.65 1.12.65 1.95v6.3h-2.1v-5.97c0-.52-.1-.88-.27-1.09-.18-.2-.45-.3-.8-.3-.36 0-.69.1-.98.33-.29.22-.57.55-.85.98v6.05h-2.1v-8.7h1.82l.17 1.13a3.23 3.23 0 0 1 2.65-1.38ZM906.62 351.08c1.1 0 1.9.4 2.43 1.2.53.8.8 1.93.8 3.37 0 .9-.14 1.7-.4 2.4-.28.7-.67 1.24-1.2 1.63-.51.4-1.13.6-1.84.6-.92 0-1.65-.32-2.19-.96v4.06l-2.1.23v-12.28h1.84l.11 1.07a3.4 3.4 0 0 1 1.17-.99c.44-.22.9-.33 1.38-.33Zm-.8 7.58c1.21 0 1.82-1 1.82-2.99 0-1.06-.14-1.83-.41-2.3-.27-.47-.69-.7-1.23-.7-.36 0-.68.1-1 .31-.3.22-.56.5-.78.87v3.91c.4.6.94.9 1.6.9ZM918.87 360.03h-1.82l-.12-1.22c-.31.5-.69.86-1.12 1.1-.44.24-.95.37-1.54.37-.78 0-1.38-.24-1.8-.72a2.89 2.89 0 0 1-.64-1.98v-6.25h2.11v5.99c0 .49.08.84.25 1.05.17.2.45.31.82.31.67 0 1.25-.41 1.76-1.23v-6.12h2.1v8.7ZM926.39 359.62c-.3.22-.65.38-1.03.5-.38.1-.76.16-1.16.16-.85-.01-1.5-.26-1.95-.74-.44-.47-.66-1.18-.66-2.1v-4.6h-1.37v-1.51h1.37v-1.93l2.1-.24v2.17h2.03l-.22 1.51h-1.8v4.54c0 .43.07.74.21.92.15.19.39.28.7.28.32 0 .67-.1 1.04-.31l.74 1.35Z" style="fill:#3ab211;fill-rule:nonzero"/></g><g><path d="M772.01 450.73h171.97c6.95 0 12.6-5.75 12.6-12.83v-25.65c0-7.08-5.65-12.82-12.6-12.82H772" style="fill:none;stroke:#073b4c;stroke-width:3px;stroke-miterlimit:1"/><path d="M820.68 416.03H802.6v18.09h18.1v-18.09Zm-9.04 4.1c1.11 0 1.96.42 2.54 1.29.57.86.86 2.07.86 3.64a6.6 6.6 0 0 1-.86 3.67 2.85 2.85 0 0 1-2.54 1.3 2.85 2.85 0 0 1-2.54-1.3 6.58 6.58 0 0 1-.86-3.67c0-1.57.28-2.78.86-3.64a2.86 2.86 0 0 1 2.54-1.3Zm0 8.35c.48 0 .83-.26 1.05-.78.21-.51.32-1.4.32-2.64 0-.5-.01-.94-.04-1.32l-2.16 4.48c.18.17.46.26.83.26Zm0-6.8c-.48 0-.83.27-1.06.79a7.2 7.2 0 0 0-.33 2.6c0 .78.03 1.42.08 1.9l2.3-4.82a.9.9 0 0 0-.4-.36 1.5 1.5 0 0 0-.6-.1Z" style="fill:#8a11b2"/><path d="M834.55 422.3c-.56.2-1.4.29-2.52.29.54.24.94.54 1.2.9.25.35.38.8.38 1.34 0 .57-.14 1.07-.42 1.51-.28.44-.69.78-1.22 1.04a4.3 4.3 0 0 1-2.9.24.75.75 0 0 0-.36.64c0 .41.35.61 1.05.61h1.33c.64 0 1.2.1 1.67.32.48.2.85.5 1.11.87.27.38.4.8.4 1.28 0 .88-.37 1.56-1.12 2.05a5.9 5.9 0 0 1-3.22.73c-1.01 0-1.8-.1-2.38-.31-.58-.21-.98-.51-1.23-.9-.24-.4-.36-.9-.36-1.52h1.9c0 .3.05.55.17.72.11.18.32.31.62.4.3.09.74.13 1.3.13.8 0 1.37-.1 1.7-.3.33-.2.5-.48.5-.85a.89.89 0 0 0-.38-.77 1.88 1.88 0 0 0-1.1-.27h-1.32c-.82 0-1.44-.16-1.86-.48a1.46 1.46 0 0 1-.62-1.2c0-.3.09-.6.27-.88.18-.29.43-.53.75-.73a2.88 2.88 0 0 1-1.16-1c-.25-.4-.37-.89-.37-1.45a2.95 2.95 0 0 1 1.73-2.74 4.31 4.31 0 0 1 1.87-.38c.92.02 1.66-.05 2.23-.2a9.35 9.35 0 0 0 1.83-.77l.53 1.67Zm-4.56.72c-.47 0-.84.15-1.1.45-.28.3-.41.7-.41 1.2 0 .53.13.95.4 1.26.28.3.66.46 1.14.46.5 0 .9-.15 1.16-.45.26-.3.39-.73.39-1.28 0-1.1-.53-1.64-1.58-1.64ZM842.64 425.98l-.05.85h-5.46c.07.85.28 1.45.66 1.81.37.37.86.55 1.48.55.38 0 .74-.07 1.08-.2.34-.12.7-.31 1.09-.58l.87 1.2a5 5 0 0 1-3.22 1.17c-1.33 0-2.35-.4-3.07-1.22a4.84 4.84 0 0 1-1.08-3.32c0-.89.16-1.68.46-2.4a3.56 3.56 0 0 1 3.4-2.26c1.22 0 2.17.4 2.84 1.17.67.77 1 1.85 1 3.23Zm-2.09-.61c0-1.52-.56-2.29-1.7-2.29-.5 0-.91.2-1.2.57-.3.38-.47.99-.52 1.82h3.42v-.1ZM849.17 421.59c.78 0 1.38.23 1.82.7.43.46.65 1.11.65 1.94v6.3h-2.11v-5.97c0-.51-.09-.87-.27-1.08-.18-.21-.45-.31-.8-.31-.36 0-.69.1-.98.33-.29.23-.57.55-.84.98v6.05h-2.1v-8.7h1.82l.16 1.14a3.23 3.23 0 0 1 2.65-1.38ZM861.22 425.98l-.04.85h-5.46c.06.85.28 1.45.65 1.81.38.37.87.55 1.48.55.39 0 .75-.07 1.09-.2.34-.12.7-.31 1.08-.58l.88 1.2a5 5 0 0 1-3.23 1.17c-1.32 0-2.35-.4-3.07-1.22a4.84 4.84 0 0 1-1.07-3.32c0-.89.15-1.68.46-2.4a3.56 3.56 0 0 1 3.4-2.26c1.22 0 2.16.4 2.83 1.17.67.77 1 1.85 1 3.23Zm-2.08-.61c0-1.52-.57-2.29-1.7-2.29-.51 0-.92.2-1.2.57-.3.38-.47.99-.52 1.82h3.42v-.1ZM865.86 421.59c1.18 0 2.2.34 3.1 1.03l-.83 1.24a4.08 4.08 0 0 0-2.19-.71c-.41 0-.74.08-.97.24a.74.74 0 0 0-.34.63c0 .2.05.36.15.5.1.13.27.25.53.36.26.12.64.25 1.14.4.95.24 1.65.58 2.1 1 .46.41.68 1 .68 1.74 0 .86-.35 1.54-1.05 2.03-.7.49-1.57.73-2.61.73-.72 0-1.37-.1-1.95-.33a4.73 4.73 0 0 1-1.52-.9l1.05-1.19c.76.57 1.55.86 2.37.86a2 2 0 0 0 1.12-.28.88.88 0 0 0 .42-.77c0-.26-.05-.46-.15-.6-.1-.15-.3-.28-.56-.4-.27-.11-.69-.25-1.26-.42a4.2 4.2 0 0 1-1.96-1.01 2.25 2.25 0 0 1-.62-1.62c0-.48.14-.92.42-1.3.28-.38.67-.69 1.18-.9a4.4 4.4 0 0 1 1.75-.33ZM873.05 421.83v8.7h-2.1v-8.7h2.1Zm-1.07-4.4c.4 0 .72.12.96.37.25.24.37.55.37.9 0 .37-.12.67-.37.91-.24.24-.57.36-.96.36-.38 0-.7-.12-.95-.36a1.21 1.21 0 0 1-.37-.9c0-.36.13-.67.37-.91.25-.25.57-.37.95-.37ZM878.33 421.59c1.17 0 2.2.34 3.1 1.03l-.83 1.24a4.09 4.09 0 0 0-2.19-.71c-.42 0-.74.08-.97.24a.74.74 0 0 0-.34.63c0 .2.04.36.14.5.1.13.28.25.54.36.26.12.64.25 1.14.4.94.24 1.64.58 2.1 1 .45.41.68 1 .68 1.74 0 .86-.35 1.54-1.05 2.03-.7.49-1.58.73-2.62.73-.7 0-1.36-.1-1.95-.33a4.73 4.73 0 0 1-1.52-.9l1.06-1.19c.75.57 1.54.86 2.36.86.48 0 .85-.1 1.13-.28a.88.88 0 0 0 .42-.77c0-.26-.05-.46-.16-.6-.1-.15-.29-.28-.56-.4-.26-.11-.68-.25-1.25-.42a4.2 4.2 0 0 1-1.96-1.01 2.24 2.24 0 0 1-.63-1.62c0-.48.14-.92.42-1.3.28-.38.68-.69 1.19-.9a4.4 4.4 0 0 1 1.75-.33ZM889.63 421.83v8.7h-2.1v-8.7h2.1Zm-1.07-4.4c.4 0 .72.12.96.37.25.24.37.55.37.9 0 .37-.12.67-.37.91-.24.24-.57.36-.96.36-.38 0-.7-.12-.95-.36a1.21 1.21 0 0 1-.37-.9c0-.36.13-.67.37-.91.25-.25.57-.37.95-.37ZM896.8 421.59c.78 0 1.38.23 1.82.7.43.46.65 1.11.65 1.94v6.3h-2.1v-5.97c0-.51-.1-.87-.28-1.08-.18-.21-.45-.31-.8-.31-.36 0-.69.1-.98.33-.29.23-.57.55-.84.98v6.05h-2.1v-8.7h1.82l.16 1.14a3.23 3.23 0 0 1 2.65-1.38ZM906.22 421.59c1.1 0 1.91.4 2.44 1.2.52.8.79 1.92.79 3.37 0 .9-.14 1.7-.4 2.4-.27.69-.67 1.23-1.19 1.63-.52.4-1.14.6-1.85.6-.92 0-1.65-.33-2.19-.96v4.06l-2.1.23v-12.29h1.84l.11 1.07a3.4 3.4 0 0 1 1.17-.98c.44-.22.9-.33 1.38-.33Zm-.8 7.58c1.22 0 1.82-1 1.82-3 0-1.06-.13-1.83-.4-2.3-.28-.47-.7-.7-1.24-.7-.35 0-.68.1-.99.32-.3.21-.57.5-.79.86v3.91c.4.6.94.9 1.6.9ZM918.48 430.53h-1.83l-.11-1.21c-.32.5-.7.86-1.13 1.1-.43.24-.95.36-1.54.36-.78 0-1.38-.24-1.8-.71a2.89 2.89 0 0 1-.63-1.99v-6.25h2.1v5.99c0 .5.09.84.26 1.05.17.21.44.32.81.32.67 0 1.26-.42 1.76-1.24v-6.12h2.1v8.7ZM926 430.12c-.31.22-.66.39-1.03.5-.38.1-.77.16-1.16.16-.86-.01-1.5-.25-1.95-.73-.45-.48-.67-1.18-.67-2.11v-4.6h-1.36v-1.5h1.36v-1.93l2.1-.25v2.17h2.03l-.21 1.52h-1.81v4.54c0 .42.07.73.22.92.15.18.38.28.7.28.31 0 .66-.1 1.03-.32l.74 1.35Z" style="fill:#8a11b2;fill-rule:nonzero"/></g><path d="M1159.4 274.28c0-6.42-5.21-11.64-11.64-11.64H783.1a11.64 11.64 0 0 0-11.64 11.64v470c0 6.43 5.21 11.65 11.64 11.65h364.67c6.43 0 11.64-5.22 11.64-11.64V274.28Z" style="fill:none;stroke:#073b4c;stroke-width:3px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5"/><g><path d="M984.84 291.64a6.99 6.99 0 0 1 4.82 1.74l-1.6 2.15a4.51 4.51 0 0 0-3-1.06c-2.22 0-3.33 1.69-3.33 5.06 0 1.72.3 2.96.87 3.71.58.76 1.4 1.14 2.47 1.14a4 4 0 0 0 1.44-.25c.44-.17.95-.44 1.55-.82l1.6 2.27c-1.4 1.14-3 1.71-4.8 1.71a7.07 7.07 0 0 1-3.69-.94 6.16 6.16 0 0 1-2.4-2.67 9.3 9.3 0 0 1-.84-4.09c0-1.57.28-2.95.84-4.16a6.44 6.44 0 0 1 2.4-2.8 6.7 6.7 0 0 1 3.67-1ZM996.6 287.7c1.25 0 2.33.2 3.23.63a4.43 4.43 0 0 1 2.73 4.14c0 1.15-.32 2.1-.97 2.85a5.17 5.17 0 0 1-2.7 1.58c1.26.11 2.29.56 3.09 1.35.8.78 1.2 1.86 1.2 3.24a5.41 5.41 0 0 1-3.2 5.03 8.05 8.05 0 0 1-3.63.77 7.5 7.5 0 0 1-6.1-2.72l1.98-1.9a6.8 6.8 0 0 0 1.88 1.39c.62.29 1.3.43 2.04.43 1.01 0 1.82-.28 2.43-.85.6-.57.9-1.34.9-2.31 0-1.09-.28-1.86-.85-2.33-.57-.46-1.41-.7-2.53-.7h-1.49l.42-2.55h1.01c.92 0 1.65-.25 2.2-.75.55-.5.82-1.2.82-2.1 0-.77-.25-1.37-.75-1.8a2.96 2.96 0 0 0-2.02-.67c-.72 0-1.39.14-1.98.41-.6.27-1.2.69-1.8 1.25l-1.82-2a8.34 8.34 0 0 1 5.91-2.4ZM1017.49 302.95c0 .58.09 1 .27 1.28.17.27.46.48.85.63l-.76 2.38a4.58 4.58 0 0 1-2.05-.62 3.15 3.15 0 0 1-1.22-1.54c-.5.75-1.14 1.3-1.9 1.67-.75.36-1.6.54-2.53.54a4.8 4.8 0 0 1-3.5-1.26 4.42 4.42 0 0 1-1.28-3.3c0-1.6.58-2.84 1.75-3.68 1.16-.85 2.83-1.28 5-1.28h1.84v-.84c0-.95-.22-1.62-.66-2-.43-.38-1.14-.57-2.11-.57-1.08 0-2.39.26-3.92.78l-.84-2.44c1.85-.7 3.64-1.06 5.38-1.06 3.79 0 5.68 1.7 5.68 5.1v6.21Zm-6.38 1.74c1.21 0 2.16-.61 2.85-1.82v-3h-1.48c-2.32 0-3.47.86-3.47 2.58 0 .7.17 1.26.53 1.65.35.4.88.59 1.57.59ZM1028.86 294.33a4.94 4.94 0 0 1 4.62 2.81c.47.92.7 2.03.7 3.32 0 1.3-.27 2.48-.81 3.51a6.04 6.04 0 0 1-2.28 2.44c-.98.59-2.1.88-3.35.88-2.31 0-4.03-.81-5.14-2.44-1.1-1.62-1.66-3.85-1.66-6.69 0-2.09.3-3.92.93-5.5a8.21 8.21 0 0 1 2.7-3.67 6.68 6.68 0 0 1 4.1-1.3c1.54 0 2.92.4 4.11 1.2l-1.34 2.22a5.28 5.28 0 0 0-2.72-.76 3.3 3.3 0 0 0-2.87 1.61 8.71 8.71 0 0 0-1.22 4.44 5.27 5.27 0 0 1 4.23-2.07Zm-1.12 10.3c.93 0 1.64-.37 2.11-1.1a5.5 5.5 0 0 0 .72-3.01c0-1.3-.22-2.21-.66-2.76-.44-.55-1.08-.83-1.92-.83-.63 0-1.23.17-1.8.52-.57.34-1.08.82-1.53 1.41.04 2.04.3 3.5.77 4.41.48.9 1.25 1.36 2.31 1.36ZM1043.08 287.7c2.2 0 3.88.83 5.03 2.51 1.14 1.68 1.72 4.1 1.72 7.25 0 3.18-.58 5.6-1.72 7.3a5.7 5.7 0 0 1-5.03 2.53 5.7 5.7 0 0 1-5.03-2.53c-1.14-1.7-1.72-4.12-1.72-7.3 0-3.15.58-5.57 1.72-7.25a5.7 5.7 0 0 1 5.03-2.52Zm0 2.7c-1.06 0-1.84.54-2.32 1.62-.49 1.07-.73 2.89-.73 5.44 0 2.58.24 4.4.73 5.5.48 1.07 1.26 1.62 2.32 1.62 1.06 0 1.84-.54 2.32-1.61.49-1.08.73-2.91.73-5.5 0-2.58-.24-4.4-.73-5.47-.48-1.06-1.26-1.6-2.32-1.6ZM1060.41 288.03v18.84h-3.53v-15.23l-4.2 2.55-1.57-2.41 6.14-3.75h3.16ZM1066.4 302.75c.64 0 1.18.22 1.62.66.45.44.68.98.68 1.61 0 .62-.23 1.15-.68 1.6-.44.45-.98.67-1.62.67-.62 0-1.14-.22-1.58-.67a2.2 2.2 0 0 1-.66-1.6 2.22 2.22 0 0 1 2.24-2.26ZM1073.12 302.75c.64 0 1.18.22 1.62.66.45.44.68.98.68 1.61 0 .62-.23 1.15-.68 1.6-.44.45-.99.67-1.62.67-.62 0-1.14-.22-1.58-.67a2.2 2.2 0 0 1-.66-1.6 2.22 2.22 0 0 1 2.24-2.26ZM1079.85 302.75c.64 0 1.18.22 1.62.66.45.44.68.98.68 1.61 0 .62-.23 1.15-.68 1.6-.44.45-.99.67-1.62.67-.62 0-1.14-.22-1.58-.67a2.2 2.2 0 0 1-.66-1.6 2.22 2.22 0 0 1 2.24-2.26Z" style="fill:#073b4c;fill-rule:nonzero"/><path d="m806.06 287.92-.4 3.07h-4.16v13.81h-4V291h-4.36v-3.07h12.92ZM813.88 291.5c.47 0 .9.06 1.3.17l-.62 3.73a5.49 5.49 0 0 0-1.17-.17c-.76 0-1.34.26-1.74.79-.4.53-.7 1.32-.94 2.38v6.4h-3.85v-12.94h3.37l.31 2.51c.3-.89.74-1.6 1.33-2.1a3 3 0 0 1 2.01-.77ZM826.07 301.05c0 .49.07.85.2 1.07.14.23.37.4.67.52l-.8 2.5a4.74 4.74 0 0 1-1.95-.52 2.8 2.8 0 0 1-1.17-1.35c-.84 1.3-2.14 1.95-3.9 1.95a4.2 4.2 0 0 1-3.07-1.12 3.91 3.91 0 0 1-1.15-2.93c0-1.4.52-2.49 1.56-3.24 1.04-.74 2.55-1.12 4.51-1.12h1.32v-.56c0-.76-.16-1.29-.49-1.57-.32-.28-.9-.43-1.7-.43-.43 0-.94.06-1.54.19-.6.12-1.22.28-1.85.5l-.88-2.54a14.75 14.75 0 0 1 4.88-.95c1.85 0 3.2.38 4.07 1.15.86.76 1.29 1.9 1.29 3.43v5.02Zm-5.83 1.42c.88 0 1.56-.42 2.05-1.25v-2.29h-.95c-.88 0-1.53.16-1.96.47-.43.3-.65.78-.65 1.43 0 .52.14.93.4 1.2.27.3.64.44 1.11.44ZM836.72 291.45c1.12 0 2 .34 2.63 1.02.63.69.95 1.64.95 2.88v9.45h-3.85V296c0-.64-.1-1.1-.3-1.35-.21-.25-.51-.37-.92-.37-.78 0-1.53.56-2.24 1.68v8.84h-3.85v-12.94h3.36l.27 1.54a5.84 5.84 0 0 1 1.79-1.46 4.7 4.7 0 0 1 2.16-.49ZM847.76 291.45c.92 0 1.8.14 2.6.41.82.28 1.53.67 2.15 1.17l-1.42 2.17a5.94 5.94 0 0 0-3.19-1c-.5 0-.89.09-1.16.26a.8.8 0 0 0-.4.72c0 .24.06.44.18.6.13.15.37.3.75.47.37.16.95.36 1.73.59 1.35.39 2.35.9 3 1.52.67.62 1 1.49 1 2.6 0 .87-.26 1.63-.76 2.27-.5.64-1.2 1.14-2.07 1.48-.88.34-1.85.5-2.93.5s-2.1-.16-3.03-.5a7 7 0 0 1-2.38-1.42l1.88-2.1a5.52 5.52 0 0 0 3.44 1.28c.58 0 1.04-.11 1.37-.32a1 1 0 0 0 .5-.9c0-.31-.06-.56-.2-.73a1.76 1.76 0 0 0-.75-.5c-.37-.16-.96-.35-1.78-.58a6.34 6.34 0 0 1-2.87-1.56 3.46 3.46 0 0 1-.95-2.48c0-.75.21-1.42.64-2.01a4.38 4.38 0 0 1 1.86-1.42c.8-.35 1.73-.52 2.79-.52ZM865.01 301.05c0 .49.07.85.2 1.07.14.23.37.4.68.52l-.8 2.5a4.74 4.74 0 0 1-1.96-.52 2.8 2.8 0 0 1-1.17-1.35c-.84 1.3-2.14 1.95-3.9 1.95a4.2 4.2 0 0 1-3.07-1.12 3.9 3.9 0 0 1-1.14-2.93c0-1.4.52-2.49 1.56-3.24 1.04-.74 2.54-1.12 4.5-1.12h1.32v-.56c0-.76-.16-1.29-.49-1.57-.32-.28-.89-.43-1.7-.43-.42 0-.94.06-1.54.19-.6.12-1.22.28-1.85.5l-.88-2.54a14.78 14.78 0 0 1 4.88-.95c1.85 0 3.2.38 4.07 1.15.86.76 1.29 1.9 1.29 3.43v5.02Zm-5.83 1.42c.88 0 1.56-.42 2.05-1.25v-2.29h-.95c-.88 0-1.53.16-1.96.47-.43.3-.65.78-.65 1.43 0 .52.14.93.4 1.2.27.3.64.44 1.11.44ZM873.69 291.45c.89 0 1.7.13 2.4.39.72.26 1.4.66 2.03 1.2l-1.66 2.28a4.05 4.05 0 0 0-2.46-.92c-.86 0-1.5.32-1.95.95-.44.63-.65 1.66-.65 3.07 0 1.36.21 2.33.65 2.9.44.57 1.08.85 1.9.85.44 0 .84-.07 1.2-.2.35-.14.79-.37 1.29-.67l1.68 2.38a6.8 6.8 0 0 1-4.36 1.54 6.65 6.65 0 0 1-3.41-.84 5.67 5.67 0 0 1-2.22-2.36 7.74 7.74 0 0 1-.78-3.57c0-1.37.26-2.58.78-3.64a5.9 5.9 0 0 1 5.56-3.36ZM887.87 304.2a6.75 6.75 0 0 1-3.5 1.02c-2.84-.02-4.25-1.58-4.25-4.68v-6h-1.83v-2.68h1.83v-2.8l3.85-.44v3.24h2.97l-.41 2.68h-2.56v5.95c0 .6.1 1.03.3 1.3.19.25.5.38.92.38.44 0 .9-.14 1.39-.41l1.29 2.44ZM893.01 291.87v12.94h-3.85v-12.94h3.85Zm-1.95-6.83c.67 0 1.22.2 1.65.62.43.42.64.94.64 1.57 0 .64-.21 1.16-.64 1.58-.43.41-.98.62-1.65.62-.66 0-1.2-.21-1.63-.62a2.1 2.1 0 0 1-.63-1.58c0-.63.2-1.15.63-1.57.42-.41.97-.62 1.63-.62ZM901.64 291.45c1.98 0 3.53.6 4.65 1.82 1.12 1.2 1.68 2.9 1.68 5.08 0 1.38-.25 2.58-.76 3.62a5.65 5.65 0 0 1-2.2 2.4c-.95.56-2.07.85-3.37.85-1.97 0-3.51-.6-4.64-1.82-1.13-1.2-1.7-2.9-1.7-5.08 0-1.38.26-2.59.77-3.62a5.66 5.66 0 0 1 2.2-2.4 6.45 6.45 0 0 1 3.37-.85Zm0 2.83a1.9 1.9 0 0 0-1.76.98 6.19 6.19 0 0 0-.58 3.06c0 1.42.19 2.45.57 3.1.38.65.97.97 1.77.97.78 0 1.36-.33 1.75-.98.4-.66.59-1.68.59-3.06 0-1.42-.2-2.45-.57-3.1a1.9 1.9 0 0 0-1.77-.97ZM917.84 291.45c1.13 0 2 .34 2.64 1.02.63.69.95 1.64.95 2.88v9.45h-3.85V296c0-.64-.1-1.1-.3-1.35-.21-.25-.52-.37-.92-.37-.78 0-1.53.56-2.24 1.68v8.84h-3.85v-12.94h3.36l.27 1.54a5.83 5.83 0 0 1 1.79-1.46 4.7 4.7 0 0 1 2.15-.49ZM930.18 287.92h4v16.89h-4zM942.02 287.92c2.65 0 4.77.6 6.37 1.79 1.6 1.2 2.4 3.38 2.4 6.57 0 3.13-.78 5.34-2.34 6.61-1.56 1.28-3.58 1.91-6.07 1.91h-5.06v-16.88h4.7Zm-.7 2.9v11.08h1.3c1.33 0 2.32-.4 3-1.23.69-.82 1.03-2.28 1.03-4.4a8.8 8.8 0 0 0-.51-3.36c-.34-.8-.8-1.34-1.4-1.64a4.7 4.7 0 0 0-2.16-.45h-1.27ZM954.52 300.8c.6 0 1.12.22 1.55.65.43.44.64.95.64 1.55 0 .62-.21 1.14-.64 1.57-.43.43-.95.65-1.55.65-.62 0-1.14-.22-1.57-.65a2.14 2.14 0 0 1-.65-1.57c0-.6.22-1.11.65-1.55.43-.43.95-.64 1.57-.64Zm0-8.42c.6 0 1.12.21 1.55.64.43.43.64.95.64 1.55 0 .62-.21 1.14-.64 1.57-.43.43-.95.65-1.55.65-.62 0-1.14-.22-1.57-.65a2.14 2.14 0 0 1-.65-1.57c0-.6.22-1.12.65-1.55.43-.43.95-.64 1.57-.64Z" style="fill:#073b4c;fill-rule:nonzero"/></g><path d="M668.55 399.55H496.23a12.73 12.73 0 0 0-12.62 12.83v25.65c0 7.08 5.66 12.82 12.62 12.82h172.32M280.9 379.43h172.32c6.97 0 12.62-5.75 12.62-12.83v-25.65c0-7.08-5.65-12.82-12.62-12.82H280.9" style="fill:none;stroke:#b4c4c9;stroke-width:2px;stroke-linecap:round;stroke-dasharray:2,4,0,0"/><path d="M667.87 328.13H495.91c-6.96 0-12.6 5.74-12.6 12.82v25.65c0 7.08 5.64 12.82 12.6 12.82h171.96" style="fill:none;stroke:#3ab211;stroke-width:3px;stroke-miterlimit:1"/><path d="M668.55 268.9c0-3.46-2.8-6.26-6.25-6.26H286.85a6.25 6.25 0 0 0-6.25 6.25v195.85c0 3.45 2.8 6.25 6.25 6.25H662.3c3.45 0 6.25-2.8 6.25-6.25V268.89Z" style="fill:none;stroke:#073b4c;stroke-width:3px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5"/><g><path d="m315.06 287.92-.4 3.07h-4.16v13.81h-4V291h-4.36v-3.07h12.92ZM322.88 291.5c.47 0 .9.06 1.3.17l-.62 3.73a5.49 5.49 0 0 0-1.17-.17c-.76 0-1.34.26-1.74.79-.4.53-.7 1.32-.94 2.38v6.4h-3.85v-12.94h3.37l.31 2.51c.3-.89.74-1.6 1.33-2.1a3 3 0 0 1 2.01-.77ZM335.07 301.05c0 .49.07.85.2 1.07.14.23.37.4.67.52l-.8 2.5a4.74 4.74 0 0 1-1.95-.52 2.8 2.8 0 0 1-1.17-1.35c-.84 1.3-2.14 1.95-3.9 1.95a4.2 4.2 0 0 1-3.07-1.12 3.91 3.91 0 0 1-1.15-2.93c0-1.4.53-2.49 1.57-3.24 1.03-.74 2.54-1.12 4.5-1.12h1.32v-.56c0-.76-.16-1.29-.49-1.57-.32-.28-.9-.43-1.7-.43-.43 0-.94.06-1.54.19-.6.12-1.22.28-1.85.5l-.88-2.54a14.75 14.75 0 0 1 4.87-.95c1.86 0 3.21.38 4.07 1.15.87.76 1.3 1.9 1.3 3.43v5.02Zm-5.83 1.42c.88 0 1.56-.42 2.05-1.25v-2.29h-.95c-.88 0-1.53.16-1.96.47-.43.3-.65.78-.65 1.43 0 .52.13.93.4 1.2.27.3.64.44 1.11.44ZM345.72 291.45c1.12 0 2 .34 2.63 1.02.63.69.95 1.64.95 2.88v9.45h-3.85V296c0-.64-.1-1.1-.3-1.35-.21-.25-.51-.37-.92-.37-.78 0-1.53.56-2.24 1.68v8.84h-3.85v-12.94h3.36l.27 1.54a5.84 5.84 0 0 1 1.79-1.46 4.7 4.7 0 0 1 2.16-.49ZM356.76 291.45c.92 0 1.8.14 2.6.41.82.28 1.53.67 2.15 1.17l-1.42 2.17a5.94 5.94 0 0 0-3.19-1c-.5 0-.89.09-1.15.26a.8.8 0 0 0-.4.72c0 .24.05.44.17.6.13.15.37.3.75.47.37.16.95.36 1.73.59 1.35.39 2.35.9 3 1.52.67.62 1 1.49 1 2.6 0 .87-.26 1.63-.76 2.27-.5.64-1.2 1.14-2.07 1.48-.88.34-1.85.5-2.93.5s-2.1-.16-3.03-.5a7 7 0 0 1-2.38-1.42l1.88-2.1a5.52 5.52 0 0 0 3.44 1.28c.58 0 1.04-.11 1.37-.32a1 1 0 0 0 .5-.9c0-.31-.06-.56-.2-.73a1.76 1.76 0 0 0-.75-.5c-.37-.16-.96-.35-1.78-.58a6.34 6.34 0 0 1-2.87-1.56 3.46 3.46 0 0 1-.95-2.48c0-.75.21-1.42.64-2.01a4.38 4.38 0 0 1 1.86-1.42c.8-.35 1.73-.52 2.79-.52ZM374.01 301.05c0 .49.07.85.2 1.07.15.23.37.4.68.52l-.8 2.5a4.74 4.74 0 0 1-1.96-.52 2.8 2.8 0 0 1-1.17-1.35c-.84 1.3-2.14 1.95-3.9 1.95a4.2 4.2 0 0 1-3.07-1.12 3.9 3.9 0 0 1-1.14-2.93c0-1.4.52-2.49 1.56-3.24 1.04-.74 2.54-1.12 4.5-1.12h1.32v-.56c0-.76-.16-1.29-.48-1.57-.33-.28-.9-.43-1.71-.43-.42 0-.93.06-1.54.19-.6.12-1.21.28-1.85.5l-.88-2.54a14.78 14.78 0 0 1 4.88-.95c1.85 0 3.2.38 4.07 1.15.86.76 1.29 1.9 1.29 3.43v5.02Zm-5.83 1.42c.88 0 1.56-.42 2.05-1.25v-2.29h-.95c-.87 0-1.53.16-1.96.47-.43.3-.65.78-.65 1.43 0 .52.14.93.4 1.2.28.3.64.44 1.12.44ZM382.69 291.45c.89 0 1.7.13 2.4.39.72.26 1.4.66 2.03 1.2l-1.66 2.28a4.05 4.05 0 0 0-2.46-.92c-.86 0-1.5.32-1.95.95-.44.63-.66 1.66-.66 3.07 0 1.36.22 2.33.66 2.9.44.57 1.07.85 1.9.85.44 0 .84-.07 1.2-.2.36-.14.79-.37 1.29-.67l1.68 2.38a6.8 6.8 0 0 1-4.36 1.54 6.65 6.65 0 0 1-3.41-.84 5.67 5.67 0 0 1-2.22-2.36 7.74 7.74 0 0 1-.78-3.57c0-1.37.26-2.58.78-3.64a5.9 5.9 0 0 1 5.56-3.36ZM396.87 304.2a6.75 6.75 0 0 1-3.5 1.02c-2.84-.02-4.25-1.58-4.25-4.68v-6h-1.83v-2.68h1.83v-2.8l3.85-.44v3.24h2.97l-.41 2.68h-2.56v5.95c0 .6.1 1.03.3 1.3.19.25.5.38.92.38.44 0 .9-.14 1.39-.41l1.29 2.44ZM402.01 291.87v12.94h-3.85v-12.94h3.85Zm-1.95-6.83c.67 0 1.22.2 1.65.62.43.42.64.94.64 1.57 0 .64-.21 1.16-.64 1.58-.43.41-.98.62-1.65.62-.66 0-1.2-.21-1.63-.62a2.1 2.1 0 0 1-.63-1.58c0-.63.2-1.15.63-1.57.42-.41.97-.62 1.63-.62ZM410.64 291.45c1.98 0 3.53.6 4.65 1.82 1.12 1.2 1.68 2.9 1.68 5.08 0 1.38-.25 2.58-.76 3.62a5.65 5.65 0 0 1-2.2 2.4c-.95.56-2.07.85-3.37.85-1.97 0-3.52-.6-4.64-1.82-1.13-1.2-1.7-2.9-1.7-5.08 0-1.38.26-2.59.77-3.62a5.66 5.66 0 0 1 2.2-2.4 6.45 6.45 0 0 1 3.37-.85Zm0 2.83a1.9 1.9 0 0 0-1.76.98 6.19 6.19 0 0 0-.58 3.06c0 1.42.19 2.45.57 3.1.38.65.97.97 1.77.97.78 0 1.36-.33 1.75-.98.4-.66.59-1.68.59-3.06 0-1.42-.2-2.45-.58-3.1a1.9 1.9 0 0 0-1.76-.97ZM426.84 291.45c1.13 0 2 .34 2.64 1.02.63.69.95 1.64.95 2.88v9.45h-3.85V296c0-.64-.1-1.1-.3-1.35-.21-.25-.52-.37-.92-.37-.78 0-1.53.56-2.24 1.68v8.84h-3.85v-12.94h3.36l.27 1.54a5.83 5.83 0 0 1 1.79-1.46 4.7 4.7 0 0 1 2.15-.49ZM439.18 287.92h4v16.89h-4zM451.02 287.92c2.65 0 4.77.6 6.37 1.79 1.6 1.2 2.4 3.38 2.4 6.57 0 3.13-.78 5.34-2.34 6.61-1.56 1.28-3.58 1.91-6.06 1.91h-5.07v-16.88h4.7Zm-.7 2.9v11.08h1.3c1.32 0 2.32-.4 3-1.23.69-.82 1.03-2.28 1.03-4.4a8.8 8.8 0 0 0-.51-3.36c-.34-.8-.8-1.34-1.4-1.64a4.7 4.7 0 0 0-2.16-.45h-1.27ZM463.52 300.8c.6 0 1.12.22 1.55.65.43.44.65.95.65 1.55 0 .62-.22 1.14-.65 1.57-.43.43-.95.65-1.55.65-.62 0-1.14-.22-1.57-.65a2.14 2.14 0 0 1-.65-1.57c0-.6.22-1.11.65-1.55.43-.43.95-.64 1.57-.64Zm0-8.42c.6 0 1.12.21 1.55.64.43.43.65.95.65 1.55 0 .62-.22 1.14-.65 1.57-.43.43-.95.65-1.55.65-.62 0-1.14-.22-1.57-.65a2.14 2.14 0 0 1-.65-1.57c0-.6.22-1.12.65-1.55.43-.43.95-.64 1.57-.64Z" style="fill:#073b4c;fill-rule:nonzero"/></g><g><path d="m517.8 343.94 9.84 19.67h-19.68l9.84-19.67Zm0 7.67c1.14 0 2 .44 2.6 1.32.58.88.87 2.13.87 3.73 0 1.61-.29 2.86-.88 3.75a2.91 2.91 0 0 1-2.6 1.32c-1.13 0-2-.44-2.58-1.32a6.74 6.74 0 0 1-.89-3.75c0-1.6.3-2.85.88-3.73a2.92 2.92 0 0 1 2.6-1.32Zm0 8.54c.49 0 .85-.26 1.07-.8.22-.52.33-1.42.33-2.7 0-.5-.01-.95-.04-1.34l-2.2 4.58c.18.17.46.26.84.26Zm0-6.94c-.5 0-.85.27-1.08.8a7.37 7.37 0 0 0-.34 2.65c0 .8.03 1.45.08 1.94l2.35-4.92a.93.93 0 0 0-.4-.37c-.16-.07-.36-.1-.61-.1Z" style="fill:#3ab211"/><path d="M540.7 351.79c-.55.2-1.39.3-2.5.3.53.24.93.54 1.18.9.26.35.39.8.39 1.33 0 .57-.14 1.08-.42 1.51-.28.44-.69.79-1.22 1.04a4.3 4.3 0 0 1-2.9.25.75.75 0 0 0-.36.64c0 .4.35.6 1.05.6h1.33c.64 0 1.2.11 1.67.32.48.2.85.5 1.11.88.27.38.4.8.4 1.27 0 .88-.37 1.56-1.12 2.05a5.9 5.9 0 0 1-3.22.73c-1.01 0-1.8-.1-2.38-.3-.58-.22-.99-.52-1.23-.91-.24-.4-.36-.9-.36-1.52h1.9c0 .31.05.55.17.73.11.17.32.3.62.4.3.08.74.12 1.3.12.8 0 1.37-.1 1.7-.3.33-.19.5-.47.5-.85a.89.89 0 0 0-.38-.76 1.88 1.88 0 0 0-1.1-.27h-1.32c-.82 0-1.44-.16-1.86-.48a1.45 1.45 0 0 1-.62-1.2c0-.3.09-.6.27-.89.18-.28.43-.53.75-.72a2.87 2.87 0 0 1-1.16-1.01c-.25-.4-.37-.88-.37-1.44a2.95 2.95 0 0 1 1.73-2.74 4.3 4.3 0 0 1 1.87-.39c.92.02 1.66-.05 2.23-.2a9.23 9.23 0 0 0 1.83-.77l.53 1.68Zm-4.55.72c-.47 0-.84.15-1.1.45-.28.3-.41.71-.41 1.21 0 .53.14.95.41 1.25.27.31.65.46 1.13.46.5 0 .9-.15 1.16-.45.26-.3.4-.72.4-1.27 0-1.1-.54-1.65-1.59-1.65ZM548.8 355.47l-.05.86h-5.46c.07.84.28 1.45.66 1.8.37.37.86.55 1.48.55.38 0 .74-.06 1.08-.19.34-.12.7-.32 1.09-.58l.87 1.2a5 5 0 0 1-3.22 1.17c-1.33 0-2.35-.41-3.07-1.22a4.83 4.83 0 0 1-1.08-3.32c0-.9.16-1.69.46-2.4a3.56 3.56 0 0 1 3.4-2.26c1.22 0 2.17.39 2.84 1.16.66.78 1 1.85 1 3.23Zm-2.09-.6c0-1.53-.56-2.3-1.7-2.3-.5 0-.91.2-1.2.58-.3.37-.46.98-.52 1.81h3.42v-.1ZM555.33 351.08c.78 0 1.38.24 1.82.7.43.47.65 1.12.65 1.95v6.3h-2.1v-5.97c0-.52-.1-.88-.28-1.09-.18-.2-.45-.3-.8-.3-.36 0-.69.1-.98.33-.29.22-.57.55-.84.98v6.05h-2.1v-8.7h1.82l.16 1.13a3.23 3.23 0 0 1 2.65-1.38ZM567.38 355.47c0 .11-.01.4-.05.86h-5.46c.07.84.29 1.45.66 1.8.38.37.87.55 1.48.55.39 0 .75-.06 1.09-.19.34-.12.7-.32 1.08-.58l.88 1.2a5 5 0 0 1-3.23 1.17c-1.33 0-2.35-.41-3.07-1.22a4.84 4.84 0 0 1-1.07-3.32c0-.9.15-1.69.46-2.4a3.57 3.57 0 0 1 3.4-2.26c1.22 0 2.16.39 2.83 1.16.67.78 1 1.85 1 3.23Zm-2.08-.6c0-1.53-.57-2.3-1.7-2.3-.51 0-.92.2-1.2.58-.3.37-.47.98-.52 1.81h3.42v-.1ZM572.02 351.08c1.18 0 2.2.35 3.1 1.04l-.83 1.23a4.08 4.08 0 0 0-2.18-.7c-.42 0-.74.07-.97.23a.73.73 0 0 0-.35.64c0 .2.05.36.15.49.1.13.27.26.53.37.26.12.64.24 1.14.39.95.25 1.65.58 2.1 1 .46.42.68 1 .68 1.74 0 .87-.35 1.55-1.05 2.03-.7.5-1.57.74-2.61.74-.72 0-1.37-.11-1.95-.33a4.72 4.72 0 0 1-1.52-.9l1.05-1.2c.76.58 1.55.86 2.37.86a2 2 0 0 0 1.12-.28.88.88 0 0 0 .42-.77c0-.25-.05-.45-.15-.6-.1-.15-.3-.28-.56-.4a11.9 11.9 0 0 0-1.26-.41 4.2 4.2 0 0 1-1.96-1.01 2.24 2.24 0 0 1-.62-1.62c0-.49.14-.92.42-1.3.28-.39.67-.69 1.18-.9a4.4 4.4 0 0 1 1.75-.34ZM579.21 351.33v8.7h-2.1v-8.7h2.1Zm-1.07-4.4c.4 0 .72.11.96.36.25.25.37.55.37.91 0 .37-.12.67-.37.9-.24.25-.56.37-.96.37-.38 0-.7-.12-.94-.36a1.21 1.21 0 0 1-.37-.9c0-.37.12-.67.37-.92.24-.25.56-.37.94-.37ZM584.49 351.08c1.17 0 2.2.35 3.1 1.04l-.83 1.23a4.08 4.08 0 0 0-2.19-.7c-.42 0-.74.07-.97.23a.73.73 0 0 0-.34.64c0 .2.05.36.14.49.1.13.28.26.54.37.26.12.64.24 1.14.39.94.25 1.64.58 2.1 1 .45.42.68 1 .68 1.74 0 .87-.35 1.55-1.05 2.03-.7.5-1.57.74-2.62.74-.7 0-1.36-.11-1.95-.33a4.72 4.72 0 0 1-1.52-.9l1.06-1.2c.75.58 1.54.86 2.36.86a2 2 0 0 0 1.13-.28.88.88 0 0 0 .42-.77c0-.25-.05-.45-.16-.6-.1-.15-.29-.28-.55-.4a11.9 11.9 0 0 0-1.26-.41 4.2 4.2 0 0 1-1.96-1.01 2.25 2.25 0 0 1-.62-1.62c0-.49.13-.92.41-1.3.28-.39.68-.69 1.19-.9a4.4 4.4 0 0 1 1.75-.34ZM597.24 351.08c1.28 0 2.28.41 3 1.23a4.92 4.92 0 0 1 1.07 3.36c0 .91-.16 1.71-.49 2.41a3.74 3.74 0 0 1-3.6 2.2c-1.28 0-2.29-.41-3.01-1.23a4.92 4.92 0 0 1-1.09-3.38c0-.9.17-1.71.5-2.4.33-.7.8-1.23 1.42-1.61a4.08 4.08 0 0 1 2.2-.58Zm0 1.6c-1.27 0-1.9 1-1.9 3 0 1.02.16 1.78.47 2.27.32.49.79.73 1.41.73.63 0 1.1-.25 1.4-.74.32-.5.47-1.25.47-2.27s-.15-1.77-.46-2.26a1.54 1.54 0 0 0-1.4-.73ZM610.25 360.03h-1.83l-.12-1.22c-.31.5-.69.86-1.12 1.1-.43.24-.95.37-1.54.37-.78 0-1.38-.24-1.8-.72a2.89 2.89 0 0 1-.63-1.98v-6.25h2.1v5.99c0 .49.09.84.26 1.05.17.2.44.31.81.31.67 0 1.26-.41 1.76-1.23v-6.12h2.1v8.7ZM617.76 359.62c-.3.22-.65.38-1.03.5-.37.1-.76.16-1.16.16-.85-.01-1.5-.26-1.94-.74-.45-.47-.67-1.18-.67-2.1v-4.6h-1.37v-1.51h1.37v-1.93l2.1-.24v2.17h2.03l-.22 1.51h-1.8v4.54c0 .43.07.74.22.92.14.19.38.28.7.28.31 0 .66-.1 1.03-.31l.74 1.35ZM623.45 351.08c1.1 0 1.91.4 2.44 1.2.52.8.79 1.93.79 3.37 0 .9-.14 1.7-.4 2.4-.28.7-.67 1.24-1.2 1.63-.51.4-1.13.6-1.84.6-.92 0-1.65-.32-2.19-.96v4.06l-2.1.23v-12.28h1.84l.11 1.07a3.4 3.4 0 0 1 1.17-.99c.44-.22.9-.33 1.38-.33Zm-.8 7.58c1.21 0 1.82-1 1.82-2.99 0-1.06-.14-1.83-.4-2.3-.28-.47-.7-.7-1.24-.7-.35 0-.68.1-.99.31-.3.22-.57.5-.79.87v3.91c.4.6.94.9 1.6.9ZM635.7 360.03h-1.82l-.12-1.22c-.31.5-.69.86-1.12 1.1-.43.24-.95.37-1.54.37-.78 0-1.38-.24-1.8-.72a2.89 2.89 0 0 1-.63-1.98v-6.25h2.1v5.99c0 .49.09.84.26 1.05.17.2.44.31.81.31.67 0 1.26-.41 1.76-1.23v-6.12h2.1v8.7ZM643.22 359.62c-.3.22-.65.38-1.03.5-.37.1-.76.16-1.16.16-.85-.01-1.5-.26-1.94-.74-.45-.47-.67-1.18-.67-2.1v-4.6h-1.36v-1.51h1.36v-1.93l2.1-.24v2.17h2.03l-.22 1.51h-1.8v4.54c0 .43.07.74.22.92.14.19.38.28.7.28.31 0 .66-.1 1.03-.31l.74 1.35Z" style="fill:#3ab211;fill-rule:nonzero"/></g><g><path d="M.3-.54c.07 0 .13.02.18.07a.3.3 0 0 1 .06.2c0 .06 0 .1-.03.15A.23.23 0 0 1 .3.01a.23.23 0 0 1-.18-.07.3.3 0 0 1-.07-.2c0-.06.01-.1.03-.15a.22.22 0 0 1 .09-.1.25.25 0 0 1 .13-.03Zm0 .1c-.08 0-.12.05-.12.17 0 .07 0 .11.03.14a.1.1 0 0 0 .08.05.1.1 0 0 0 .09-.05.26.26 0 0 0 .03-.14C.4-.33.4-.37.38-.4a.1.1 0 0 0-.09-.05Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 524.12 429.6)"/><path d="M.38-.03a.23.23 0 0 1-.13.04C.19.01.15 0 .13-.03.1-.06.09-.1.09-.16v-.28H0v-.09H.1v-.12l.13-.01v.13h.12l-.01.1H.22v.27l.01.05c0 .02.02.02.04.02s.04 0 .06-.02l.05.08Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 533.72 429.6)"/><path d="M.36-.54c.05 0 .08.01.1.04.04.03.05.07.05.12V0H.38v-.36c0-.03 0-.06-.02-.07L.32-.45a.1.1 0 0 0-.06.02.23.23 0 0 0-.06.06V0H.09v-.74L.2-.75v.28a.2.2 0 0 1 .15-.07Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 539.89 429.6)"/><path d="M.51-.28v.06H.18c0 .05.01.08.04.1.02.03.05.04.09.04a.2.2 0 0 0 .13-.05l.05.07a.3.3 0 0 1-.2.07.24.24 0 0 1-.18-.07.3.3 0 0 1-.07-.2c0-.06.01-.1.03-.15a.25.25 0 0 1 .08-.1.22.22 0 0 1 .13-.03c.07 0 .13.02.17.07.04.04.06.1.06.2ZM.38-.3c0-.1-.03-.14-.1-.14a.09.09 0 0 0-.07.03.2.2 0 0 0-.03.11h.2Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 549.44 429.6)"/><path d="M.34-.54h.05L.37-.4a.2.2 0 0 0-.05 0 .09.09 0 0 0-.07.03.26.26 0 0 0-.04.1V0H.08v-.53h.1l.02.1A.19.19 0 0 1 .26-.5a.12.12 0 0 1 .08-.03Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 558.47 429.6)"/><path d="M.3-.54c.07 0 .13.02.18.07a.3.3 0 0 1 .06.2c0 .06 0 .1-.03.15A.23.23 0 0 1 .3.01a.23.23 0 0 1-.18-.07.3.3 0 0 1-.07-.2c0-.06.01-.1.03-.15a.22.22 0 0 1 .09-.1.25.25 0 0 1 .13-.03Zm0 .1c-.08 0-.12.05-.12.17 0 .07 0 .11.03.14a.1.1 0 0 0 .08.05.1.1 0 0 0 .09-.05.26.26 0 0 0 .03-.14C.4-.33.4-.37.38-.4a.1.1 0 0 0-.09-.05Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 569.23 429.6)"/><path d="M.5 0H.39v-.07a.2.2 0 0 1-.08.06.18.18 0 0 1-.09.03.14.14 0 0 1-.11-.05.18.18 0 0 1-.04-.12v-.38H.2v.36l.01.07.06.02c.04 0 .07-.03.1-.08v-.37H.5V0Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 578.83 429.6)"/><path d="M.38-.03a.23.23 0 0 1-.13.04C.19.01.15 0 .13-.03.1-.06.09-.1.09-.16v-.28H0v-.09H.1v-.12l.13-.01v.13h.12l-.01.1H.22v.27l.01.05c0 .02.02.02.04.02s.04 0 .06-.02l.05.08Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 588.33 429.6)"/><path d="M.35-.54c.07 0 .12.02.15.07s.05.12.05.2c0 .06-.01.1-.03.15a.22.22 0 0 1-.07.1.18.18 0 0 1-.11.03.16.16 0 0 1-.14-.05V.2L.09.22v-.75h.1l.02.07a.2.2 0 0 1 .16-.08ZM.3-.08c.08 0 .11-.06.11-.18 0-.07 0-.12-.02-.15A.08.08 0 0 0 .3-.45a.1.1 0 0 0-.06.02.15.15 0 0 0-.05.05v.24c.03.04.06.06.1.06Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 594.5 429.6)"/><path d="M.5 0H.39v-.07a.2.2 0 0 1-.08.06.18.18 0 0 1-.09.03.14.14 0 0 1-.11-.05.18.18 0 0 1-.04-.12v-.38H.2v.36l.01.07.06.02c.04 0 .07-.03.1-.08v-.37H.5V0Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 604.3 429.6)"/><path d="M.38-.03a.23.23 0 0 1-.13.04C.19.01.15 0 .13-.03.1-.06.09-.1.09-.16v-.28H0v-.09H.1v-.12l.13-.01v.13h.12l-.01.1H.22v.27l.01.05c0 .02.02.02.04.02s.04 0 .06-.02l.05.08Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 613.79 429.6)"/><path d="M.24-.54a.3.3 0 0 1 .2.06l-.06.07a.25.25 0 0 0-.13-.04.1.1 0 0 0-.06.02.04.04 0 0 0-.02.03v.03l.04.03a.6.6 0 0 0 .07.02l.13.06c.03.03.04.06.04.1 0 .06-.02.1-.07.13a.27.27 0 0 1-.15.05L.1 0A.3.3 0 0 1 0-.06l.07-.07c.05.03.1.05.14.05.03 0 .05 0 .07-.02a.05.05 0 0 0 .03-.04L.3-.18.27-.2A.67.67 0 0 0 .2-.23a.25.25 0 0 1-.12-.06.14.14 0 0 1-.04-.1c0-.03 0-.06.03-.08a.16.16 0 0 1 .07-.05.27.27 0 0 1 .1-.02Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 619.95 429.6)"/></g><g><path d="M.3-.54c.07 0 .13.02.18.07a.3.3 0 0 1 .06.2c0 .06 0 .1-.03.15A.23.23 0 0 1 .3.01a.23.23 0 0 1-.18-.07.3.3 0 0 1-.07-.2c0-.06.01-.1.03-.15a.22.22 0 0 1 .09-.1.25.25 0 0 1 .13-.03Zm0 .1c-.08 0-.12.05-.12.17 0 .07 0 .11.03.14a.1.1 0 0 0 .08.05.1.1 0 0 0 .09-.05.26.26 0 0 0 .03-.14C.4-.33.4-.37.38-.4a.1.1 0 0 0-.09-.05Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 326.94 358.54)"/><path d="M.38-.03a.23.23 0 0 1-.13.04C.19.01.15 0 .13-.03.1-.06.09-.1.09-.16v-.28H0v-.09H.1v-.12l.13-.01v.13h.12l-.01.1H.22v.27l.01.05c0 .02.02.02.04.02s.04 0 .06-.02l.05.08Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 336.55 358.54)"/><path d="M.36-.54c.05 0 .08.01.1.04.04.03.05.07.05.12V0H.38v-.36c0-.03 0-.06-.02-.07L.32-.45a.1.1 0 0 0-.06.02.23.23 0 0 0-.06.06V0H.09v-.74L.2-.75v.28a.2.2 0 0 1 .15-.07Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 342.72 358.54)"/><path d="M.51-.28v.06H.18c0 .05.01.08.04.1.02.03.05.04.09.04a.2.2 0 0 0 .13-.05l.05.07a.3.3 0 0 1-.2.07.24.24 0 0 1-.18-.07.3.3 0 0 1-.07-.2c0-.06.01-.1.03-.15a.25.25 0 0 1 .08-.1.22.22 0 0 1 .13-.03c.07 0 .13.02.17.07.04.04.06.1.06.2ZM.38-.3c0-.1-.03-.14-.1-.14a.09.09 0 0 0-.07.03.2.2 0 0 0-.03.11h.2Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 352.27 358.54)"/><path d="M.34-.54h.05L.37-.4a.2.2 0 0 0-.05 0 .09.09 0 0 0-.07.03.26.26 0 0 0-.04.1V0H.08v-.53h.1l.02.1A.19.19 0 0 1 .26-.5a.12.12 0 0 1 .08-.03Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 361.3 358.54)"/><path d="M.2-.53V0H.08v-.53H.2ZM.14-.8l.06.03.02.05c0 .02 0 .04-.02.06a.08.08 0 0 1-.06.02c-.02 0-.04 0-.06-.02a.07.07 0 0 1-.02-.06c0-.02 0-.04.02-.05A.08.08 0 0 1 .14-.8Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 372.06 358.54)"/><path d="M.36-.54c.05 0 .08.01.11.04s.04.07.04.12V0H.38v-.36c0-.03 0-.06-.02-.07L.32-.45a.1.1 0 0 0-.06.02.22.22 0 0 0-.06.06V0H.09v-.53h.1l.02.07a.2.2 0 0 1 .16-.08Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 376.7 358.54)"/><path d="M.35-.54c.07 0 .12.02.15.07s.05.12.05.2c0 .06-.01.1-.03.15a.22.22 0 0 1-.07.1.18.18 0 0 1-.11.03.16.16 0 0 1-.14-.05V.2L.09.22v-.75h.1l.02.07a.2.2 0 0 1 .16-.08ZM.3-.08c.08 0 .11-.06.11-.18 0-.07 0-.12-.02-.15A.08.08 0 0 0 .3-.45a.1.1 0 0 0-.06.02.15.15 0 0 0-.05.05v.24c.03.04.06.06.1.06Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 386.25 358.54)"/><path d="M.5 0H.39v-.07a.2.2 0 0 1-.08.06.18.18 0 0 1-.09.03.14.14 0 0 1-.11-.05.18.18 0 0 1-.04-.12v-.38H.2v.36l.01.07.06.02c.04 0 .07-.03.1-.08v-.37H.5V0Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 396.06 358.54)"/><path d="M.38-.03a.23.23 0 0 1-.13.04C.19.01.15 0 .13-.03.1-.06.09-.1.09-.16v-.28H0v-.09H.1v-.12l.13-.01v.13h.12l-.01.1H.22v.27l.01.05c0 .02.02.02.04.02s.04 0 .06-.02l.05.08Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 405.54 358.54)"/><path d="M.24-.54a.3.3 0 0 1 .2.06l-.06.07a.25.25 0 0 0-.13-.04.1.1 0 0 0-.06.02.04.04 0 0 0-.02.03v.03l.04.03a.6.6 0 0 0 .07.02l.13.06c.03.03.04.06.04.1 0 .06-.02.1-.07.13a.27.27 0 0 1-.15.05L.1 0A.3.3 0 0 1 0-.06l.07-.07c.05.03.1.05.14.05.03 0 .05 0 .07-.02a.05.05 0 0 0 .03-.04L.3-.18.27-.2A.67.67 0 0 0 .2-.23a.25.25 0 0 1-.12-.06.14.14 0 0 1-.04-.1c0-.03 0-.06.03-.08a.16.16 0 0 1 .07-.05.27.27 0 0 1 .1-.02Z" style="fill:#b4c4c9;fill-rule:nonzero" transform="matrix(16.44712 0 0 16.44712 411.71 358.54)"/></g><path d="m756.45 347.77 15 7.5-15 7.5v-15Z" style="fill:#073b4c"/><path d="M668.55 355.27h90.9" style="fill:none;stroke:#073b4c;stroke-width:5px"/><path d="m756.45 418.02 15 7.5-15 7.5v-15Z" style="fill:#073b4c"/><path d="M668.55 613.52h26.37A25.08 25.08 0 0 0 720 588.44V450.7a25.18 25.18 0 0 1 25.18-25.18h14.27" style="fill:none;stroke:#073b4c;stroke-width:5px"/><path d="M501.96 140.8c2.01 0 3.77.29 5.28.86 1.5.58 2.97 1.46 4.41 2.64l-3.21 3.75a9.68 9.68 0 0 0-6.15-2.36c-2.46 0-4.44 1-5.93 2.98-1.48 1.99-2.23 5.1-2.23 9.36 0 4.16.74 7.25 2.21 9.27a7 7 0 0 0 5.95 3.02 8.4 8.4 0 0 0 3.5-.7 17.72 17.72 0 0 0 3.27-1.99l2.98 3.75a13.86 13.86 0 0 1-9.98 4.03c-2.89 0-5.43-.67-7.64-2.02a13.29 13.29 0 0 1-5.14-5.93c-1.21-2.6-1.82-5.75-1.82-9.43 0-3.61.63-6.72 1.9-9.31 1.26-2.6 2.99-4.56 5.18-5.9a13.9 13.9 0 0 1 7.42-2.02ZM534.64 167.97c0 .99.16 1.72.46 2.18.3.47.8.83 1.46 1.08l-1.3 4.08a7.85 7.85 0 0 1-3.52-1.05 5.4 5.4 0 0 1-2.09-2.64 8.14 8.14 0 0 1-3.24 2.85c-1.3.63-2.74.94-4.34.94-2.53 0-4.53-.72-6-2.16a7.57 7.57 0 0 1-2.21-5.67c0-2.75 1-4.85 3-6.3 2-1.46 4.86-2.2 8.57-2.2h3.17v-1.43c0-1.63-.38-2.78-1.13-3.43-.75-.66-1.96-.99-3.63-.99-1.85 0-4.1.45-6.72 1.35l-1.44-4.18a25.65 25.65 0 0 1 9.22-1.82c6.5 0 9.74 2.9 9.74 8.73v10.66Zm-10.94 2.97c2.08 0 3.71-1.04 4.9-3.12v-5.13h-2.55c-3.97 0-5.95 1.47-5.95 4.41 0 1.22.3 2.16.91 2.84.61.67 1.5 1 2.69 1ZM549.62 148.57c3.42 0 6.43 1.01 9.02 3.03l-2.4 3.6a11.93 11.93 0 0 0-6.38-2.07c-1.22 0-2.16.24-2.83.7-.67.46-1.01 1.08-1.01 1.85 0 .57.14 1.05.43 1.44.29.38.81.74 1.56 1.08.75.34 1.87.71 3.34 1.13 2.75.73 4.79 1.7 6.12 2.92s1.99 2.92 1.99 5.1c0 2.52-1.02 4.5-3.07 5.92s-4.6 2.14-7.63 2.14c-2.08 0-3.98-.32-5.7-.96a13.8 13.8 0 0 1-4.43-2.64l3.07-3.46c2.2 1.67 4.51 2.5 6.91 2.5 1.38 0 2.47-.27 3.29-.82a2.57 2.57 0 0 0 1.22-2.25 3 3 0 0 0-.45-1.76c-.3-.43-.85-.81-1.63-1.15-.79-.33-2.01-.74-3.68-1.22-2.59-.7-4.5-1.7-5.7-2.95a6.55 6.55 0 0 1-1.83-4.73c0-1.41.4-2.67 1.22-3.8.82-1.11 1.97-2 3.46-2.63 1.49-.64 3.19-.96 5.11-.96ZM577.99 148.57c2.24 0 4 .7 5.28 2.07 1.28 1.37 1.92 3.26 1.92 5.66v18.39h-6.15v-17.43c0-1.5-.26-2.56-.79-3.17-.53-.6-1.3-.9-2.33-.9-1.02 0-1.96.32-2.83.98-.86.65-1.7 1.59-2.5 2.8v17.72h-6.14v-35.52l6.15-.63v13.78c2.04-2.5 4.5-3.75 7.39-3.75ZM613.84 141.52l-.67 5.04h-8.64v28.13h-6.38v-28.13h-8.93v-5.04h24.62ZM625.5 148.57c3.75 0 6.67 1.2 8.77 3.58 2.1 2.38 3.14 5.66 3.14 9.82 0 2.65-.48 5-1.44 7.03a10.93 10.93 0 0 1-4.13 4.73 11.8 11.8 0 0 1-6.38 1.68c-3.74 0-6.67-1.2-8.78-3.58-2.12-2.38-3.17-5.67-3.17-9.86 0-2.66.48-5 1.44-7.01a10.9 10.9 0 0 1 4.15-4.7 11.92 11.92 0 0 1 6.4-1.68Zm0 4.66c-3.67 0-5.51 2.91-5.51 8.74 0 3 .45 5.22 1.37 6.64a4.55 4.55 0 0 0 4.1 2.14c1.82 0 3.2-.72 4.1-2.16.92-1.44 1.37-3.65 1.37-6.62 0-2.98-.45-5.18-1.37-6.6a4.5 4.5 0 0 0-4.05-2.14ZM649.32 138.45v36.24h-6.15v-35.57l6.15-.67Zm15.21 10.85-8.45 11.18 9.27 14.2h-7.06l-8.73-13.86 8.5-11.52h6.47ZM689.1 161.4c0 .31-.04 1.14-.14 2.49h-15.93c.19 2.46.83 4.22 1.92 5.28a5.94 5.94 0 0 0 4.32 1.58c1.12 0 2.17-.18 3.17-.55.99-.37 2.04-.94 3.16-1.7l2.55 3.5a14.62 14.62 0 0 1-9.41 3.4c-3.87 0-6.86-1.18-8.95-3.55-2.1-2.36-3.15-5.6-3.15-9.7 0-2.58.45-4.91 1.35-6.98.9-2.06 2.19-3.68 3.89-4.84a10.4 10.4 0 0 1 6.04-1.76c3.56 0 6.3 1.13 8.26 3.39 1.95 2.25 2.93 5.4 2.93 9.43Zm-6.09-1.79c0-4.44-1.65-6.67-4.94-6.67a4.2 4.2 0 0 0-3.53 1.66c-.85 1.1-1.35 2.87-1.51 5.3H683v-.29ZM708.16 148.57c2.28 0 4.04.68 5.3 2.04 1.27 1.36 1.9 3.26 1.9 5.7v18.38h-6.14v-17.43c0-1.5-.26-2.56-.8-3.17-.52-.6-1.3-.9-2.32-.9-1.06 0-2 .32-2.86.98-.84.65-1.67 1.6-2.47 2.85v17.67h-6.14v-25.4h5.33l.48 3.32c2.08-2.7 4.65-4.04 7.72-4.04ZM747.38 140.8c2.02 0 3.78.29 5.28.86 1.5.58 2.98 1.46 4.42 2.64l-3.22 3.75a9.68 9.68 0 0 0-6.14-2.36c-2.47 0-4.44 1-5.93 2.98-1.49 1.99-2.23 5.1-2.23 9.36 0 4.16.73 7.25 2.2 9.27a7 7 0 0 0 5.96 3.02 8.4 8.4 0 0 0 3.5-.7 17.72 17.72 0 0 0 3.26-1.99l2.98 3.75a13.86 13.86 0 0 1-9.98 4.03c-2.88 0-5.43-.67-7.64-2.02a13.29 13.29 0 0 1-5.13-5.93c-1.22-2.6-1.83-5.75-1.83-9.43 0-3.61.64-6.72 1.9-9.31 1.26-2.6 3-4.56 5.18-5.9a13.9 13.9 0 0 1 7.42-2.02ZM773.68 148.62c.93 0 1.78.11 2.55.34l-1.06 5.95a9.28 9.28 0 0 0-2.25-.29c-1.5 0-2.7.54-3.56 1.61-.86 1.07-1.55 2.71-2.06 4.92v13.54h-6.14v-25.4h5.32l.58 5a9.13 9.13 0 0 1 2.64-4.2 5.98 5.98 0 0 1 3.98-1.47ZM799.46 161.4c0 .31-.05 1.14-.14 2.49h-15.94c.2 2.46.83 4.22 1.92 5.28a5.94 5.94 0 0 0 4.32 1.58c1.12 0 2.18-.18 3.17-.55.99-.37 2.05-.94 3.17-1.7l2.54 3.5a14.62 14.62 0 0 1-9.4 3.4c-3.88 0-6.86-1.18-8.96-3.55-2.1-2.36-3.14-5.6-3.14-9.7 0-2.58.44-4.91 1.34-6.98.9-2.06 2.2-3.68 3.89-4.84a10.4 10.4 0 0 1 6.05-1.76c3.55 0 6.3 1.13 8.25 3.39 1.95 2.25 2.93 5.4 2.93 9.43Zm-6.1-1.79c0-4.44-1.64-6.67-4.94-6.67a4.2 4.2 0 0 0-3.53 1.66c-.85 1.1-1.35 2.87-1.51 5.3h9.98v-.29ZM823.27 167.97c0 .99.15 1.72.45 2.18.3.47.8.83 1.47 1.08l-1.3 4.08a7.85 7.85 0 0 1-3.53-1.05 5.4 5.4 0 0 1-2.08-2.64 8.14 8.14 0 0 1-3.24 2.85c-1.3.63-2.75.94-4.35.94-2.53 0-4.53-.72-6-2.16a7.57 7.57 0 0 1-2.2-5.67c0-2.75 1-4.85 3-6.3 2-1.46 4.85-2.2 8.56-2.2h3.17v-1.43c0-1.63-.38-2.78-1.13-3.43-.75-.66-1.96-.99-3.62-.99-1.86 0-4.1.45-6.72 1.35l-1.44-4.18a25.65 25.65 0 0 1 9.21-1.82c6.5 0 9.75 2.9 9.75 8.73v10.66Zm-10.95 2.97c2.08 0 3.72-1.04 4.9-3.12v-5.13h-2.54c-3.97 0-5.96 1.47-5.96 4.41 0 1.22.3 2.16.92 2.84.6.67 1.5 1 2.68 1ZM845.25 173.49c-.9.64-1.9 1.12-3 1.44-1.1.32-2.23.48-3.38.48-2.5-.04-4.4-.75-5.69-2.14-1.3-1.4-1.94-3.45-1.94-6.17v-13.39h-3.99v-4.42h3.99v-5.61l6.14-.72v6.33h5.9l-.62 4.42h-5.28v13.25c0 1.25.22 2.14.65 2.69.43.54 1.11.81 2.04.81.93 0 1.93-.3 3.02-.9l2.16 3.93ZM854.85 149.3v25.39h-6.14v-25.4h6.14Zm-3.12-12.87a3.8 3.8 0 0 1 2.81 1.08c.72.72 1.08 1.6 1.08 2.67 0 1.05-.36 1.93-1.08 2.63a3.85 3.85 0 0 1-2.8 1.06 3.78 3.78 0 0 1-2.77-1.06 3.54 3.54 0 0 1-1.08-2.64c0-1.05.36-1.94 1.08-2.66a3.74 3.74 0 0 1 2.76-1.08ZM872.61 148.57c3.75 0 6.67 1.2 8.76 3.58 2.1 2.38 3.15 5.66 3.15 9.82 0 2.65-.48 5-1.44 7.03a10.93 10.93 0 0 1-4.13 4.73 11.8 11.8 0 0 1-6.39 1.68c-3.74 0-6.67-1.2-8.78-3.58-2.11-2.38-3.17-5.67-3.17-9.86 0-2.66.48-5 1.44-7.01a10.9 10.9 0 0 1 4.15-4.7 11.92 11.92 0 0 1 6.41-1.68Zm0 4.66c-3.68 0-5.52 2.91-5.52 8.74 0 3 .46 5.22 1.37 6.64a4.55 4.55 0 0 0 4.1 2.14c1.83 0 3.2-.72 4.1-2.16.92-1.44 1.38-3.65 1.38-6.62 0-2.98-.46-5.18-1.37-6.6a4.5 4.5 0 0 0-4.06-2.14ZM903.81 148.57c2.27 0 4.04.68 5.3 2.04 1.27 1.36 1.9 3.26 1.9 5.7v18.38h-6.14v-17.43c0-1.5-.27-2.56-.8-3.17-.52-.6-1.3-.9-2.32-.9-1.06 0-2.01.32-2.86.98-.85.65-1.67 1.6-2.47 2.85v17.67h-6.14v-25.4h5.32l.48 3.32c2.08-2.7 4.66-4.04 7.73-4.04Z" style="fill:#073b4c;fill-rule:nonzero"/><g><path d="m366.64 818.82-.28 2.1h-3.6v11.72h-2.66v-11.72h-3.72v-2.1h10.26ZM371.92 821.08a5 5 0 0 1 3.9 1.55c.93 1.03 1.4 2.47 1.4 4.33 0 1.85-.47 3.3-1.42 4.36a4.95 4.95 0 0 1-3.88 1.58 5 5 0 0 1-3.9-1.56c-.94-1.04-1.42-2.5-1.42-4.38 0-1.2.22-2.25.65-3.13a4.71 4.71 0 0 1 1.85-2.04c.8-.48 1.74-.71 2.82-.71Zm0 1.88c-.86 0-1.52.32-1.98.96-.45.64-.68 1.65-.68 3.04 0 1.41.23 2.44.68 3.09.46.64 1.12.97 1.98.97.88 0 1.54-.32 1.98-.96.44-.64.66-1.68.66-3.1 0-1.39-.22-2.4-.67-3.04a2.25 2.25 0 0 0-1.97-.96ZM382.24 821.32v11.32h-2.54v-11.32h2.54Zm6.8 0-3.98 5.08 4.3 6.24h-2.98l-4.04-6.06 3.98-5.26h2.72ZM397.98 821.32l-.26 1.84h-4.34v2.8h3.78v1.82h-3.78v3H398v1.86h-7.16v-11.32h7.14ZM409.54 832.64h-3.28l-3.84-9 .06.48c.1.73.2 1.42.25 2.06.06.64.1 1.36.1 2.18v4.28h-2.3v-11.32h3.2l3.9 9.02c-.26-1.4-.39-2.82-.39-4.26v-4.76h2.3v11.32ZM423.04 818.52c.84 0 1.57.12 2.2.36.63.24 1.24.6 1.84 1.1l-1.34 1.56a4.04 4.04 0 0 0-2.56-.98c-1.03 0-1.85.41-2.47 1.24-.62.82-.93 2.12-.93 3.9 0 1.73.3 3.02.92 3.86a2.91 2.91 0 0 0 2.48 1.26c.55 0 1.03-.1 1.46-.3.43-.19.88-.46 1.36-.82l1.24 1.56a5.68 5.68 0 0 1-4.16 1.68 5.53 5.53 0 0 1-5.32-3.31 9.24 9.24 0 0 1-.76-3.93c0-1.5.27-2.8.8-3.88a5.74 5.74 0 0 1 2.15-2.46 5.8 5.8 0 0 1 3.1-.84ZM435.16 832.64l-.68-2.5h-3.74l-.68 2.5h-2.66l3.7-11.32h3.08l3.66 11.32h-2.68Zm-3.92-4.36h2.74l-1.38-5.1-1.36 5.1ZM446.24 821.32l-.26 1.98h-3.04v9.34h-2.56v-9.34h-3.16v-1.98h9.02ZM455.1 821.32l-.26 1.84h-4.34v2.8h3.78v1.82h-3.78v3h4.62v1.86h-7.16v-11.32h7.14ZM462.22 821.08c1.5 0 2.83.45 3.96 1.36l-1.38 1.4a3.63 3.63 0 0 0-2.44-.88c-.9 0-1.62.33-2.19 1-.57.66-.85 1.66-.85 3 0 1.45.22 2.5.66 3.12.44.62 1.1.94 2 .94.68 0 1.28-.14 1.8-.4v-2.66h-1.7l-.24-1.82h4.4v5.6a7.5 7.5 0 0 1-1.99.86c-.73.2-1.48.3-2.27.3-1.73 0-3.05-.5-3.96-1.51-.9-1-1.36-2.49-1.36-4.43 0-1.23.25-2.29.74-3.17a5.01 5.01 0 0 1 2.01-2.02 5.79 5.79 0 0 1 2.81-.7ZM473.48 821.08a5 5 0 0 1 3.9 1.55c.93 1.03 1.4 2.47 1.4 4.33 0 1.85-.47 3.3-1.42 4.36a4.95 4.95 0 0 1-3.88 1.58 5 5 0 0 1-3.9-1.56c-.94-1.04-1.42-2.5-1.42-4.38 0-1.2.22-2.25.65-3.13a4.71 4.71 0 0 1 1.85-2.04c.8-.48 1.74-.71 2.82-.71Zm0 1.88c-.86 0-1.52.32-1.98.96-.45.64-.68 1.65-.68 3.04 0 1.41.23 2.44.68 3.09.46.64 1.12.97 1.98.97.88 0 1.54-.32 1.98-.96.44-.64.66-1.68.66-3.1 0-1.39-.22-2.4-.67-3.04a2.25 2.25 0 0 0-1.97-.96ZM485.08 828.24h-1.26v4.4h-2.56v-11.32h3.72c3.23 0 4.84 1.12 4.84 3.38 0 .76-.19 1.39-.57 1.89-.38.5-.97.9-1.77 1.2l3.08 4.85h-2.9l-2.58-4.4Zm-1.26-1.78h1.3c.7 0 1.22-.14 1.56-.41.35-.28.52-.71.52-1.31 0-.56-.18-.97-.54-1.23-.36-.26-.92-.4-1.68-.4h-1.16v3.35ZM500.54 821.32l-3.86 7.04v4.28h-2.58v-4.26l-3.84-7.06h2.8l2.38 5.12 2.38-5.12h2.72ZM629.94 818.82l-.28 2.1h-3.6v11.72h-2.66v-11.72h-3.72v-2.1h10.26ZM635.22 821.08a5 5 0 0 1 3.89 1.55c.94 1.03 1.41 2.47 1.41 4.33 0 1.85-.47 3.3-1.42 4.36a4.95 4.95 0 0 1-3.88 1.58 5.01 5.01 0 0 1-3.9-1.56c-.95-1.04-1.42-2.5-1.42-4.38 0-1.2.22-2.25.65-3.13a4.71 4.71 0 0 1 1.85-2.04c.8-.48 1.74-.71 2.82-.71Zm0 1.88c-.87 0-1.53.32-1.98.96-.45.64-.68 1.65-.68 3.04 0 1.41.23 2.44.68 3.09.45.64 1.11.97 1.98.97.88 0 1.54-.32 1.98-.96.44-.64.66-1.68.66-3.1 0-1.39-.22-2.4-.67-3.04a2.25 2.25 0 0 0-1.97-.96ZM645.54 821.32v11.32H643v-11.32h2.54Zm6.8 0-3.98 5.08 4.3 6.24h-2.98l-4.04-6.06 3.98-5.26h2.72ZM661.28 821.32l-.26 1.84h-4.34v2.8h3.78v1.82h-3.78v3h4.62v1.86h-7.16v-11.32h7.14ZM672.84 832.64h-3.28l-3.84-9 .06.48a23.59 23.59 0 0 1 .34 4.24v4.28h-2.3v-11.32h3.2l3.9 9.02a23.9 23.9 0 0 1-.38-4.26v-4.76h2.3v11.32ZM685.04 818.52a7 7 0 0 1 2.54.42c.72.28 1.4.7 2.02 1.28l-1.3 1.5a4.58 4.58 0 0 0-3.1-1.18c-.64 0-1.16.14-1.55.43-.4.28-.59.69-.59 1.2 0 .35.08.64.23.87.15.22.43.44.83.64.4.2 1 .42 1.78.66 1.36.42 2.38.95 3.07 1.59.69.63 1.03 1.55 1.03 2.77a3.92 3.92 0 0 1-2.44 3.7c-.79.36-1.72.54-2.8.54-1.05 0-2-.17-2.83-.51a6.6 6.6 0 0 1-2.15-1.4l1.36-1.51c.53.45 1.09.8 1.66 1.03.57.23 1.2.35 1.9.35.76 0 1.37-.18 1.84-.54.47-.36.7-.87.7-1.52 0-.4-.08-.73-.24-1-.16-.25-.43-.49-.82-.7-.39-.2-.95-.42-1.68-.64a7.88 7.88 0 0 1-3.18-1.64 3.37 3.37 0 0 1-.98-2.52c0-.76.2-1.43.6-2 .4-.58.96-1.02 1.67-1.34a5.88 5.88 0 0 1 2.43-.48ZM701.18 828.88c0 1.2-.4 2.17-1.19 2.9-.8.75-1.92 1.12-3.39 1.12-1.47 0-2.59-.37-3.37-1.1a3.81 3.81 0 0 1-1.17-2.92v-7.56h2.54v7.46c0 .74.16 1.3.49 1.67.33.36.83.55 1.51.55.7 0 1.2-.19 1.53-.55.33-.37.49-.93.49-1.67v-7.46h2.56v7.56ZM707.9 821.32c1.56 0 2.77.3 3.63.92.86.61 1.29 1.52 1.29 2.74 0 1.28-.43 2.24-1.29 2.88-.86.64-2 .96-3.43.96h-1.36v3.82h-2.54v-11.32h3.7Zm0 5.64c.75 0 1.31-.15 1.7-.45.39-.3.58-.8.58-1.51 0-1.24-.77-1.86-2.32-1.86h-1.12v3.82h1.16ZM718.66 821.32c1.56 0 2.77.3 3.63.92.86.61 1.29 1.52 1.29 2.74 0 1.28-.43 2.24-1.29 2.88-.86.64-2 .96-3.43.96h-1.36v3.82h-2.54v-11.32h3.7Zm0 5.64c.75 0 1.31-.15 1.7-.45.39-.3.58-.8.58-1.51 0-1.24-.77-1.86-2.32-1.86h-1.12v3.82h1.16ZM728.26 821.32v9.28h4.76l-.28 2.04h-7.02v-11.32h2.54ZM742 821.32l-3.86 7.04v4.28h-2.58v-4.26l-3.84-7.06h2.8l2.38 5.12 2.38-5.12H742ZM871.34 832.73h-3.42l-4.74-11.18a38.98 38.98 0 0 1 .36 5.54v5.64h-2.4V818.9h3.34l4.82 11.2a38.46 38.46 0 0 1-.36-4.72v-6.48h2.4v13.82ZM879.14 821.17a5 5 0 0 1 3.89 1.55c.94 1.03 1.4 2.47 1.4 4.33 0 1.85-.46 3.3-1.41 4.36a4.95 4.95 0 0 1-3.88 1.58 5.01 5.01 0 0 1-3.9-1.56c-.95-1.04-1.42-2.5-1.42-4.38 0-1.2.22-2.25.65-3.13a4.72 4.72 0 0 1 1.85-2.04c.8-.48 1.74-.71 2.82-.71Zm0 1.88c-.87 0-1.53.32-1.98.96-.45.64-.68 1.65-.68 3.04 0 1.41.23 2.44.68 3.09.45.64 1.11.97 1.98.97.88 0 1.54-.32 1.98-.96.44-.64.66-1.68.66-3.1 0-1.39-.22-2.4-.67-3.04a2.25 2.25 0 0 0-1.97-.96ZM895.94 832.73h-3.28l-3.84-9 .06.48a23.59 23.59 0 0 1 .34 4.24v4.28h-2.3V821.4h3.2l3.9 9.02a23.9 23.9 0 0 1-.38-4.26v-4.76h2.3v11.32ZM898.58 825.45h6.04v2.04h-6.04zM907.26 832.73V818.9h7.82l-.28 1.96h-4.9V825h4.26v1.96h-4.26v5.76h-2.64ZM925.36 828.97c0 1.2-.4 2.17-1.2 2.9-.79.75-1.92 1.12-3.38 1.12-1.47 0-2.6-.37-3.37-1.1a3.81 3.81 0 0 1-1.17-2.92v-7.56h2.54v7.46c0 .74.16 1.3.49 1.67.32.36.83.55 1.5.55.7 0 1.21-.19 1.54-.55.32-.37.49-.93.49-1.67v-7.46h2.56v7.56ZM937.4 832.73h-3.28l-3.84-9 .06.48a23.59 23.59 0 0 1 .34 4.24v4.28h-2.3V821.4h3.2l3.9 9.02a23.9 23.9 0 0 1-.38-4.26v-4.76h2.3v11.32ZM945.42 821.17c1.5 0 2.83.45 3.96 1.36l-1.38 1.4a3.63 3.63 0 0 0-2.44-.88c-.9 0-1.62.33-2.2 1-.56.66-.84 1.66-.84 3 0 1.45.22 2.5.66 3.12.44.62 1.1.94 2 .94.68 0 1.28-.14 1.8-.4v-2.66h-1.7l-.24-1.82h4.4v5.6a7.5 7.5 0 0 1-2 .86c-.72.2-1.48.3-2.26.3-1.74 0-3.06-.5-3.96-1.51-.9-1-1.36-2.49-1.36-4.43 0-1.23.24-2.29.74-3.17a5.02 5.02 0 0 1 2-2.02 5.8 5.8 0 0 1 2.82-.7ZM952.12 821.41h2.56v11.32h-2.56zM964.04 826.73c1.8.33 2.7 1.23 2.7 2.7 0 1.2-.45 2.05-1.34 2.55-.9.5-2.15.75-3.76.75h-3.74V821.4h3.26c1.64 0 2.9.23 3.76.69.87.46 1.3 1.2 1.3 2.25 0 .68-.2 1.2-.6 1.57-.4.36-.93.63-1.58.8Zm-3.6-3.5v2.72h1.24c.61 0 1.1-.12 1.44-.35.35-.24.52-.58.52-1.03 0-.5-.18-.84-.55-1.04-.37-.2-.93-.3-1.7-.3h-.95Zm1.22 7.64c.79 0 1.39-.11 1.8-.33.41-.22.62-.63.62-1.23 0-.58-.2-1-.6-1.26-.4-.27-.94-.4-1.62-.4h-1.42v3.22h1.22ZM971.6 821.4v9.29h4.76l-.28 2.04h-7.02V821.4h2.54ZM985.44 821.4l-.26 1.85h-4.34v2.8h3.78v1.82h-3.78v3h4.62v1.86h-7.16V821.4h7.14ZM1001.86 818.9l-.28 2.1h-3.6v11.73h-2.66V821h-3.72v-2.1h10.26ZM1007.14 821.17a5 5 0 0 1 3.89 1.55c.94 1.03 1.41 2.47 1.41 4.33 0 1.85-.47 3.3-1.42 4.36a4.95 4.95 0 0 1-3.88 1.58 5.01 5.01 0 0 1-3.9-1.56c-.95-1.04-1.42-2.5-1.42-4.38 0-1.2.22-2.25.65-3.13a4.72 4.72 0 0 1 1.85-2.04c.8-.48 1.74-.71 2.82-.71Zm0 1.88c-.87 0-1.53.32-1.98.96-.45.64-.68 1.65-.68 3.04 0 1.41.23 2.44.68 3.09.45.64 1.11.97 1.98.97.88 0 1.54-.32 1.98-.96.44-.64.66-1.68.66-3.1 0-1.39-.22-2.4-.67-3.04a2.25 2.25 0 0 0-1.97-.96ZM1017.46 821.4v11.33h-2.54V821.4h2.54Zm6.8 0-3.98 5.09 4.3 6.24h-2.98l-4.04-6.06 3.98-5.26h2.72ZM1033.2 821.4l-.26 1.85h-4.34v2.8h3.78v1.82h-3.78v3h4.62v1.86h-7.16V821.4h7.14ZM1044.76 832.73h-3.28l-3.84-9 .06.48a23.59 23.59 0 0 1 .34 4.24v4.28h-2.3V821.4h3.2l3.9 9.02a23.9 23.9 0 0 1-.38-4.26v-4.76h2.3v11.32ZM1051.54 821.17c.85 0 1.6.12 2.26.36.65.24 1.25.6 1.78 1.08l-1.24 1.4a4.16 4.16 0 0 0-2.62-.96c-.56 0-1 .1-1.32.3-.32.2-.48.5-.48.88 0 .25.06.46.19.62.13.16.35.31.68.46.33.14.82.32 1.49.52 1.19.36 2.07.8 2.66 1.35.59.54.88 1.3.88 2.27 0 .7-.18 1.3-.55 1.84-.37.53-.9.95-1.6 1.25-.7.3-1.52.45-2.47.45-.96 0-1.82-.15-2.58-.43a5.62 5.62 0 0 1-1.92-1.17l1.28-1.46a4.72 4.72 0 0 0 3.12 1.16c.63 0 1.13-.13 1.5-.4.37-.25.56-.6.56-1.04 0-.3-.06-.54-.19-.73-.13-.2-.35-.37-.67-.53a8.59 8.59 0 0 0-1.38-.5 6.8 6.8 0 0 1-2.81-1.4 2.8 2.8 0 0 1-.83-2.08c0-1 .4-1.8 1.21-2.37a5.1 5.1 0 0 1 3.05-.87ZM1067.46 816.79a16.45 16.45 0 0 0-2.15 4.1 15.26 15.26 0 0 0-.67 4.84c0 1.88.22 3.48.67 4.82.45 1.33 1.16 2.7 2.15 4.12l-1.64 1.1a44.2 44.2 0 0 1-2.05-3.1c-.5-.84-.92-1.84-1.25-3-.33-1.15-.5-2.46-.5-3.94s.17-2.8.5-3.95c.33-1.16.75-2.16 1.25-3 .5-.85 1.18-1.88 2.05-3.1l1.64 1.1ZM1079.76 832.73h-3.42l-4.74-11.18a38.98 38.98 0 0 1 .36 5.54v5.64h-2.4V818.9h3.34l4.82 11.2a38.46 38.46 0 0 1-.36-4.72v-6.48h2.4v13.82ZM1083 832.73V818.9h7.82l-.28 1.96h-4.9V825h4.26v1.96h-4.26v5.76H1083ZM1101.66 818.9l-.28 2.1h-3.6v11.73h-2.66V821h-3.72v-2.1h10.26ZM1105.94 821.17c.85 0 1.6.12 2.26.36.65.24 1.25.6 1.78 1.08l-1.24 1.4a4.16 4.16 0 0 0-2.62-.96c-.56 0-1 .1-1.32.3-.32.2-.48.5-.48.88 0 .25.06.46.19.62.13.16.35.31.68.46.33.14.82.32 1.49.52 1.19.36 2.07.8 2.66 1.35.59.54.88 1.3.88 2.27 0 .7-.18 1.3-.55 1.84-.37.53-.9.95-1.6 1.25-.7.3-1.52.45-2.47.45-.96 0-1.82-.15-2.58-.43a5.62 5.62 0 0 1-1.92-1.17l1.28-1.46a4.72 4.72 0 0 0 3.12 1.16c.63 0 1.13-.13 1.5-.4.37-.25.56-.6.56-1.04 0-.3-.06-.54-.19-.73-.13-.2-.35-.37-.67-.53a8.59 8.59 0 0 0-1.38-.5 6.8 6.8 0 0 1-2.81-1.4 2.8 2.8 0 0 1-.83-2.08c0-1 .4-1.8 1.21-2.37a5.1 5.1 0 0 1 3.05-.87ZM1112.98 815.69c.87 1.2 1.55 2.22 2.05 3.08a13.23 13.23 0 0 1 1.75 6.96 13.2 13.2 0 0 1-1.75 6.96c-.5.85-1.18 1.88-2.05 3.08l-1.62-1.1a16.9 16.9 0 0 0 2.14-4.12c.45-1.34.68-2.94.68-4.82 0-1.88-.23-3.49-.68-4.81a17.36 17.36 0 0 0-2.14-4.13l1.62-1.1Z" style="fill:#073b4c;fill-rule:nonzero"/></g><g><path d="M796.78 222.86c-.81.3-2.04.43-3.67.43.79.36 1.37.8 1.74 1.31.38.52.57 1.17.57 1.96 0 .83-.2 1.57-.62 2.2-.4.65-1 1.15-1.77 1.52a6.3 6.3 0 0 1-2.72.55c-.58 0-1.08-.06-1.52-.2-.35.25-.52.56-.52.94 0 .6.5.9 1.53.9h1.94c.93 0 1.74.14 2.44.45.7.3 1.24.73 1.62 1.28.38.55.58 1.17.58 1.86 0 1.28-.55 2.28-1.64 3-1.08.7-2.65 1.06-4.7 1.06-1.47 0-2.63-.15-3.47-.46a3.31 3.31 0 0 1-1.78-1.32 4.18 4.18 0 0 1-.53-2.2h2.76c0 .44.08.8.25 1.05.17.26.47.45.91.58.44.12 1.08.19 1.9.19 1.18 0 2-.15 2.48-.43.48-.3.72-.7.72-1.25 0-.48-.18-.85-.55-1.12-.37-.26-.9-.4-1.6-.4h-1.93c-1.2 0-2.1-.22-2.71-.69a2.12 2.12 0 0 1-.91-1.75c0-.45.13-.88.4-1.3.26-.41.62-.76 1.09-1.05a4.2 4.2 0 0 1-1.7-1.48 3.92 3.92 0 0 1-.54-2.1 4.3 4.3 0 0 1 2.54-4c.79-.37 1.7-.56 2.72-.56 1.34.03 2.43-.07 3.25-.3.83-.23 1.72-.6 2.68-1.11l.77 2.44Zm-6.64 1.06c-.7 0-1.23.22-1.62.66-.4.44-.6 1.03-.6 1.76 0 .77.2 1.38.6 1.83.4.45.96.67 1.67.67.73 0 1.3-.22 1.67-.66.39-.44.58-1.06.58-1.86 0-1.6-.77-2.4-2.3-2.4ZM808.6 228.24c0 .16-.03.57-.08 1.25h-7.97c.1 1.23.42 2.1.96 2.64.55.52 1.27.79 2.16.79.56 0 1.1-.1 1.59-.28a7.4 7.4 0 0 0 1.58-.85l1.27 1.75a7.3 7.3 0 0 1-4.7 1.7c-1.94 0-3.43-.59-4.48-1.77-1.04-1.18-1.57-2.8-1.57-4.85 0-1.3.22-2.46.67-3.49a5.2 5.2 0 0 1 4.97-3.3c1.78 0 3.15.56 4.13 1.7.98 1.12 1.46 2.7 1.46 4.7Zm-3.06-.89c0-2.22-.82-3.33-2.47-3.33a2.1 2.1 0 0 0-1.76.82 4.93 4.93 0 0 0-.76 2.65h5v-.14ZM818.12 221.83c1.14 0 2.02.34 2.65 1.02.64.68.95 1.63.95 2.85v9.19h-3.07v-8.71c0-.76-.13-1.28-.4-1.59-.26-.3-.65-.45-1.16-.45-.53 0-1 .16-1.43.49-.42.33-.83.8-1.23 1.43v8.83h-3.08v-12.7h2.67l.24 1.66a4.72 4.72 0 0 1 3.86-2.02ZM835.71 228.24c0 .16-.02.57-.07 1.25h-7.97c.1 1.23.42 2.1.96 2.64.55.52 1.27.79 2.16.79.56 0 1.1-.1 1.59-.28a7.4 7.4 0 0 0 1.58-.85l1.27 1.75a7.3 7.3 0 0 1-4.7 1.7c-1.94 0-3.43-.59-4.48-1.77-1.04-1.18-1.57-2.8-1.57-4.85 0-1.3.22-2.46.67-3.49a5.2 5.2 0 0 1 4.97-3.3c1.78 0 3.15.56 4.13 1.7.98 1.12 1.46 2.7 1.46 4.7Zm-3.05-.89c0-2.22-.82-3.33-2.47-3.33a2.1 2.1 0 0 0-1.76.82 4.93 4.93 0 0 0-.76 2.65h5v-.14ZM842.48 221.83c1.71 0 3.22.5 4.51 1.51l-1.2 1.8a5.96 5.96 0 0 0-3.19-1.03c-.6 0-1.08.12-1.42.35-.33.23-.5.54-.5.92 0 .3.07.53.22.72.14.2.4.38.78.54.37.17.93.36 1.66.57 1.38.36 2.4.85 3.06 1.46.67.6 1 1.46 1 2.55 0 1.26-.51 2.25-1.54 2.96a6.52 6.52 0 0 1-3.81 1.07 8.07 8.07 0 0 1-2.85-.48 6.9 6.9 0 0 1-2.22-1.32l1.54-1.73a5.67 5.67 0 0 0 3.46 1.25c.68 0 1.23-.14 1.64-.41.4-.27.61-.65.61-1.13 0-.37-.07-.66-.23-.87-.15-.22-.42-.41-.81-.58-.4-.17-1-.37-1.84-.61a6.13 6.13 0 0 1-2.85-1.48 3.28 3.28 0 0 1-.92-2.36c0-.7.2-1.34.62-1.9.4-.56.98-1 1.72-1.32.75-.32 1.6-.48 2.56-.48ZM852.97 222.2v12.69h-3.07v-12.7h3.07Zm-1.56-6.44c.58 0 1.04.18 1.4.54.36.36.54.8.54 1.33s-.18.97-.54 1.32c-.36.35-.82.53-1.4.53a1.9 1.9 0 0 1-1.38-.53c-.36-.35-.54-.8-.54-1.32 0-.53.18-.97.54-1.33.36-.36.82-.54 1.38-.54ZM860.67 221.83c1.72 0 3.22.5 4.52 1.51l-1.2 1.8a5.96 5.96 0 0 0-3.2-1.03c-.6 0-1.08.12-1.41.35-.34.23-.5.54-.5.92 0 .3.06.53.2.72.15.2.41.38.79.54.37.17.93.36 1.67.57 1.37.36 2.4.85 3.06 1.46.66.6 1 1.46 1 2.55 0 1.26-.52 2.25-1.54 2.96a6.52 6.52 0 0 1-3.82 1.07 8.07 8.07 0 0 1-2.84-.48 6.9 6.9 0 0 1-2.22-1.32l1.53-1.73a5.67 5.67 0 0 0 3.46 1.25c.69 0 1.23-.14 1.64-.41.41-.27.61-.65.61-1.13 0-.37-.07-.66-.22-.87-.16-.22-.43-.41-.82-.58-.4-.17-1-.37-1.84-.61a6.13 6.13 0 0 1-2.85-1.48 3.28 3.28 0 0 1-.91-2.36c0-.7.2-1.34.6-1.9.42-.56 1-1 1.74-1.32.74-.32 1.6-.48 2.55-.48ZM881.36 234.29c-.45.32-.95.56-1.5.72-.55.16-1.12.24-1.7.24-1.24-.02-2.19-.37-2.83-1.07-.65-.7-.98-1.73-.98-3.09v-6.7h-1.99v-2.2h2v-2.8l3.06-.37v3.17h2.96l-.32 2.2h-2.64v6.63c0 .63.11 1.07.33 1.35.21.27.55.4 1.02.4.46 0 .97-.15 1.51-.45l1.08 1.97ZM889.35 221.85c.47 0 .9.06 1.27.17l-.52 2.98c-.39-.1-.76-.15-1.13-.15-.75 0-1.35.27-1.78.8a6.18 6.18 0 0 0-1.03 2.47v6.77h-3.07v-12.7h2.66l.3 2.5c.3-.91.73-1.61 1.31-2.1a3 3 0 0 1 2-.73ZM901.09 231.53c0 .5.08.86.23 1.09.15.23.4.41.73.54l-.65 2.04a3.93 3.93 0 0 1-1.76-.53 2.7 2.7 0 0 1-1.05-1.32 4.07 4.07 0 0 1-1.62 1.43c-.65.31-1.37.47-2.17.47a4.1 4.1 0 0 1-3-1.08 3.78 3.78 0 0 1-1.1-2.84c0-1.37.5-2.42 1.5-3.15s2.42-1.1 4.28-1.1h1.58v-.71c0-.82-.18-1.4-.56-1.72-.38-.33-.98-.5-1.81-.5-.93 0-2.05.23-3.36.68l-.72-2.09c1.58-.6 3.12-.9 4.6-.9 3.25 0 4.88 1.45 4.88 4.36v5.33Zm-5.47 1.48c1.04 0 1.85-.52 2.45-1.56v-2.56h-1.28c-1.98 0-2.97.73-2.97 2.2 0 .61.15 1.08.45 1.42.3.34.76.5 1.35.5ZM911.58 221.83c1.13 0 2.02.34 2.65 1.02.63.68.95 1.63.95 2.85v9.19h-3.07v-8.71c0-.76-.14-1.28-.4-1.59-.26-.3-.65-.45-1.16-.45-.53 0-1 .16-1.43.49-.43.33-.84.8-1.24 1.43v8.83h-3.07v-12.7h2.66l.24 1.66a4.72 4.72 0 0 1 3.87-2.02ZM922.76 221.83c1.71 0 3.22.5 4.51 1.51l-1.2 1.8a5.96 5.96 0 0 0-3.19-1.03c-.6 0-1.08.12-1.42.35-.33.23-.5.54-.5.92 0 .3.07.53.22.72.14.2.4.38.78.54.37.17.93.36 1.66.57 1.38.36 2.4.85 3.06 1.46.67.6 1 1.46 1 2.55 0 1.26-.51 2.25-1.54 2.96a6.52 6.52 0 0 1-3.81 1.07 8.07 8.07 0 0 1-2.85-.48 6.9 6.9 0 0 1-2.22-1.32l1.54-1.73a5.67 5.67 0 0 0 3.46 1.25c.68 0 1.23-.14 1.64-.41.4-.27.61-.65.61-1.13 0-.37-.07-.66-.23-.87-.15-.22-.42-.41-.81-.58-.4-.17-1-.37-1.84-.61a6.13 6.13 0 0 1-2.85-1.48 3.28 3.28 0 0 1-.92-2.36c0-.7.2-1.34.62-1.9.4-.56.98-1 1.72-1.32.75-.32 1.6-.48 2.56-.48ZM939.32 231.53c0 .5.08.86.23 1.09.15.23.4.41.73.54l-.65 2.04a3.93 3.93 0 0 1-1.76-.53 2.7 2.7 0 0 1-1.05-1.32 4.07 4.07 0 0 1-1.62 1.43c-.64.31-1.37.47-2.17.47a4.1 4.1 0 0 1-3-1.08 3.78 3.78 0 0 1-1.1-2.84c0-1.37.5-2.42 1.5-3.15s2.43-1.1 4.28-1.1h1.59v-.71c0-.82-.2-1.4-.57-1.72-.37-.33-.98-.5-1.8-.5-.94 0-2.06.23-3.37.68l-.72-2.09c1.58-.6 3.12-.9 4.6-.9 3.26 0 4.88 1.45 4.88 4.36v5.33Zm-5.47 1.48c1.04 0 1.86-.52 2.45-1.56v-2.56h-1.27c-1.99 0-2.98.73-2.98 2.2 0 .61.15 1.08.46 1.42.3.34.75.5 1.34.5ZM948.15 221.83a6 6 0 0 1 4.13 1.49l-1.37 1.85a3.87 3.87 0 0 0-2.57-.91c-1.9 0-2.85 1.44-2.85 4.34 0 1.47.25 2.53.74 3.18.5.65 1.2.97 2.11.97.45 0 .86-.07 1.24-.21.38-.15.82-.38 1.33-.7l1.37 1.94a6.33 6.33 0 0 1-4.1 1.47 6.05 6.05 0 0 1-3.17-.8 5.28 5.28 0 0 1-2.07-2.3c-.48-1-.72-2.16-.72-3.5 0-1.35.24-2.54.72-3.57a5.52 5.52 0 0 1 2.07-2.4c.9-.57 1.94-.85 3.14-.85ZM961.78 234.29c-.44.32-.94.56-1.5.72-.55.16-1.11.24-1.69.24-1.25-.02-2.2-.37-2.84-1.07-.65-.7-.97-1.73-.97-3.09v-6.7h-2v-2.2h2v-2.8l3.07-.37v3.17h2.95l-.31 2.2h-2.64v6.63c0 .63.1 1.07.32 1.35.22.27.56.4 1.02.4.47 0 .97-.15 1.51-.45l1.08 1.97ZM966.59 222.2v12.69h-3.08v-12.7h3.08Zm-1.56-6.44c.57 0 1.04.18 1.4.54.36.36.54.8.54 1.33s-.18.97-.54 1.32c-.36.35-.83.53-1.4.53a1.9 1.9 0 0 1-1.38-.53c-.36-.35-.54-.8-.54-1.32 0-.53.18-.97.54-1.33.36-.36.82-.54 1.38-.54ZM975.47 221.83c1.87 0 3.33.6 4.38 1.79 1.04 1.2 1.57 2.83 1.57 4.9 0 1.33-.24 2.5-.72 3.52a5.47 5.47 0 0 1-5.26 3.2c-1.87 0-3.34-.59-4.4-1.78-1.05-1.2-1.57-2.84-1.57-4.93 0-1.33.24-2.5.72-3.5.48-1.02 1.17-1.8 2.07-2.36.9-.56 1.97-.84 3.2-.84Zm0 2.33c-1.84 0-2.76 1.45-2.76 4.37 0 1.5.22 2.6.68 3.32a2.28 2.28 0 0 0 2.05 1.07c.91 0 1.6-.36 2.05-1.08.46-.72.69-1.83.69-3.31 0-1.5-.23-2.6-.69-3.3a2.25 2.25 0 0 0-2.02-1.07ZM991.07 221.83c1.13 0 2.02.34 2.65 1.02.63.68.95 1.63.95 2.85v9.19h-3.08v-8.71c0-.76-.13-1.28-.4-1.59-.26-.3-.64-.45-1.16-.45-.52 0-1 .16-1.42.49-.43.33-.84.8-1.24 1.43v8.83h-3.07v-12.7h2.66l.24 1.66a4.72 4.72 0 0 1 3.87-2.02ZM1009.38 219.1c-.6 0-1.04.14-1.3.42-.27.27-.4.72-.4 1.33v1.34h3.04l-.33 2.2h-2.71v10.5h-3.08v-10.5h-2.06v-2.2h2.06v-1.4c0-1.2.4-2.16 1.17-2.9.77-.75 1.87-1.12 3.3-1.12 1.12 0 2.21.24 3.29.74l-.9 2.06a4.9 4.9 0 0 0-2.08-.48ZM1017.51 221.83c1.87 0 3.33.6 4.38 1.79 1.05 1.2 1.57 2.83 1.57 4.9 0 1.33-.24 2.5-.72 3.52a5.47 5.47 0 0 1-5.25 3.2c-1.88 0-3.34-.59-4.4-1.78-1.05-1.2-1.58-2.84-1.58-4.93 0-1.33.24-2.5.72-3.5.48-1.02 1.17-1.8 2.08-2.36.9-.56 1.97-.84 3.2-.84Zm0 2.33c-1.84 0-2.76 1.45-2.76 4.37 0 1.5.23 2.6.68 3.32a2.28 2.28 0 0 0 2.06 1.07c.9 0 1.6-.36 2.05-1.08.45-.72.68-1.83.68-3.31 0-1.5-.23-2.6-.68-3.3a2.25 2.25 0 0 0-2.03-1.07ZM1032.61 221.85c.46 0 .89.06 1.27.17l-.53 2.98c-.38-.1-.76-.15-1.12-.15-.76 0-1.35.27-1.78.8a6.18 6.18 0 0 0-1.03 2.47v6.77h-3.07v-12.7h2.66l.29 2.5c.3-.91.74-1.61 1.32-2.1a3 3 0 0 1 1.99-.73ZM1081.18 231.53c0 .5.08.86.23 1.09.15.23.4.41.73.54l-.65 2.04a3.93 3.93 0 0 1-1.76-.53 2.7 2.7 0 0 1-1.05-1.32 4.07 4.07 0 0 1-1.62 1.43c-.64.31-1.37.47-2.17.47a4.1 4.1 0 0 1-3-1.08 3.78 3.78 0 0 1-1.1-2.84c0-1.37.5-2.42 1.5-3.15s2.43-1.1 4.28-1.1h1.59v-.71c0-.82-.2-1.4-.57-1.72-.37-.33-.98-.5-1.81-.5-.93 0-2.05.23-3.36.68l-.72-2.09c1.58-.6 3.12-.9 4.6-.9 3.26 0 4.88 1.45 4.88 4.36v5.33Zm-5.47 1.48c1.04 0 1.85-.52 2.45-1.56v-2.56h-1.28c-1.98 0-2.97.73-2.97 2.2 0 .61.15 1.08.45 1.42.3.34.76.5 1.35.5ZM1091.67 221.83c1.14 0 2.02.34 2.65 1.02.63.68.95 1.63.95 2.85v9.19h-3.07v-8.71c0-.76-.13-1.28-.4-1.59-.26-.3-.65-.45-1.16-.45-.53 0-1 .16-1.43.49-.42.33-.84.8-1.24 1.43v8.83h-3.07v-12.7h2.67l.24 1.66a4.72 4.72 0 0 1 3.86-2.02ZM1109.53 217.1v17.79h-2.71l-.22-1.61a4.16 4.16 0 0 1-3.62 1.97c-1.55 0-2.75-.6-3.58-1.8-.83-1.2-1.25-2.84-1.25-4.9 0-1.3.21-2.45.63-3.47a5.47 5.47 0 0 1 1.79-2.39 4.4 4.4 0 0 1 2.7-.86c1.21 0 2.28.46 3.19 1.37v-6.43l3.07.33Zm-5.69 15.82c.55 0 1.03-.13 1.44-.4.42-.26.81-.67 1.18-1.23v-5.81a4.4 4.4 0 0 0-1.12-1 2.5 2.5 0 0 0-1.3-.34 2.2 2.2 0 0 0-1.94 1.09c-.47.73-.7 1.83-.7 3.3 0 1.57.2 2.69.62 3.37a2.01 2.01 0 0 0 1.82 1.02Z" style="fill:#073b4c;fill-rule:nonzero"/><path d="M1123.17 219.94h16v16h-16z" style="fill:#8a11b2"/><path d="m1053.17 217.94 9 18h-18l9-18Z" style="fill:#3ab211"/></g><g><path d="M523.82 549.14c1.72 0 3.06.69 4.03 2.06.97 1.37 1.46 3.3 1.46 5.75 0 1.53-.24 2.9-.71 4.08a6.34 6.34 0 0 1-2.03 2.77c-.88.66-1.92 1-3.11 1a4.79 4.79 0 0 1-3.92-1.94l-.22 1.52h-3.17v-20.75l3.59-.4v8.01a4.93 4.93 0 0 1 4.09-2.1Zm-1.34 12.97c.97 0 1.72-.42 2.27-1.25.54-.83.8-2.13.8-3.9 0-1.87-.24-3.2-.75-3.97a2.4 2.4 0 0 0-2.12-1.16c-1.14 0-2.12.67-2.94 2.02v6.55c.31.54.7.96 1.18 1.26.48.3 1 .45 1.56.45ZM536.65 545.2c1.27 0 2.36.23 3.29.7.92.46 1.62 1.1 2.11 1.9.49.8.73 1.7.73 2.69 0 1.06-.23 2.08-.69 3.06-.46.98-1.22 2.07-2.28 3.27a87.66 87.66 0 0 1-4.68 4.73h8.07l-.4 2.83h-11.73v-2.64c2.4-2.42 4.1-4.22 5.14-5.39a16.3 16.3 0 0 0 2.21-3c.44-.82.66-1.69.66-2.58a2.7 2.7 0 0 0-.74-2.02 2.7 2.7 0 0 0-1.97-.73c-.73 0-1.37.16-1.92.47-.55.3-1.13.81-1.72 1.52l-2.19-1.73a7.38 7.38 0 0 1 6.1-3.08ZM552.33 545.2c2.2 0 3.87.84 5.02 2.52 1.15 1.68 1.72 4.1 1.72 7.25 0 3.17-.57 5.6-1.72 7.3a5.7 5.7 0 0 1-5.02 2.52 5.7 5.7 0 0 1-5.03-2.53c-1.15-1.69-1.72-4.12-1.72-7.3 0-3.15.57-5.57 1.72-7.25a5.7 5.7 0 0 1 5.03-2.52Zm0 2.71c-1.07 0-1.84.54-2.33 1.61-.48 1.07-.72 2.89-.72 5.45 0 2.57.24 4.4.72 5.49.49 1.08 1.26 1.62 2.33 1.62 1.06 0 1.83-.54 2.32-1.61.49-1.07.73-2.9.73-5.5 0-2.58-.24-4.4-.73-5.46-.49-1.07-1.26-1.6-2.32-1.6ZM569.66 545.53v18.84h-3.53v-15.23l-4.2 2.55-1.57-2.4 6.13-3.76h3.17ZM585.42 560.46c0 .57.1 1 .27 1.27.18.27.46.48.85.63l-.75 2.38a4.58 4.58 0 0 1-2.06-.62 3.15 3.15 0 0 1-1.22-1.54c-.5.75-1.13 1.3-1.89 1.67-.75.36-1.6.55-2.53.55a4.79 4.79 0 0 1-3.5-1.26 4.41 4.41 0 0 1-1.3-3.3c0-1.61.6-2.84 1.76-3.7 1.17-.84 2.83-1.26 5-1.26h1.85v-.84c0-.96-.22-1.62-.66-2-.44-.39-1.15-.58-2.12-.58-1.08 0-2.39.26-3.92.78l-.84-2.43a14.95 14.95 0 0 1 5.38-1.07c3.79 0 5.68 1.7 5.68 5.1v6.22Zm-6.38 1.73c1.21 0 2.16-.6 2.86-1.82v-3h-1.49c-2.31 0-3.47.86-3.47 2.58 0 .71.18 1.26.53 1.65.35.4.88.6 1.57.6ZM595.62 545.2c2.2 0 3.87.84 5.02 2.52 1.15 1.68 1.72 4.1 1.72 7.25 0 3.17-.57 5.6-1.72 7.3a5.7 5.7 0 0 1-5.03 2.52 5.7 5.7 0 0 1-5.02-2.53c-1.15-1.69-1.72-4.12-1.72-7.3 0-3.15.57-5.57 1.72-7.25a5.7 5.7 0 0 1 5.03-2.52Zm0 2.71c-1.07 0-1.84.54-2.33 1.61-.48 1.07-.73 2.89-.73 5.45 0 2.57.25 4.4.73 5.49.49 1.08 1.26 1.62 2.33 1.62 1.06 0 1.83-.54 2.32-1.61.48-1.07.73-2.9.73-5.5 0-2.58-.25-4.4-.73-5.46-.49-1.07-1.26-1.6-2.33-1.6ZM606.98 560.26c.64 0 1.18.22 1.63.66.44.44.67.97.67 1.6 0 .62-.22 1.16-.67 1.6-.45.45-1 .68-1.63.68-.61 0-1.14-.23-1.58-.68a2.2 2.2 0 0 1-.66-1.6 2.21 2.21 0 0 1 2.24-2.26ZM613.7 560.26c.64 0 1.18.22 1.63.66.44.44.67.97.67 1.6 0 .62-.22 1.16-.67 1.6-.45.45-1 .68-1.63.68-.61 0-1.14-.23-1.58-.68a2.2 2.2 0 0 1-.66-1.6 2.21 2.21 0 0 1 2.24-2.26ZM620.42 560.26c.64 0 1.18.22 1.63.66.45.44.67.97.67 1.6 0 .62-.22 1.16-.67 1.6-.45.45-1 .68-1.63.68-.61 0-1.14-.23-1.58-.68a2.2 2.2 0 0 1-.66-1.6 2.21 2.21 0 0 1 2.24-2.26Z" style="fill:#8a11b2;fill-rule:nonzero"/><path d="M486.09 544.99h19.66v19.66h-19.66z" style="fill:#8a11b2"/></g><g><path d="M407.21 860.2c1.3 0 2.3.52 3.03 1.55s1.1 2.47 1.1 4.32c0 1.15-.19 2.17-.54 3.06a4.76 4.76 0 0 1-1.53 2.09c-.66.5-1.43.74-2.33.74a3.6 3.6 0 0 1-2.95-1.45l-.17 1.14h-2.37v-15.59l2.69-.3v6.02a3.71 3.71 0 0 1 3.07-1.58Zm-1 9.74c.72 0 1.29-.3 1.7-.93.4-.63.6-1.6.6-2.94 0-1.4-.18-2.4-.56-2.97a1.8 1.8 0 0 0-1.6-.88c-.86 0-1.6.5-2.21 1.52v4.92c.24.4.54.72.9.95.35.22.74.33 1.16.33ZM416.84 857.24c.96 0 1.78.18 2.48.53.69.35 1.22.82 1.58 1.43.37.6.55 1.27.55 2.01 0 .8-.17 1.57-.52 2.3a10.6 10.6 0 0 1-1.71 2.46c-.8.9-1.97 2.08-3.51 3.55h6.06l-.3 2.13h-8.81v-1.98c1.8-1.82 3.08-3.17 3.86-4.05.78-.88 1.33-1.63 1.66-2.25.33-.62.5-1.27.5-1.95 0-.64-.2-1.15-.56-1.5a2.03 2.03 0 0 0-1.49-.56 2.9 2.9 0 0 0-1.44.35 4.9 4.9 0 0 0-1.3 1.15l-1.63-1.3a5.55 5.55 0 0 1 4.58-2.32ZM428.62 857.24c1.66 0 2.91.63 3.78 1.9.86 1.25 1.29 3.07 1.29 5.44 0 2.38-.43 4.21-1.3 5.48a4.28 4.28 0 0 1-3.77 1.9 4.28 4.28 0 0 1-3.77-1.9c-.87-1.27-1.3-3.1-1.3-5.48 0-2.37.43-4.19 1.3-5.45a4.28 4.28 0 0 1 3.77-1.9Zm0 2.04c-.8 0-1.38.4-1.74 1.2-.37.82-.55 2.18-.55 4.1 0 1.94.18 3.3.55 4.12.36.81.94 1.22 1.74 1.22s1.38-.4 1.75-1.2c.36-.81.54-2.2.54-4.14 0-1.94-.18-3.3-.54-4.1-.37-.8-.95-1.2-1.75-1.2ZM441.64 857.5v14.15h-2.65V860.2l-3.15 1.92-1.18-1.81 4.6-2.82h2.38ZM453.48 868.7c0 .44.07.76.2.96.13.2.35.36.64.47l-.56 1.79a3.43 3.43 0 0 1-1.55-.46c-.4-.26-.7-.64-.92-1.16-.38.56-.85.98-1.42 1.25-.56.27-1.2.41-1.9.41a3.6 3.6 0 0 1-2.63-.95 3.31 3.31 0 0 1-.97-2.48c0-1.2.44-2.12 1.32-2.76.87-.64 2.13-.96 3.75-.96h1.4v-.63c0-.71-.17-1.22-.5-1.5-.33-.3-.86-.44-1.6-.44-.8 0-1.79.2-2.94.6l-.63-1.84c1.4-.53 2.74-.8 4.04-.8 2.85 0 4.27 1.28 4.27 3.83v4.67Zm-4.8 1.3c.92 0 1.63-.45 2.15-1.36v-2.25h-1.11c-1.74 0-2.61.64-2.61 1.93 0 .54.13.95.4 1.24.26.3.66.45 1.18.45ZM461.14 857.24c1.65 0 2.91.63 3.77 1.9.86 1.25 1.3 3.07 1.3 5.44 0 2.38-.44 4.21-1.3 5.48a4.28 4.28 0 0 1-3.77 1.9 4.28 4.28 0 0 1-3.78-1.9c-.86-1.27-1.3-3.1-1.3-5.48 0-2.37.44-4.19 1.3-5.45a4.28 4.28 0 0 1 3.78-1.9Zm0 2.04c-.8 0-1.38.4-1.75 1.2-.36.82-.55 2.18-.55 4.1 0 1.94.19 3.3.55 4.12.37.81.95 1.22 1.75 1.22s1.38-.4 1.74-1.2c.37-.81.55-2.2.55-4.14 0-1.94-.18-3.3-.55-4.1-.36-.8-.94-1.2-1.74-1.2ZM469.68 868.55c.47 0 .88.17 1.22.5.33.33.5.73.5 1.2s-.17.87-.5 1.2c-.34.34-.75.51-1.22.51a1.6 1.6 0 0 1-1.2-.5c-.32-.34-.49-.74-.49-1.2a1.66 1.66 0 0 1 1.69-1.7ZM474.72 868.55c.48 0 .89.17 1.22.5.34.33.5.73.5 1.2s-.16.87-.5 1.2c-.33.34-.74.51-1.22.51a1.6 1.6 0 0 1-1.19-.5c-.32-.34-.49-.74-.49-1.2a1.66 1.66 0 0 1 1.68-1.7ZM479.77 868.55c.48 0 .89.17 1.22.5.34.33.5.73.5 1.2s-.16.87-.5 1.2c-.33.34-.74.51-1.22.51a1.6 1.6 0 0 1-1.19-.5c-.33-.34-.5-.74-.5-1.2a1.66 1.66 0 0 1 1.7-1.7Z" style="fill:#8a11b2;fill-rule:nonzero"/><path d="M378.87 857.09h14.77v14.77h-14.77z" style="fill:#8a11b2"/><path d="M674.46 857.1v13.46h-2.52V859.7l-3 1.82-1.12-1.72 4.38-2.68h2.26ZM685.14 859h-5.04v3.34a4.5 4.5 0 0 1 2.04-.5c.75 0 1.41.18 2 .52a3.5 3.5 0 0 1 1.37 1.5c.33.66.5 1.43.5 2.32 0 .93-.22 1.74-.63 2.45-.41.7-1 1.25-1.76 1.65-.76.39-1.64.59-2.64.59a5.47 5.47 0 0 1-4.24-1.9l1.46-1.36a3.57 3.57 0 0 0 2.72 1.28c.76 0 1.36-.24 1.8-.7.42-.47.64-1.14.64-2 0-1.67-.72-2.5-2.16-2.5-.3 0-.6.03-.86.1a4.9 4.9 0 0 0-.88.36h-1.82v-7.04h7.8l-.3 1.9ZM692.48 856.87c1.57 0 2.77.6 3.6 1.8.81 1.2 1.22 2.92 1.22 5.18s-.4 4-1.23 5.2a4.07 4.07 0 0 1-3.59 1.81c-1.57 0-2.77-.6-3.59-1.8-.82-1.21-1.23-2.95-1.23-5.21s.41-3.99 1.23-5.19a4.07 4.07 0 0 1 3.6-1.8Zm0 1.94c-.76 0-1.31.38-1.66 1.15-.35.76-.52 2.06-.52 3.89 0 1.84.18 3.14.52 3.92.35.77.9 1.16 1.66 1.16.76 0 1.31-.39 1.66-1.15.35-.77.52-2.08.52-3.93 0-1.84-.17-3.14-.52-3.9-.35-.76-.9-1.14-1.66-1.14ZM978.21 870.63h-3.42l-4.74-11.18a38.96 38.96 0 0 1 .36 5.54v5.64h-2.4V856.8h3.34l4.82 11.2a38.69 38.69 0 0 1-.36-4.73v-6.48h2.4v13.82ZM985.69 859.75c1.56 0 2.78.5 3.65 1.49.87.99 1.31 2.35 1.31 4.09 0 1.1-.2 2.08-.6 2.93a4.56 4.56 0 0 1-4.38 2.67c-1.56 0-2.78-.5-3.66-1.5-.88-.99-1.32-2.36-1.32-4.1 0-1.11.2-2.08.6-2.92.4-.84.98-1.5 1.73-1.96.75-.47 1.64-.7 2.67-.7Zm0 1.94c-1.53 0-2.3 1.2-2.3 3.64 0 1.25.19 2.17.57 2.77.38.59.95.89 1.71.89s1.33-.3 1.71-.9c.38-.6.57-1.52.57-2.76a5.2 5.2 0 0 0-.57-2.75c-.38-.6-.94-.9-1.69-.9ZM998.69 859.75c.95 0 1.68.28 2.21.85.53.56.79 1.35.79 2.37v7.66h-2.56v-7.26c0-.63-.11-1.07-.33-1.32-.22-.26-.54-.38-.97-.38-.44 0-.84.13-1.19.4-.35.28-.7.67-1.03 1.2v7.36h-2.56v-10.58h2.22l.2 1.38a3.93 3.93 0 0 1 3.22-1.68ZM1013.35 865.09l-.06 1.04h-6.64c.08 1.02.35 1.76.8 2.2.45.44 1.05.66 1.8.66.47 0 .9-.08 1.32-.23a6.2 6.2 0 0 0 1.32-.71l1.06 1.46a6.1 6.1 0 0 1-3.92 1.42c-1.61 0-2.86-.5-3.73-1.48a5.88 5.88 0 0 1-1.31-4.05c0-1.08.19-2.05.56-2.9a4.33 4.33 0 0 1 4.14-2.75 4.3 4.3 0 0 1 3.44 1.4c.81.94 1.22 2.25 1.22 3.93Zm-2.54-.74c0-1.86-.69-2.78-2.06-2.78-.63 0-1.12.23-1.47.69-.35.46-.56 1.2-.63 2.2h4.16v-.11Z" style="fill:#073b4c;fill-rule:nonzero"/></g><g><path d="M531.88 300.88c0 .57.09 1 .26 1.27.18.27.46.48.86.63l-.76 2.38a4.58 4.58 0 0 1-2.06-.62 3.15 3.15 0 0 1-1.21-1.54c-.5.75-1.14 1.3-1.9 1.67-.75.36-1.6.55-2.53.55a4.8 4.8 0 0 1-3.5-1.26 4.42 4.42 0 0 1-1.29-3.3c0-1.61.59-2.84 1.75-3.69 1.17-.85 2.84-1.27 5-1.27h1.85v-.84c0-.96-.22-1.62-.66-2-.44-.39-1.14-.58-2.11-.58-1.09 0-2.4.26-3.92.78l-.84-2.43a14.95 14.95 0 0 1 5.37-1.07c3.8 0 5.69 1.7 5.69 5.1v6.22Zm-6.39 1.73c1.22 0 2.17-.6 2.86-1.82v-3h-1.49c-2.3 0-3.47.86-3.47 2.58 0 .71.18 1.26.53 1.65.36.4.88.6 1.57.6ZM542.6 285.95v18.85h-3.53v-15.24l-4.2 2.55-1.57-2.4 6.14-3.76h3.16ZM559.57 297.04c0 .19-.03.67-.09 1.46h-9.3c.12 1.43.5 2.46 1.13 3.08.63.61 1.47.92 2.52.92.65 0 1.27-.1 1.85-.32.58-.22 1.2-.55 1.84-1l1.49 2.05a8.53 8.53 0 0 1-5.49 1.99c-2.26 0-4-.7-5.22-2.08-1.22-1.38-1.84-3.26-1.84-5.65 0-1.51.27-2.87.79-4.08a6.06 6.06 0 0 1 5.8-3.85c2.07 0 3.67.66 4.81 1.98 1.14 1.31 1.7 3.15 1.7 5.5ZM556 296c0-2.6-.96-3.89-2.88-3.89-.88 0-1.56.32-2.06.97-.5.64-.79 1.67-.88 3.1H556V296ZM568.78 286.37c-.7 0-1.22.17-1.53.5-.3.32-.46.84-.46 1.55v1.56h3.56l-.4 2.58h-3.16v12.24h-3.58v-12.24h-2.4v-2.58h2.4v-1.62c0-1.4.45-2.53 1.36-3.4.9-.87 2.19-1.3 3.85-1.3 1.3 0 2.58.28 3.83.86l-1.03 2.41a5.71 5.71 0 0 0-2.44-.56ZM578.19 289.56a6.97 6.97 0 0 1 4.82 1.74l-1.6 2.16a4.51 4.51 0 0 0-3-1.06c-2.22 0-3.33 1.68-3.33 5.06 0 1.72.3 2.95.87 3.71.58.76 1.4 1.13 2.46 1.13a4 4 0 0 0 1.45-.25c.43-.17.95-.44 1.55-.81l1.6 2.27c-1.4 1.14-3 1.7-4.8 1.7a7.07 7.07 0 0 1-3.69-.93 6.16 6.16 0 0 1-2.4-2.68 9.3 9.3 0 0 1-.85-4.08c0-1.57.28-2.96.84-4.16a6.44 6.44 0 0 1 2.41-2.8 6.7 6.7 0 0 1 3.67-1ZM597.5 284.05v20.75h-3.15l-.26-1.88a4.85 4.85 0 0 1-4.23 2.3c-1.8 0-3.2-.7-4.17-2.1-.97-1.4-1.45-3.3-1.45-5.72 0-1.5.24-2.86.72-4.04a6.39 6.39 0 0 1 2.1-2.79c.9-.67 1.95-1 3.14-1a5.1 5.1 0 0 1 3.72 1.59v-7.5l3.59.39Zm-6.63 18.45c.64 0 1.2-.15 1.68-.46.49-.31.95-.8 1.38-1.44v-6.78a5.11 5.11 0 0 0-1.3-1.18c-.45-.26-.95-.39-1.53-.39-.96 0-1.7.43-2.26 1.28-.55.85-.82 2.13-.82 3.85 0 1.83.24 3.14.72 3.93.5.8 1.2 1.19 2.13 1.19ZM603 300.68c.63 0 1.17.22 1.62.66.45.44.67.97.67 1.6 0 .62-.22 1.16-.67 1.6-.45.45-.99.68-1.62.68-.62 0-1.15-.23-1.59-.68a2.2 2.2 0 0 1-.65-1.6 2.21 2.21 0 0 1 2.24-2.26ZM609.72 300.68c.63 0 1.17.22 1.62.66.45.44.67.97.67 1.6 0 .62-.22 1.16-.67 1.6-.45.45-.99.68-1.62.68-.62 0-1.15-.23-1.59-.68a2.2 2.2 0 0 1-.65-1.6 2.21 2.21 0 0 1 2.24-2.26ZM616.44 300.68c.63 0 1.17.22 1.62.66.45.44.67.97.67 1.6 0 .62-.22 1.16-.67 1.6-.45.45-.99.68-1.62.68-.62 0-1.15-.23-1.59-.68a2.2 2.2 0 0 1-.65-1.6 2.21 2.21 0 0 1 2.24-2.26Z" style="fill:#3ab211;fill-rule:nonzero"/><path d="m500.7 283.8 10.55 21.08h-21.1l10.55-21.08Z" style="fill:#3ab211"/></g><g><path d="M411.5 929.21c0 .44.08.76.2.96.14.2.36.36.65.47l-.57 1.79a3.44 3.44 0 0 1-1.54-.46c-.4-.25-.7-.64-.92-1.16-.38.56-.85.98-1.42 1.25-.57.28-1.2.41-1.9.41a3.6 3.6 0 0 1-2.63-.94 3.32 3.32 0 0 1-.97-2.49c0-1.2.44-2.12 1.32-2.76.87-.64 2.12-.96 3.75-.96h1.39v-.63c0-.71-.17-1.22-.5-1.5-.33-.3-.85-.43-1.58-.43-.82 0-1.8.2-2.95.58l-.63-1.83c1.39-.53 2.74-.8 4.04-.8 2.85 0 4.27 1.28 4.27 3.83v4.67Zm-4.79 1.3c.92 0 1.63-.45 2.15-1.36v-2.25h-1.12c-1.73 0-2.6.64-2.6 1.93 0 .54.13.95.4 1.24.26.3.65.45 1.17.45ZM419.56 918v14.16h-2.65V920.7l-3.15 1.92-1.18-1.8 4.6-2.83h2.38ZM432.31 926.33l-.06 1.1h-6.99c.09 1.07.37 1.85.85 2.3.47.47 1.1.7 1.89.7.49 0 .95-.08 1.39-.24.43-.16.9-.41 1.38-.75l1.12 1.54a6.4 6.4 0 0 1-4.12 1.5c-1.7 0-3-.53-3.93-1.56-.91-1.04-1.37-2.46-1.37-4.25 0-1.14.2-2.16.59-3.06.39-.9.96-1.61 1.7-2.13a4.56 4.56 0 0 1 2.65-.76c1.56 0 2.76.49 3.62 1.48.85.99 1.28 2.36 1.28 4.13Zm-2.67-.78c0-1.95-.72-2.92-2.17-2.92-.66 0-1.17.24-1.54.73-.37.48-.6 1.25-.67 2.32h4.38v-.13ZM439.23 918.32c-.53 0-.92.12-1.15.37-.23.24-.34.63-.34 1.16v1.18h2.67l-.3 1.94h-2.37v9.19h-2.7v-9.2h-1.8v-1.93h1.8v-1.22c0-1.05.34-1.9 1.02-2.55.68-.66 1.65-.98 2.9-.98.98 0 1.94.22 2.88.65l-.78 1.8a4.3 4.3 0 0 0-1.83-.41ZM446.3 920.72a5.26 5.26 0 0 1 3.62 1.3l-1.2 1.62a3.4 3.4 0 0 0-2.25-.8c-1.67 0-2.5 1.27-2.5 3.8 0 1.3.2 2.23.64 2.8a2.2 2.2 0 0 0 1.85.85c.4 0 .76-.07 1.09-.2.33-.12.72-.32 1.16-.6l1.2 1.7a5.54 5.54 0 0 1-3.6 1.28c-1.06 0-1.98-.23-2.77-.7a4.63 4.63 0 0 1-1.8-2.01 6.99 6.99 0 0 1-.64-3.07c0-1.18.21-2.22.63-3.12.42-.9 1.03-1.61 1.81-2.1.79-.5 1.7-.75 2.76-.75ZM460.8 916.57v15.59h-2.37l-.19-1.41a3.65 3.65 0 0 1-3.17 1.72c-1.36 0-2.4-.52-3.14-1.58-.73-1.05-1.1-2.48-1.1-4.29 0-1.13.2-2.14.56-3.04.36-.89.88-1.58 1.56-2.09.68-.5 1.47-.76 2.37-.76 1.07 0 2 .4 2.8 1.2v-5.63l2.69.3Zm-4.98 13.86c.48 0 .9-.11 1.27-.34.36-.24.7-.6 1.03-1.09v-5.09c-.33-.39-.65-.68-.98-.88a2.2 2.2 0 0 0-1.15-.3c-.71 0-1.28.32-1.7.96-.4.64-.61 1.6-.61 2.9 0 1.37.18 2.35.54 2.95.37.6.9.9 1.6.9ZM464.93 929.07c.48 0 .88.16 1.22.49.34.33.5.73.5 1.2s-.16.87-.5 1.2c-.34.34-.74.51-1.22.51a1.6 1.6 0 0 1-1.19-.5c-.33-.34-.5-.74-.5-1.2a1.66 1.66 0 0 1 1.7-1.7ZM469.98 929.07c.47 0 .88.16 1.22.49.34.33.5.73.5 1.2s-.16.87-.5 1.2c-.34.34-.74.51-1.22.51a1.6 1.6 0 0 1-1.19-.5c-.33-.34-.5-.74-.5-1.2a1.67 1.67 0 0 1 1.69-1.7ZM475.03 929.07c.47 0 .88.16 1.22.49.33.33.5.73.5 1.2s-.17.87-.5 1.2c-.34.34-.75.51-1.22.51a1.6 1.6 0 0 1-1.2-.5c-.32-.34-.49-.74-.49-1.2a1.67 1.67 0 0 1 1.69-1.7Z" style="fill:#3ab211;fill-rule:nonzero"/><path d="m388.1 916.38 7.91 15.84h-15.84l7.92-15.84Z" style="fill:#3ab211"/><path d="M672.21 917.62v13.46h-2.52V920.2l-3 1.82-1.12-1.72 4.38-2.68h2.26ZM679.83 917.38c1.57 0 2.77.6 3.59 1.8.82 1.2 1.23 2.92 1.23 5.18s-.41 4-1.23 5.2a4.07 4.07 0 0 1-3.59 1.81c-1.57 0-2.77-.6-3.59-1.8-.82-1.21-1.23-2.95-1.23-5.22 0-2.25.41-3.98 1.23-5.18a4.07 4.07 0 0 1 3.59-1.8Zm0 1.94c-.76 0-1.31.38-1.66 1.15-.35.76-.52 2.06-.52 3.89 0 1.84.17 3.14.52 3.92.35.77.9 1.16 1.66 1.16.76 0 1.31-.39 1.66-1.16.35-.76.52-2.07.52-3.93 0-1.84-.17-3.14-.52-3.9-.35-.76-.9-1.14-1.66-1.14ZM691.29 917.38c1.57 0 2.77.6 3.59 1.8.82 1.2 1.23 2.92 1.23 5.18s-.41 4-1.23 5.2a4.07 4.07 0 0 1-3.59 1.81c-1.57 0-2.77-.6-3.59-1.8-.82-1.21-1.23-2.95-1.23-5.22 0-2.25.41-3.98 1.23-5.18a4.07 4.07 0 0 1 3.59-1.8Zm0 1.94c-.76 0-1.31.38-1.66 1.15-.35.76-.52 2.06-.52 3.89 0 1.84.17 3.14.52 3.92.35.77.9 1.16 1.66 1.16.76 0 1.31-.39 1.66-1.16.35-.76.52-2.07.52-3.93 0-1.84-.17-3.14-.52-3.9-.35-.76-.9-1.14-1.66-1.14Z" style="fill:#073b4c;fill-rule:nonzero"/><g><path d="M964.32 924.38c0-7.68-6.24-13.92-13.92-13.92h-68.17a13.92 13.92 0 0 0 0 27.83h68.17c7.68 0 13.92-6.24 13.92-13.91Zm-1.5 0c0-6.86-5.56-12.42-12.42-12.42h-68.17a12.42 12.42 0 0 0 0 24.83h68.17c6.86 0 12.42-5.56 12.42-12.41Z" style="fill:#3ab211"/><path d="M887.08 919.24c1.15 0 2.02.45 2.61 1.33.6.9.89 2.14.89 3.76 0 1.62-.3 2.88-.89 3.77-.6.89-1.46 1.34-2.61 1.34a2.94 2.94 0 0 1-2.61-1.34c-.6-.9-.9-2.15-.9-3.77s.3-2.87.9-3.76a2.94 2.94 0 0 1 2.6-1.33Zm0 1.61c-.5 0-.86.27-1.09.8a7.43 7.43 0 0 0-.34 2.68c0 .8.03 1.46.08 1.96l2.37-4.96a.93.93 0 0 0-.4-.37c-.16-.07-.37-.1-.62-.1Zm0 6.99c.5 0 .85-.27 1.08-.8a7.7 7.7 0 0 0 .33-2.71c0-.52-.01-.97-.04-1.36l-2.23 4.6c.2.18.48.27.86.27ZM897.33 921.57l1.23 1.23-1.9 1.83 1.9 1.87-1.23 1.23-1.85-1.9-1.85 1.9-1.23-1.23 1.89-1.87-1.9-1.83 1.24-1.23 1.85 1.87 1.85-1.87ZM903.88 919.24c1.15 0 2.02.45 2.61 1.33.6.9.89 2.14.89 3.76 0 1.62-.3 2.88-.89 3.77-.6.89-1.46 1.34-2.61 1.34a2.94 2.94 0 0 1-2.61-1.34c-.6-.9-.9-2.15-.9-3.77s.3-2.87.9-3.76a2.94 2.94 0 0 1 2.6-1.33Zm0 1.61c-.5 0-.86.27-1.09.8a7.43 7.43 0 0 0-.34 2.68c0 .8.03 1.46.08 1.96l2.37-4.96a.93.93 0 0 0-.4-.37c-.16-.07-.37-.1-.62-.1Zm0 6.99c.5 0 .85-.27 1.08-.8a7.7 7.7 0 0 0 .33-2.71c0-.52-.01-.97-.04-1.36l-2.23 4.6c.2.18.48.27.86.27ZM913.99 927.52h1.8v1.68h-6.3v-1.68h2.34v-5.85l-2 1.26-.94-1.53 3.14-1.9h1.96v8.02ZM920.68 919.24c1.15 0 2.02.45 2.61 1.33.6.9.89 2.14.89 3.76 0 1.62-.3 2.88-.89 3.77-.6.89-1.46 1.34-2.61 1.34a2.94 2.94 0 0 1-2.61-1.34c-.6-.9-.9-2.15-.9-3.77s.3-2.87.9-3.76a2.94 2.94 0 0 1 2.6-1.33Zm0 1.61c-.5 0-.86.27-1.09.8a7.43 7.43 0 0 0-.34 2.68c0 .8.03 1.46.08 1.96l2.37-4.96a.93.93 0 0 0-.4-.37c-.16-.07-.37-.1-.62-.1Zm0 6.99c.5 0 .85-.27 1.08-.8a7.7 7.7 0 0 0 .33-2.71c0-.52-.01-.97-.04-1.36l-2.23 4.6c.2.18.48.27.86.27ZM928.74 919.24c.71 0 1.32.13 1.82.38s.89.6 1.14 1.02c.26.42.39.89.39 1.39 0 .53-.12 1.05-.36 1.54-.25.5-.65 1.05-1.2 1.66-.56.61-1.34 1.37-2.36 2.27h4.14l-.23 1.7h-6.45v-1.57c1.15-1.11 2.01-1.98 2.58-2.6.57-.62.98-1.14 1.24-1.58.26-.43.38-.84.38-1.22 0-.4-.1-.72-.33-.94-.23-.23-.55-.34-.97-.34-.36 0-.68.08-.95.23-.27.16-.54.4-.8.75l-1.34-1.02c.38-.53.84-.94 1.38-1.23a4 4 0 0 1 1.92-.44ZM937.48 919.24c1.15 0 2.02.45 2.61 1.33.6.9.89 2.14.89 3.76 0 1.62-.3 2.88-.89 3.77-.6.89-1.46 1.34-2.61 1.34a2.94 2.94 0 0 1-2.61-1.34c-.6-.9-.9-2.15-.9-3.77s.3-2.87.9-3.76a2.94 2.94 0 0 1 2.6-1.33Zm0 1.61c-.5 0-.86.27-1.09.8a7.43 7.43 0 0 0-.34 2.68c0 .8.03 1.46.09 1.96l2.36-4.96a.93.93 0 0 0-.4-.37c-.16-.07-.37-.1-.62-.1Zm0 6.99c.5 0 .85-.27 1.08-.8a7.7 7.7 0 0 0 .33-2.71c0-.52-.01-.97-.04-1.36l-2.23 4.6c.2.18.48.27.86.27ZM945.49 919.24c.67 0 1.25.12 1.75.34.5.22.89.53 1.15.9.27.38.4.8.4 1.26 0 .6-.17 1.08-.52 1.47-.35.38-.84.66-1.47.85 1.53.2 2.3 1 2.3 2.4 0 .56-.15 1.06-.46 1.51-.3.46-.73.81-1.3 1.07-.57.27-1.24.4-2 .4a4.8 4.8 0 0 1-1.93-.38 4.17 4.17 0 0 1-1.48-1.08l1.25-1.16c.53.61 1.2.92 2.01.92.5 0 .9-.12 1.2-.38.3-.25.44-.6.44-1.05 0-.97-.55-1.45-1.64-1.45h-.88l.25-1.51h.62c.45 0 .8-.11 1.07-.33.27-.22.4-.54.4-.95 0-.36-.13-.65-.4-.86-.25-.2-.6-.31-1.02-.31-.7 0-1.34.28-1.93.84l-1.13-1.18a4.6 4.6 0 0 1 3.32-1.32Z" style="fill:#3ab211;fill-rule:nonzero"/><g><path d="M1109.6 924.38c0-7.68-6.23-13.92-13.91-13.92h-68.18a13.92 13.92 0 0 0 0 27.83h68.18c7.68 0 13.91-6.24 13.91-13.91Zm-1.5 0c0-6.86-5.56-12.42-12.41-12.42h-68.18a12.42 12.42 0 0 0 0 24.83h68.18c6.85 0 12.41-5.56 12.41-12.41Z" style="fill:#3ab211"/><path d="M1032.36 919.24c1.15 0 2.02.45 2.61 1.33.6.9.89 2.14.89 3.76 0 1.62-.3 2.88-.89 3.77-.6.89-1.46 1.34-2.61 1.34a2.94 2.94 0 0 1-2.61-1.34c-.6-.9-.89-2.15-.89-3.77s.3-2.87.89-3.76a2.94 2.94 0 0 1 2.61-1.33Zm0 1.61c-.5 0-.86.27-1.08.8a7.43 7.43 0 0 0-.35 2.68c0 .8.03 1.46.09 1.96l2.36-4.96a.93.93 0 0 0-.4-.37c-.16-.07-.37-.1-.62-.1Zm0 6.99c.5 0 .85-.27 1.08-.8a7.7 7.7 0 0 0 .33-2.71c0-.52-.01-.97-.04-1.36l-2.22 4.6c.18.18.47.27.85.27ZM1042.61 921.57l1.23 1.23-1.89 1.83 1.9 1.87-1.24 1.23-1.85-1.9-1.85 1.9-1.23-1.23 1.9-1.87-1.9-1.83 1.23-1.23 1.85 1.87 1.85-1.87ZM1049.16 919.24c1.15 0 2.02.45 2.61 1.33.6.9.89 2.14.89 3.76 0 1.62-.3 2.88-.89 3.77-.6.89-1.46 1.34-2.61 1.34a2.94 2.94 0 0 1-2.61-1.34c-.6-.9-.89-2.15-.89-3.77s.3-2.87.89-3.76a2.94 2.94 0 0 1 2.61-1.33Zm0 1.61c-.5 0-.86.27-1.08.8a7.43 7.43 0 0 0-.35 2.68c0 .8.03 1.46.09 1.96l2.36-4.96a.93.93 0 0 0-.4-.37c-.16-.07-.37-.1-.62-.1Zm0 6.99c.5 0 .85-.27 1.08-.8a7.7 7.7 0 0 0 .33-2.71c0-.52-.01-.97-.04-1.36l-2.22 4.6c.18.18.47.27.85.27ZM1059.27 927.52h1.8v1.68h-6.3v-1.68h2.34v-5.85l-2 1.26-.94-1.53 3.14-1.9h1.96v8.02ZM1065.96 919.24c1.15 0 2.02.45 2.61 1.33.6.9.89 2.14.89 3.76 0 1.62-.3 2.88-.89 3.77-.6.89-1.46 1.34-2.61 1.34a2.94 2.94 0 0 1-2.61-1.34c-.6-.9-.89-2.15-.89-3.77s.3-2.87.89-3.76a2.94 2.94 0 0 1 2.61-1.33Zm0 1.61c-.5 0-.86.27-1.08.8a7.43 7.43 0 0 0-.35 2.68c0 .8.03 1.46.09 1.96l2.36-4.96a.93.93 0 0 0-.4-.37c-.16-.07-.37-.1-.62-.1Zm0 6.99c.5 0 .85-.27 1.08-.8a7.7 7.7 0 0 0 .33-2.71c0-.52-.01-.97-.04-1.36l-2.22 4.6c.18.18.47.27.85.27ZM1074.02 919.24c.71 0 1.32.13 1.82.38s.89.6 1.14 1.02c.26.42.39.89.39 1.39 0 .53-.12 1.05-.37 1.54-.24.5-.64 1.05-1.2 1.66-.55.61-1.34 1.37-2.35 2.27h4.14l-.24 1.7h-6.44v-1.57c1.15-1.11 2-1.98 2.58-2.6.57-.62.98-1.14 1.24-1.58.25-.43.38-.84.38-1.22 0-.4-.11-.72-.33-.94-.23-.23-.55-.34-.97-.34-.36 0-.68.08-.95.23-.27.16-.54.4-.8.75l-1.34-1.02c.38-.53.84-.94 1.38-1.23a4 4 0 0 1 1.92-.44ZM1082.76 919.24c1.15 0 2.02.45 2.61 1.33.6.9.89 2.14.89 3.76 0 1.62-.3 2.88-.89 3.77-.6.89-1.46 1.34-2.61 1.34a2.94 2.94 0 0 1-2.61-1.34c-.6-.9-.89-2.15-.89-3.77s.3-2.87.89-3.76a2.94 2.94 0 0 1 2.61-1.33Zm0 1.61c-.5 0-.86.27-1.08.8a7.43 7.43 0 0 0-.35 2.68c0 .8.03 1.46.09 1.96l2.36-4.96a.93.93 0 0 0-.4-.37c-.16-.07-.37-.1-.62-.1Zm0 6.99c.5 0 .85-.27 1.08-.8a7.7 7.7 0 0 0 .33-2.71c0-.52-.01-.97-.04-1.36l-2.22 4.6c.18.18.47.27.85.27ZM1090.77 919.24c.67 0 1.26.12 1.76.34.5.22.88.53 1.15.9.26.38.4.8.4 1.26 0 .6-.18 1.08-.53 1.47-.35.38-.84.66-1.46.85 1.53.2 2.3 1 2.3 2.4 0 .56-.16 1.06-.46 1.51-.3.46-.74.81-1.31 1.07-.57.27-1.23.4-1.99.4a4.8 4.8 0 0 1-1.93-.38 4.17 4.17 0 0 1-1.49-1.08l1.25-1.16c.53.61 1.2.92 2.02.92.5 0 .89-.12 1.19-.38.3-.25.44-.6.44-1.05 0-.97-.54-1.45-1.63-1.45h-.89l.26-1.51h.61c.45 0 .8-.11 1.07-.33.27-.22.4-.54.4-.95 0-.36-.13-.65-.39-.86-.26-.2-.6-.31-1.02-.31-.7 0-1.35.28-1.93.84l-1.14-1.18a4.6 4.6 0 0 1 3.32-1.32Z" style="fill:#3ab211;fill-rule:nonzero"/></g><path d="M981.48 928.98c0 .4.06.71.19.9.13.2.33.35.6.45l-.53 1.7c-.6-.05-1.1-.2-1.47-.43-.38-.24-.67-.61-.87-1.1a3.4 3.4 0 0 1-1.35 1.19c-.54.26-1.14.39-1.81.39-1.05 0-1.89-.3-2.5-.9a3.16 3.16 0 0 1-.92-2.36c0-1.15.42-2.03 1.25-2.63.83-.61 2.02-.91 3.57-.91h1.32v-.6c0-.68-.16-1.16-.47-1.43-.31-.28-.82-.41-1.51-.41-.77 0-1.7.18-2.8.56l-.6-1.74c1.32-.51 2.6-.76 3.84-.76 2.7 0 4.06 1.2 4.06 3.64v4.44Zm-4.56 1.24c.87 0 1.55-.44 2.04-1.3v-2.14h-1.06c-1.65 0-2.48.6-2.48 1.84 0 .5.13.9.38 1.18.25.28.63.42 1.12.42ZM990.22 920.9c.94 0 1.68.28 2.2.85.54.56.8 1.35.8 2.37v7.66h-2.56v-7.26c0-.63-.11-1.07-.33-1.32-.22-.26-.55-.39-.97-.39-.44 0-.84.14-1.2.41-.35.28-.69.67-1.02 1.2v7.36h-2.56V921.2h2.22l.2 1.37a3.93 3.93 0 0 1 3.22-1.68ZM1005.1 916.96v14.82h-2.26l-.18-1.34a3.46 3.46 0 0 1-3.02 1.64 3.4 3.4 0 0 1-2.98-1.5c-.7-1-1.04-2.36-1.04-4.08 0-1.08.17-2.05.52-2.9.35-.84.84-1.5 1.49-1.98s1.4-.72 2.25-.72c1.01 0 1.9.38 2.66 1.14v-5.36l2.56.28Zm-4.74 13.18c.45 0 .85-.11 1.2-.33.35-.22.67-.57.98-1.03v-4.84c-.3-.38-.62-.66-.93-.85a2.08 2.08 0 0 0-1.09-.28c-.68 0-1.22.3-1.61.91-.4.61-.59 1.53-.59 2.75 0 1.31.17 2.25.52 2.81.35.57.85.85 1.52.85Z" style="fill:#073b4c;fill-rule:nonzero"/></g></g></svg>
\ No newline at end of file
diff --git a/docs/source/dev/api.rst b/docs/source/dev/api.rst
index 4138b7cb..ff11b794 100644
--- a/docs/source/dev/api.rst
+++ b/docs/source/dev/api.rst
@@ -32,8 +32,16 @@ CashAddress
 .. autoclass:: bitcash.cashaddress.Address
    :members:
 
-.. autoclass:: bitcash.cashaddress.generate_cashaddress
-.. autoclass:: bitcash.cashaddress.parse_cashaddress
+.. autofunction:: bitcash.cashaddress.generate_cashaddress
+.. autofunction:: bitcash.cashaddress.parse_cashaddress
+
+CashTokens
+-----------
+
+.. autofunction:: bitcash.cashtoken.verify_cashtoken_output_data
+.. autofunction:: bitcash.cashtoken.parse_cashtoken_prefix
+.. autofunction:: bitcash.cashtoken.generate_cashtoken_prefix
+.. autofunction:: bitcash.format.cashtokenaddress_to_address
 
 Network
 -------
diff --git a/docs/source/guide/cashtokens.rst b/docs/source/guide/cashtokens.rst
new file mode 100644
index 00000000..d2699e90
--- /dev/null
+++ b/docs/source/guide/cashtokens.rst
@@ -0,0 +1,175 @@
+.. _cashtokens:
+
+CashTokens
+==========
+
+CashTokens enable `token primitives`_ for BCH. A token is an asset – distinct from 
+the Bitcoin Cash currency – that can be created and transferred on the Bitcoin Cash
+network. CashTokens come in two flavours:
+
+   #. **Non-Fungible tokens (NFTs)** are a token type in which individual units 
+         cannot be merged or divided – each NFT contains a ``commitment``, a short
+         byte string attested to by the issuer of the NFT.
+   #. **Fungible tokens** are a token type in which individual units are 
+         undifferentiated – groups of fungible tokens can be freely divided and merged
+         without tracking the identity of individual tokens (much like the Bitcoin
+         Cash currency).
+
+Moreover, an NFT token can have 3 ``capabilities``:
+   #. **Minting tokens** (NFTs with the "minting" ``capability``) allow the spending
+         transaction to create any number of new NFTs of the same ``category``, each
+         with any ``commitment`` and (optionally) the *minting* or *mutable* ``capability``.
+   #. **Mutable tokens** (NFTs with the "mutable" ``capability``) allow the spending
+         transaction to create one NFT of the same ``category``, with any
+         ``commitment`` and (optionally) the *mutable* ``capability``.
+   #. **Immutable tokens** (NFTs with "none" ``capability``) cannot have their
+         ``commitment`` modified when spent.
+
+The cashtokens are attached to BCH :ref:`Unspents <unspent>`. A single unspent can
+have tokens of a single ``category``, which can include one of or both of fungible
+tokens and an NFT.
+
+.. _token primitives: https://github.com/cashtokens/cashtokens/blob/master/readme.md
+
+CashToken genesis
+------------------
+
+To create cashtokens, an :ref:`unspent <unspent>` is required with output index 0 that
+acts as a genesis unspent. This genesis unspent can be spent to create the cashtoken
+required. This cashtoken then gets the transaction id of the genesis output as its
+``category``.
+
+.. figure:: /_static/cashtoken-creation.svg
+
+  Two new token ``categories`` are created by transaction ``c3a601...`` The first ``category`` (``■ b201a0...``) is created by spending the 0th output of transaction ``b201a0...``; for this ``category``, a supply of 150 fungible tokens are created across two outputs (100 and 50). The second ``category`` (``▲ a1efcd...``) is created by spending the 0th output of transaction ``a1efcd...``; for this ``category``, a supply of 100 fungible tokens are created across two outputs (20 and 80), and two NFTs are created (each with a ``commitment`` of ``0x010203``).
+
+Using the :func:`~bitcash.PrivateKey.get_unspents` you can query the unspent set
+belonging to your address:
+
+.. code-block:: python
+
+    >>> key = Key(...)
+    >>> key.get_unspents()
+    [Unspent(amount=900000, confirmations=1, script='76a914dd9c917762a9f585a40e5c3a54238684d8cc741e88ac', txid='afe979e6b52e37d29f6c4d7edd922bddb91b5e4d55ebfa8cd59a0f90bc03b802', txindex=0)]
+
+In the above example, the unspent output has an output index 0, which implies it can be
+a cashtoken genesis unspent. The cashtoken generated with this unspent will have a 
+``category`` of ``afe979...``. To generate a cashtoken with an NFT of "minting" 
+``capability``, and 10000 fungible tokens we can use an extended :ref:`output format <outputsparam>`
+which is a tuple of size 7 in the form `(destination, amount, currency, category_id, 
+nft_capability, nft_commitment, token_amount)`. This can be sent as:
+
+.. code-block:: python
+
+   >>> key.send([
+   ...     (
+   ...         "bitcoincash:zrweeythv25ltpdypewr54prs6zd3nr5rcjhrnhy2v",  # destination
+   ...         1000,  # amount
+   ...         "satoshi",  # currency
+   ...         "afe979e6b52e37d29f6c4d7edd922bddb91b5e4d55ebfa8cd59a0f90bc03b802",  # category
+   ...         "minting",  # NFT capability
+   ...         None,  # NFT commitment, None
+   ...         10000  # fungible token amount
+   ...     )
+   ... ])
+   '311e30abebb9d6b35d3d02308bec3985988aa0ef997bffa7bca821fe6094f17f'
+   >>> key.get_balance()  # to fetch present balance from the network
+   '899737'
+   >>> key.cashtoken_balance
+   {'afe979e6b52e37d29f6c4d7edd922bddb91b5e4d55ebfa8cd59a0f90bc03b802': {'token_amount': 10000, 'nft': [{'capability': 'minting'}]}}
+
+CashToken spending
+------------------
+
+Much like generating new cashtokens, cashtokens can be spent as well. For example, to 
+send 6000 fungible tokens of ``category`` ``afe979...`` you can use:
+
+.. code-block:: python
+
+   >>> key.send([
+   ...     (
+   ...         "bitcoincash:zrweeythv25ltpdypewr54prs6zd3nr5rcjhrnhy2v",
+   ...         1000,
+   ...         "satoshi",
+   ...         "afe979e6b52e37d29f6c4d7edd922bddb91b5e4d55ebfa8cd59a0f90bc03b802",
+   ...         None,
+   ...         None,
+   ...         6000
+   ...     )
+   ... ])
+   'fec7bff45086ac961e8f2289a9f280f7710144979a61b0a11121f674fed85b15'
+
+BitCash automatically handles unspents to form the desired transaction outputs with 
+the leftover BCH and cashtokens management.
+
+We can further use the "minting" ``capability`` of NFT to mint a cashtoken of "mutable"
+``capability`` with a ``commitment`` of ``b"bitcash"`` as:
+
+.. code-block:: python
+
+   >>> key.send(
+   ...     [
+   ...     (
+   ...         "bitcoincash:zrweeythv25ltpdypewr54prs6zd3nr5rcjhrnhy2v",
+   ...         1000,
+   ...         "satoshi",
+   ...         "afe979e6b52e37d29f6c4d7edd922bddb91b5e4d55ebfa8cd59a0f90bc03b802",
+   ...         "mutable",
+   ...         b"bitcash",
+   ...         None
+   ...     )
+   ... ])
+   '58292afb507d881e6564f4210e24d2008c7b7d9028e365811cdf7304080ecb08'
+   >>> key.get_balance()
+   '898388'
+   >>> key.cashtoken_balance
+   {'afe979e6b52e37d29f6c4d7edd922bddb91b5e4d55ebfa8cd59a0f90bc03b802': {'nft': [{'capability': 'mutable', 'commitment': b'bitcash'}, {'capability': 'minting'}], 'token_amount': 10000}}
+
+
+CashToken spending order
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+When spending unspents, BitCash follows a certain order:
+
+   #. When choosing unspents to add BCH to fulfill BCH in outputs, BitCash 
+         prioritises adding unspents with no cashtokens. It then chooses unspents
+         with just fungible tokens, followed by unspents with NFT. The unspents
+         with "none" ``capability`` are chosen first, then followed by "mutable"
+         ``capability``, and finally "minting" ``capability``.
+   #. When an NFT with "none" ``capability`` is to be sent, then a "none" ``capability``
+         NFT with the same ``commitment`` is chosen. If none are found, then an NFT
+         with "mutable" ``capability`` is chosen, whose ``commitment`` is mutated
+         to match the ``commitment`` of the NFT and is made into the NFT with "none"
+         ``capability``. If none are found, then an NFT with "minting" ``capability``
+         is added to the transaction, to mint the required NFT. The "minting" 
+         ``capability`` NFT is not consumed and is also present in a leftover output.
+   #. When an NFT with "mutable" ``capability`` is to be sent, then a "mutable"
+         ``capability`` NFT is chosen, whose ``commitment`` is mutated to match the
+         ``commitment`` of the "mutable" ``capability`` NFT sent. If none are found,
+         then an NFT with "minting" ``capability`` is added to the transaction, to
+         mint the required NFT. The "minting" ``capability`` NFT is not consumed and
+         is also present in a leftover output.
+   #. When an NFT with "minting" ``capability`` is to be sent, then a "minting"
+         ``capability`` NFT is chosen. The "minting" ``capability`` NFT is not consumed
+         and is also present in a leftover output.
+
+.. note::
+   In all the cases where an NFT is to be sent, the NFT to be spent has to be of the same
+   ``category``.
+
+If the default behaviour is not suitable, then a curated unspent set can be specified,
+which only includes cashtokens which need to be used.
+   
+
+CashToken signalling CashAddr
+-----------------------------
+
+To signal cashtoken support by wallets, new :ref:`cashaddr` versions are introduced. BitCash 
+wallet can signal cashtoken support by sharing cashtoken address using 
+:func:`~bitcash.PrivateKey.cashtoken_address`, and BitCash does not allow spending cashtokens to
+non-cashtoken-signalling addresses:
+
+.. code-block:: python
+
+   >>> key.cashtoken_address
+   'bitcoincash:zrweeythv25ltpdypewr54prs6zd3nr5rcjhrnhy2v'
diff --git a/docs/source/guide/network.rst b/docs/source/guide/network.rst
index 945d05b0..80a56690 100644
--- a/docs/source/guide/network.rst
+++ b/docs/source/guide/network.rst
@@ -46,6 +46,8 @@ terms of other currencies using :func:`~bitcash.PrivateKey.balance_as`.
 
 See also :ref:`unsupported currencies`.
 
+.. _unspent:
+
 Unspent
 -------
 
@@ -109,9 +111,17 @@ Services
 --------
 
 BitCash communicates with the blockchain using trusted third-party APIs.
-Specifically, it can access:
+Specifically, on `mainnet`, it can access:
+
+- `<https://demo.chaingraph.cash/v1/graphql>`_ via :class:`~bitcash.network.APIs.ChaingraphAPI.ChaingraphAPI`
+- `<https://gql.chaingraph.pat.mn/v1/graphql>`_ via :class:`~bitcash.network.APIs.ChaingraphAPI.ChaingraphAPI`
+- `<https://rest.bch.actorforth.org/v2/>`_ via :class:`~bitcash.network.APIs.BitcoinDotComAPI.BitcoinDotComAPI`
+
+And on `testnet`, it can access:
+
+- `<https://demo.chaingraph.cash/v1/graphql>`_ via :class:`~bitcash.network.APIs.ChaingraphAPI.ChaingraphAPI`
+- `<https://gql.chaingraph.pat.mn/v1/graphql>`_ via :class:`~bitcash.network.APIs.ChaingraphAPI.ChaingraphAPI`
 
-- `<https://insight.bitpay.com>`_ via :class:`~bitcash.network.services.BitpayAPI`
 
 NetworkAPI
 ^^^^^^^^^^
@@ -119,6 +129,10 @@ NetworkAPI
 Private key network operations use :class:`~bitcash.network.NetworkAPI`. For each method,
 it polls a service and if an error occurs it tries another.
 
+.. note::
+   Default chaingraph APIs do not indicate if a transaction broadcast has failed. The NetworkAPI fallbacks to 
+   BitcoinDotComAPI on ``mainnet`` to broadcast a transaction.
+
 .. _satoshi: https://en.bitcoin.it/wiki/Satoshi_(unit)
 .. _blockchain: https://en.bitcoin.it/wiki/Block_chain
 .. _unspent transaction outputs: https://en.bitcoin.it/wiki/Transaction#Input
diff --git a/docs/source/guide/node.rst b/docs/source/guide/node.rst
index d480e120..dde276bc 100644
--- a/docs/source/guide/node.rst
+++ b/docs/source/guide/node.rst
@@ -3,25 +3,46 @@
 Customize your node API endpoints
 =================================
 
-You can use your own or a compatible node (currently, `bch toolkit`_ is supported and works out of the box) by setting the following environment variables::
+You can use your own or a compatible node (currently, `bch toolkit`_ and `ChainGraph`_ are supported and works out of the box) by setting the following environment variables::
 
     BITCOINCOM_API_MAINNET
     BITCOINCOM_API_TESTNET
     BITCOINCOM_API_REGTEST
+    CHAINGRAPH_API
+    CHAINGRAPH_API_MAINNET
+    CHAINGRAPH_API_TESTNET
+    CHAINGRAPH_API_REGTEST
 
-For example::
+For example, for BitcoinDotComAPI::
 
     export BITCOINCOM_API_MAINNET=https://rest.bitcoin.com/v2/
 
+And for ChainGraph API::
+
+    export CHAINGRAPH_API=https://demo.chaingraph.cash/v1/graphql
+    export CHAINGRAPH_API_MAINNET=%mainnet
+    export CHAINGRAPH_API_TESTNET=%testnet
+
+This is so implemented because a ChainGraph instance can be connected to multiple BCH nodes, even on different networks of mainnet, testnet, or regtest. These nodes can be differently queried by their node names with the node-like pattern given in the relevant environment variable. If the node-like pattern environment variable is missing, then the "%" pattern is used as default.
+
 You can also specify multiple endpoints for redundancy by setting the following environment variables::
 
     BITCOINCOM_API_MAINNET_1
     BITCOINCOM_API_MAINNET_2
     BITCOINCOM_API_MAINNET_3
     and so on...
+    or
+    CHAINGRAPH_API_1
+    CHAINGRAPH_API_2
+    CHAINGRAPH_API_MAINNET_1
+    CHAINGRAPH_API_MAINNET_2
+    CHAINGRAPH_API_TESTNET_2
+    and so on...
 
 This works with any supported network (mainnet, testnet and regtest).
 
-Note that if, for example, `BITCOINCOM_API_MAINNET` is set, `BITCOINCOM_API_MAINNET_1` and so on will not be taken into account.
+.. note::
+   If, for example, `BITCOINCOM_API_MAINNET` is set, `BITCOINCOM_API_MAINNET_1` and so on will not be taken into account.
 
 .. _bch toolkit: https://github.com/actorforth/bch-toolkit
+.. _ChainGraph: https://chaingraph.cash/
diff --git a/docs/source/index.rst b/docs/source/index.rst
index c97beca0..6dea52b6 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -83,6 +83,7 @@ of best practices.
     guide/network
     guide/node
     guide/transactions
+    guide/cashtokens.rst
     guide/rates
     guide/fees
     guide/advanced


Test patch:
diff --git a/tests/network/APIs/test_BitcoinDotComAPI.py b/tests/network/APIs/test_BitcoinDotComAPI.py
new file mode 100644
index 00000000..05684091
--- /dev/null
+++ b/tests/network/APIs/test_BitcoinDotComAPI.py
@@ -0,0 +1,579 @@
+import pytest
+from _pytest.monkeypatch import MonkeyPatch
+from bitcash.network.APIs import BitcoinDotComAPI as _bapi
+
+from bitcash.network.transaction import Transaction, TxPart
+from bitcash.network.APIs.BitcoinDotComAPI import BitcoinDotComAPI
+from bitcash.network.meta import Unspent
+
+
+BITCOIN_CASHADDRESS_CATKN = "bitcoincash:zzfyvx77v2pmgc0vulwlfkl3uzjgh5gnmq37yf2mzf"
+
+
+class DummyRequest:
+    def __init__(self, return_json):
+        self.return_json = return_json
+
+    def json(self, *args, **kwargs):
+        return self.return_json
+
+    def raise_for_status(self):
+        pass
+
+
+class DummySession:
+    def __init__(self, return_json):
+        self.return_json = return_json
+
+    def get(self, url, *args, **kwargs):
+        return DummyRequest(self.return_json)
+
+    def post(self, url, json_request, *args, **kwargs):
+        """
+        Makeshift function to get cashtoken info in unspents by querying tx details.
+        Should be deprecated once BitcoinDotComAPI supports cashtokens in unspents
+        """
+        return DummyRequest(
+            [
+                {
+                    "vout": [
+                        {
+                            "tokenData": {
+                                "category": "b3d668379a421820fe89cf1bda4bfd7295202a516a0fa5ca0c8011e4c2fc256d",
+                                "amount": 0,
+                                "nft": {"capability": "none", "commitment": "0a"},
+                            },
+                        }
+                    ]
+                },
+                {
+                    "vout": [
+                        {
+                            "tokenData": {
+                                "category": "c3d668379a421820fe89cf1bda4bfd7295202a516a0fa5ca0c8011e4c2fc256d",
+                                "amount": 0,
+                                "nft": {"capability": "none", "commitment": ""},
+                            },
+                        },
+                    ]
+                },
+                {
+                    "vout": [
+                        {
+                            "tokenData": {
+                                "category": "55255e66ab1280fae24896c084c360d5027c1b4ef5b1a5588c4b7af246fdcf7a",
+                                "amount": 1000,
+                            },
+                        },
+                    ]
+                },
+                {
+                    "vout": [
+                        {},
+                        {}
+                    ]
+                },
+                {
+                    "vout": [
+                        {},
+                        {}
+                    ]
+                },
+            ]
+        )
+
+
+class TestBitcoinDotComAPI:
+    def setup_method(self):
+        self.monkeypatch = MonkeyPatch()
+        self.api = BitcoinDotComAPI("https://dummy.com/v2/")
+
+    def test_get_balance(self):
+        return_json = {
+            "balanceSat": 2500,
+            "unconfirmedBalanceSat": 500,
+            "balance": 0.00899289,
+            "unconfirmedBalance": 0,
+            "transactions": [
+                "afe979e6b52e37d29f6c4d7edd922bddb91b5e4d55ebfa8cd59a0f90bc03b802",
+                "311e30abebb9d6b35d3d02308bec3985988aa0ef997bffa7bca821fe6094f17f",
+                "fec7bff45086ac961e8f2289a9f280f7710144979a61b0a11121f674fed85b15",
+            ],
+            "txAppearances": 3,
+            "unconfirmedTxAppearances": 0,
+            "totalReceived": 0.02699026,
+            "totalReceivedSat": 2699026,
+            "totalSent": 0.01799737,
+            "totalSentSat": 1799737,
+            "legacyAddress": "1MCmtwrNwGdBAJ42MfAn4UKEns17tGQTAs",
+            "cashAddress": "bitcoincash:qrweeythv25ltpdypewr54prs6zd3nr5rc4asdez4l",
+            "slpAddress": "simpleledger:qrweeythv25ltpdypewr54prs6zd3nr5rcexmkvztp",
+            "currentPage": 0,
+            "pagesTotal": None,
+        }
+        self.monkeypatch.setattr(_bapi, "session", DummySession(return_json))
+        balance = self.api.get_balance(BITCOIN_CASHADDRESS_CATKN)
+        assert balance == 3000
+
+        # zero return
+        return_json = {
+            "balanceSat": 0,
+            "unconfirmedBalanceSat": 0,
+            "balance": 0,
+            "unconfirmedBalance": 0,
+            "transactions": [],
+            "txAppearances": 0,
+            "unconfirmedTxAppearances": 0,
+            "totalReceived": 0,
+            "totalReceivedSat": 0,
+            "totalSent": 0,
+            "totalSentSat": 0,
+            "legacyAddress": "1AaY9371BsWXnLDz1jD4PYeuehA2PMidZY",
+            "cashAddress": "bitcoincash:qp53pksewwhtufkkcs76ycl5nq9t0kr6kq4uwkyu54",
+            "slpAddress": "simpleledger:qp53pksewwhtufkkcs76ycl5nq9t0kr6kqe89d3u2t",
+            "currentPage": 0,
+            "pagesTotal": None,
+        }
+        self.monkeypatch.setattr(_bapi, "session", DummySession(return_json))
+        balance = self.api.get_balance(BITCOIN_CASHADDRESS_CATKN)
+        assert balance == 0
+
+    def test_get_transactions(self):
+        return_json = {
+            "balanceSat": 2500,
+            "unconfirmedBalanceSat": 500,
+            "balance": 0.00899289,
+            "unconfirmedBalance": 0,
+            "transactions": [
+                "ae3cdb099d52da7dd4b1e16762b5788fd151e69836a45aba53adcecb02fccb4a",
+                "d07ee04f7e5792ae848b778c8b802283aff77413865582ebba3f3c7c016e82a9",
+                "2cd47128e4af9ab1c3df0bce0305c2bbf5ad7fdecbba3c0b73766294bc88eaf8",
+                "616c8f5c64847645a9052d9aec822abf6fb526ec7b01cc918e392cdf24df8f89",
+                "2c39cebc1ea104243f87d78a522ec1d499d98ffc2f145c08d474889573300dd7",
+            ],
+            "txAppearances": 3,
+            "unconfirmedTxAppearances": 0,
+            "totalReceived": 0.02699026,
+            "totalReceivedSat": 2699026,
+            "totalSent": 0.01799737,
+            "totalSentSat": 1799737,
+            "legacyAddress": "1MCmtwrNwGdBAJ42MfAn4UKEns17tGQTAs",
+            "cashAddress": "bitcoincash:qrweeythv25ltpdypewr54prs6zd3nr5rc4asdez4l",
+            "slpAddress": "simpleledger:qrweeythv25ltpdypewr54prs6zd3nr5rcexmkvztp",
+            "currentPage": 0,
+            "pagesTotal": None,
+        }
+        self.monkeypatch.setattr(_bapi, "session", DummySession(return_json))
+        transactions = self.api.get_transactions(BITCOIN_CASHADDRESS_CATKN)
+
+        assert transactions == [
+            "ae3cdb099d52da7dd4b1e16762b5788fd151e69836a45aba53adcecb02fccb4a",
+            "d07ee04f7e5792ae848b778c8b802283aff77413865582ebba3f3c7c016e82a9",
+            "2cd47128e4af9ab1c3df0bce0305c2bbf5ad7fdecbba3c0b73766294bc88eaf8",
+            "616c8f5c64847645a9052d9aec822abf6fb526ec7b01cc918e392cdf24df8f89",
+            "2c39cebc1ea104243f87d78a522ec1d499d98ffc2f145c08d474889573300dd7",
+        ]
+
+        # zero return
+        return_json = {
+            "balanceSat": 0,
+            "unconfirmedBalanceSat": 0,
+            "balance": 0,
+            "unconfirmedBalance": 0,
+            "transactions": [],
+            "txAppearances": 0,
+            "unconfirmedTxAppearances": 0,
+            "totalReceived": 0,
+            "totalReceivedSat": 0,
+            "totalSent": 0,
+            "totalSentSat": 0,
+            "legacyAddress": "1AaY9371BsWXnLDz1jD4PYeuehA2PMidZY",
+            "cashAddress": "bitcoincash:qp53pksewwhtufkkcs76ycl5nq9t0kr6kq4uwkyu54",
+            "slpAddress": "simpleledger:qp53pksewwhtufkkcs76ycl5nq9t0kr6kqe89d3u2t",
+            "currentPage": 0,
+            "pagesTotal": None,
+        }
+        self.monkeypatch.setattr(_bapi, "session", DummySession(return_json))
+        transactions = self.api.get_transactions(BITCOIN_CASHADDRESS_CATKN)
+
+        assert transactions == []
+
+    def test_get_transaction(self):
+        return_json = {
+            "in_mempool": False,
+            "in_orphanpool": False,
+            "txid": "446f83e975d2870de740917df1b5221aa4bc52c6e2540188f5897c4ce775b7f4",
+            "size": 524,
+            "version": 2,
+            "locktime": 0,
+            "vin": [
+                {
+                    "txid": "8473d94f604de351cdee3030f6c354d36b257861ad8e95bbc0a06fbab2a2f9cf",
+                    "vout": 0,
+                    "scriptSig": {
+                        "asm": "77033dfa31b3ab4ad8a147d0b7bd10da60e7fe1df51bf1767f5ba7273767d7ffad55feec5c201ea89c6c07a1c8368d8a378aae2f48ddd2076324769b2c23a1ac41 031aa8f87cde6c87de9bf1bdb9e575801a754d2a600be4d1fc89e36eae6db63bc6",
+                        "hex": "4177033dfa31b3ab4ad8a147d0b7bd10da60e7fe1df51bf1767f5ba7273767d7ffad55feec5c201ea89c6c07a1c8368d8a378aae2f48ddd2076324769b2c23a1ac4121031aa8f87cde6c87de9bf1bdb9e575801a754d2a600be4d1fc89e36eae6db63bc6",
+                    },
+                    "sequence": 0,
+                    "cashAddress": "bitcoincash:qz8wymtvnavrd8u5sexuxccvm6chlt3095hczr7px4",
+                    "n": 0,
+                    "value": 0.0001,
+                },
+                {
+                    "txid": "79ef13a2d063b9a07d2de9308a77e8f88e65aa2d2ac9c3687c99d6b96c549acf",
+                    "vout": 1,
+                    "scriptSig": {
+                        "asm": "b818b5c19459d64c4f16ac8fbaff844a6c0d05de8cf563173737d56908de56033a1e367f3c7cae8cf3240af06659bcde09d543bc064e208a31d576bbf074bb7141 031aa8f87cde6c87de9bf1bdb9e575801a754d2a600be4d1fc89e36eae6db63bc6",
+                        "hex": "41b818b5c19459d64c4f16ac8fbaff844a6c0d05de8cf563173737d56908de56033a1e367f3c7cae8cf3240af06659bcde09d543bc064e208a31d576bbf074bb714121031aa8f87cde6c87de9bf1bdb9e575801a754d2a600be4d1fc89e36eae6db63bc6",
+                    },
+                    "sequence": 0,
+                    "cashAddress": "bitcoincash:qz8wymtvnavrd8u5sexuxccvm6chlt3095hczr7px4",
+                    "n": 1,
+                    "value": 0.00008746,
+                },
+            ],
+            "vout": [
+                {
+                    "value": 0.00001,
+                    "n": 0,
+                    "scriptPubKey": {
+                        "asm": "OP_DUP OP_HASH160 8ee26d6c9f58369f94864dc3630cdeb17fae2f2d OP_EQUALVERIFY OP_CHECKSIG",
+                        "hex": "76a9148ee26d6c9f58369f94864dc3630cdeb17fae2f2d88ac",
+                        "reqSigs": 1,
+                        "type": "pubkeyhash",
+                        "addresses": [
+                            "bitcoincash:qz8wymtvnavrd8u5sexuxccvm6chlt3095hczr7px4"
+                        ],
+                        "cashAddrs": [
+                            "bitcoincash:qz8wymtvnavrd8u5sexuxccvm6chlt3095hczr7px4"
+                        ],
+                    },
+                    "tokenData": {
+                        "category": "8473d94f604de351cdee3030f6c354d36b257861ad8e95bbc0a06fbab2a2f9cf",
+                        "amount": "140000000000",
+                    },
+                    "spentTxId": None,
+                    "spentIndex": None,
+                    "spentHeight": None,
+                },
+                {
+                    "value": 0,
+                    "n": 1,
+                    "scriptPubKey": {
+                        "asm": "OP_RETURN 1380795202 6b2000be5ce5527cd653c49cdba486e2fd0ec4214da2f71d7e56ad027b2139f4 676973742e67697468756275736572636f6e74656e742e636f6d2f6d722d7a776574732f38346230303537383038616632306466333932383135666232376434613636312f726177",
+                        "hex": "6a0442434d52206b2000be5ce5527cd653c49cdba486e2fd0ec4214da2f71d7e56ad027b2139f448676973742e67697468756275736572636f6e74656e742e636f6d2f6d722d7a776574732f38346230303537383038616632306466333932383135666232376434613636312f726177",
+                        "type": "nulldata",
+                    },
+                    "spentTxId": None,
+                    "spentIndex": None,
+                    "spentHeight": None,
+                },
+                {
+                    "value": 0.00017221,
+                    "n": 2,
+                    "scriptPubKey": {
+                        "asm": "OP_DUP OP_HASH160 8ee26d6c9f58369f94864dc3630cdeb17fae2f2d OP_EQUALVERIFY OP_CHECKSIG",
+                        "hex": "76a9148ee26d6c9f58369f94864dc3630cdeb17fae2f2d88ac",
+                        "reqSigs": 1,
+                        "type": "pubkeyhash",
+                        "addresses": [
+                            "bitcoincash:qz8wymtvnavrd8u5sexuxccvm6chlt3095hczr7px4"
+                        ],
+                        "cashAddrs": [
+                            "bitcoincash:qz8wymtvnavrd8u5sexuxccvm6chlt3095hczr7px4"
+                        ],
+                    },
+                    "tokenData": {
+                        "category": "8473d94f604de351cdee3030f6c354d36b257861ad8e95bbc0a06fbab2a2f9cf",
+                        "amount": 0,
+                        "nft": {"capability": "minting", "commitment": ""},
+                    },
+                    "spentTxId": None,
+                    "spentIndex": None,
+                    "spentHeight": None,
+                },
+            ],
+            "blockhash": "0000000000000000007c302f8790f32efb996a9d162408ce930e0e70ee3cbe8d",
+            "confirmations": 2172,
+            "time": 1684161846,
+            "blocktime": 1684161846,
+            "valueIn": 0.00018746,
+            "valueOut": 0.00018221,
+            "fees": 0.00000525,
+            "blockheight": 792781,
+        }
+        self.monkeypatch.setattr(_bapi, "session", DummySession(return_json))
+        transaction = self.api.get_transaction(BITCOIN_CASHADDRESS_CATKN)
+        tx = Transaction(
+            "446f83e975d2870de740917df1b5221aa4bc52c6e2540188f5897c4ce775b7f4",
+            792781,
+            18746,
+            18221,
+            525,
+        )
+        tx.inputs = [
+            TxPart(
+                "bitcoincash:qz8wymtvnavrd8u5sexuxccvm6chlt3095hczr7px4",
+                10000,
+                data_hex="4177033dfa31b3ab4ad8a147d0b7bd10da60e7fe1df51bf1767f5ba7273767d7ffad55feec5c201ea89c6c07a1c8368d8a378aae2f48ddd2076324769b2c23a1ac4121031aa8f87cde6c87de9bf1bdb9e575801a754d2a600be4d1fc89e36eae6db63bc6",
+            ),
+            TxPart(
+                "bitcoincash:qz8wymtvnavrd8u5sexuxccvm6chlt3095hczr7px4",
+                8746,
+                data_hex="41b818b5c19459d64c4f16ac8fbaff844a6c0d05de8cf563173737d56908de56033a1e367f3c7cae8cf3240af06659bcde09d543bc064e208a31d576bbf074bb714121031aa8f87cde6c87de9bf1bdb9e575801a754d2a600be4d1fc89e36eae6db63bc6",
+            ),
+        ]
+        tx.outputs = [
+            TxPart(
+                "bitcoincash:qz8wymtvnavrd8u5sexuxccvm6chlt3095hczr7px4",
+                1000,
+                category_id="8473d94f604de351cdee3030f6c354d36b257861ad8e95bbc0a06fbab2a2f9cf",
+                token_amount=140000000000,
+                data_hex="76a9148ee26d6c9f58369f94864dc3630cdeb17fae2f2d88ac",
+            ),
+            TxPart(
+                None,
+                0,
+                data_hex="6a0442434d52206b2000be5ce5527cd653c49cdba486e2fd0ec4214da2f71d7e56ad027b2139f448676973742e67697468756275736572636f6e74656e742e636f6d2f6d722d7a776574732f38346230303537383038616632306466333932383135666232376434613636312f726177",
+            ),
+            TxPart(
+                "bitcoincash:qz8wymtvnavrd8u5sexuxccvm6chlt3095hczr7px4",
+                17221,
+                category_id="8473d94f604de351cdee3030f6c354d36b257861ad8e95bbc0a06fbab2a2f9cf",
+                nft_capability="minting",
+                data_hex="76a9148ee26d6c9f58369f94864dc3630cdeb17fae2f2d88ac",
+            ),
+        ]
+
+        print(transaction.to_dict())
+        print(tx.to_dict())
+        assert transaction == tx
+
+        # unconfirmed tx
+        return_json = {
+            "in_mempool": True,
+            "in_orphanpool": False,
+            "txid": "2dc926aac9ffb12ffa7dec784440d76e75c545d9ab4e46ea40e6b4ae73ed448f",
+            "size": 223,
+            "version": 1,
+            "locktime": 0,
+            "vin": [
+                {
+                    "txid": "87dfe5b5af5526a7652ee23ca9ded6862f9a490de219bb7c85f5010c3b8ebc4a",
+                    "vout": 0,
+                    "scriptSig": {
+                        "asm": "3044022024d7be8afd3100656889cddc309d2f5fc343a345fe7d7a22191163f463c5aac502200bbcebf4dc1361a2931f585c33a9fdf9816cbc919341b863609551030bcdb97d41 046bad1c4c33157c12dd812e734917f05a65b502658eeb4f164decc087c54f9fca4005df3499ad93f698294ab13259d7da578461930a9cb7312d526ab2d8f82012",
+                        "hex": "473044022024d7be8afd3100656889cddc309d2f5fc343a345fe7d7a22191163f463c5aac502200bbcebf4dc1361a2931f585c33a9fdf9816cbc919341b863609551030bcdb97d4141046bad1c4c33157c12dd812e734917f05a65b502658eeb4f164decc087c54f9fca4005df3499ad93f698294ab13259d7da578461930a9cb7312d526ab2d8f82012",
+                    },
+                    "sequence": 4294967295,
+                    "cashAddress": "bitcoincash:qrelay2cnfsu84lvn6609rhrudh26rjt4y6ddw55lf",
+                    "n": 0,
+                    "value": 0.009,
+                }
+            ],
+            "vout": [
+                {
+                    "value": 0.00899745,
+                    "n": 0,
+                    "scriptPubKey": {
+                        "asm": "OP_DUP OP_HASH160 a522e4f6ca57aef5bf893d29029c3e9fc54a67f0 OP_EQUALVERIFY OP_CHECKSIG",
+                        "hex": "76a914a522e4f6ca57aef5bf893d29029c3e9fc54a67f088ac",
+                        "reqSigs": 1,
+                        "type": "pubkeyhash",
+                        "addresses": [
+                            "bitcoincash:qzjj9e8keft6aadl3y7jjq5u860u2jn87qxwpv9nzl"
+                        ],
+                        "cashAddrs": [
+                            "bitcoincash:qzjj9e8keft6aadl3y7jjq5u860u2jn87qxwpv9nzl"
+                        ],
+                    },
+                    "spentTxId": None,
+                    "spentIndex": None,
+                    "spentHeight": None,
+                }
+            ],
+            "confirmations": 0,
+            "time": 1684050728,
+            "valueIn": 0.009,
+            "valueOut": 0.00899745,
+            "fees": 0.00000255,
+        }
+        self.monkeypatch.setattr(_bapi, "session", DummySession(return_json))
+        transaction = self.api.get_transaction(BITCOIN_CASHADDRESS_CATKN)
+        tx = Transaction(
+            "2dc926aac9ffb12ffa7dec784440d76e75c545d9ab4e46ea40e6b4ae73ed448f",
+            None,
+            900000,
+            899745,
+            255,
+        )
+        tx.inputs = [
+            TxPart(
+                "bitcoincash:qrelay2cnfsu84lvn6609rhrudh26rjt4y6ddw55lf",
+                900000,
+                data_hex="473044022024d7be8afd3100656889cddc309d2f5fc343a345fe7d7a22191163f463c5aac502200bbcebf4dc1361a2931f585c33a9fdf9816cbc919341b863609551030bcdb97d4141046bad1c4c33157c12dd812e734917f05a65b502658eeb4f164decc087c54f9fca4005df3499ad93f698294ab13259d7da578461930a9cb7312d526ab2d8f82012",
+            )
+        ]
+        tx.outputs = [
+            TxPart(
+                "bitcoincash:qzjj9e8keft6aadl3y7jjq5u860u2jn87qxwpv9nzl",
+                899745,
+                data_hex="76a914a522e4f6ca57aef5bf893d29029c3e9fc54a67f088ac",
+            )
+        ]
+
+        assert transaction == tx
+
+    def test_get_tx_amount(self):
+        return_json = {"vout": [{"value": 0.00001}]}
+        self.monkeypatch.setattr(_bapi, "session", DummySession(return_json))
+        amount = self.api.get_tx_amount(
+            "446f83e975d2870de740917df1b5221aa4bc52c6e2540188f5897c4ce775b7f4", 0
+        )
+        assert amount == 1000
+
+    def test_get_unspent(self):
+        return_json = {
+            "utxos": [
+                {
+                    "height": 792782,
+                    "txid": "8aa279c9c46a812273c12fe78efff995ab6493cffb130ef54da73d4268a1bc9f",
+                    "vout": 0,
+                    "satoshis": 1000,
+                    "amount": 0.00001,
+                    "confirmations": 1265,
+                    "tokenData": {
+                        "category": "b3d668379a421820fe89cf1bda4bfd7295202a516a0fa5ca0c8011e4c2fc256d",
+                        "amount": 0,
+                        "nft": {"capability": "none", "commitment": "0a"},
+                    },
+                },
+                {
+                    "height": 792782,
+                    "txid": "9aa279c9c46a812273c12fe78efff995ab6493cffb130ef54da73d4268a1bc9f",
+                    "vout": 0,
+                    "satoshis": 1000,
+                    "amount": 0.00001,
+                    "confirmations": 1265,
+                    "tokenData": {
+                        "category": "c3d668379a421820fe89cf1bda4bfd7295202a516a0fa5ca0c8011e4c2fc256d",
+                        "amount": 0,
+                        "nft": {"capability": "none", "commitment": ""},
+                    },
+                },
+                {
+                    "height": 792785,
+                    "txid": "1c04b42cdd4fe595040a478315c31d9276abcb00cf8e7d2f9e52f81bade279a3",
+                    "vout": 0,
+                    "satoshis": 1000,
+                    "amount": 0.00001,
+                    "confirmations": 1262,
+                    "tokenData": {
+                        "category": "55255e66ab1280fae24896c084c360d5027c1b4ef5b1a5588c4b7af246fdcf7a",
+                        "amount": 1000,
+                    },
+                },
+                {
+                    "height": 794043,
+                    "txid": "5b2f18d2c214560c4fa21dd2ff18bfa2126e6693dde20d5c516fbaf56c634fdd",
+                    "vout": 1,
+                    "satoshis": 2512699,
+                    "amount": 0.02512699,
+                    "confirmations": 4,
+                },
+                {
+                    "height": 0,
+                    "txid": "6b2f18d2c214560c4fa21dd2ff18bfa2126e6693dde20d5c516fbaf56c634fdd",
+                    "vout": 1,
+                    "satoshis": 2512699,
+                    "amount": 0.02512699,
+                    "confirmations": 0,
+                },
+            ],
+            "legacyAddress": "1E2WChGBeJXtLtrwAfb4KwYF61C99BJ47K",
+            "cashAddress": "bitcoincash:qz8wymtvnavrd8u5sexuxccvm6chlt3095hczr7px4",
+            "slpAddress": "simpleledger:qz8wymtvnavrd8u5sexuxccvm6chlt3095mrfctpct",
+            "scriptPubKey": "76a9148ee26d6c9f58369f94864dc3630cdeb17fae2f2d88ac",
+            "asm": "OP_DUP OP_HASH160 8ee26d6c9f58369f94864dc3630cdeb17fae2f2d OP_EQUALVERIFY OP_CHECKSIG",
+        }
+        self.monkeypatch.setattr(_bapi, "session", DummySession(return_json))
+        unspents = self.api.get_unspent(BITCOIN_CASHADDRESS_CATKN)
+        script = "76a9148ee26d6c9f58369f94864dc3630cdeb17fae2f2d88ac"
+        assert unspents == [
+            Unspent(
+                1000,
+                1265,
+                script,
+                "8aa279c9c46a812273c12fe78efff995ab6493cffb130ef54da73d4268a1bc9f",
+                0,
+                "b3d668379a421820fe89cf1bda4bfd7295202a516a0fa5ca0c8011e4c2fc256d",
+                "none",
+                b"\n",
+                None
+            ),
+            Unspent(
+                1000,
+                1265,
+                script,
+                "9aa279c9c46a812273c12fe78efff995ab6493cffb130ef54da73d4268a1bc9f",
+                0,
+                "c3d668379a421820fe89cf1bda4bfd7295202a516a0fa5ca0c8011e4c2fc256d",
+                "none",
+                None,
+                None
+            ),
+            Unspent(
+                1000,
+                1262,
+                script,
+                "1c04b42cdd4fe595040a478315c31d9276abcb00cf8e7d2f9e52f81bade279a3",
+                0,
+                "55255e66ab1280fae24896c084c360d5027c1b4ef5b1a5588c4b7af246fdcf7a",
+                None,
+                None,
+                1000
+            ),
+            Unspent(
+                2512699,
+                4,
+                script,
+                "5b2f18d2c214560c4fa21dd2ff18bfa2126e6693dde20d5c516fbaf56c634fdd",
+                1,
+                None,
+                None,
+                None,
+                None,
+            ),
+            Unspent(
+                2512699,
+                0,
+                script,
+                "6b2f18d2c214560c4fa21dd2ff18bfa2126e6693dde20d5c516fbaf56c634fdd",
+                1,
+                None,
+                None,
+                None,
+                None,
+            ),
+        ]
+
+        # zero return
+        return_json = {
+            "utxos": [],
+            "legacyAddress": "1AaY9371BsWXnLDz1jD4PYeuehA2PMidZY",
+            "cashAddress": "bitcoincash:qp53pksewwhtufkkcs76ycl5nq9t0kr6kq4uwkyu54",
+            "slpAddress": "simpleledger:qp53pksewwhtufkkcs76ycl5nq9t0kr6kqe89d3u2t",
+            "scriptPubKey": "",
+            "asm": "",
+        }
+        self.monkeypatch.setattr(_bapi, "session", DummySession(return_json))
+        unspents = self.api.get_unspent(BITCOIN_CASHADDRESS_CATKN)
+        assert unspents == []
+
+    def test_get_raw_transaction(self):
+        return_json = {"dummy": "dummy"}
+        self.monkeypatch.setattr(_bapi, "session", DummySession(return_json))
+        tx = self.api.get_raw_transaction(
+            "446f83e975d2870de740917df1b5221aa4bc52c6e2540188f5897c4ce775b7f4",
+        )
+        assert tx == {"dummy": "dummy"}
diff --git a/tests/network/APIs/test_ChaingraphAPI.py b/tests/network/APIs/test_ChaingraphAPI.py
new file mode 100644
index 00000000..1ecff89c
--- /dev/null
+++ b/tests/network/APIs/test_ChaingraphAPI.py
@@ -0,0 +1,480 @@
+import pytest
+from _pytest.monkeypatch import MonkeyPatch
+from bitcash.network.APIs import ChaingraphAPI as _capi
+
+from bitcash.network.transaction import Transaction, TxPart
+from bitcash.network.APIs.ChaingraphAPI import ChaingraphAPI
+from bitcash.network.meta import Unspent
+
+
+BITCOIN_CASHADDRESS_CATKN = "bitcoincash:zzfyvx77v2pmgc0vulwlfkl3uzjgh5gnmq37yf2mzf"
+
+
+class DummyRequest:
+    def __init__(self, return_json):
+        self.return_json = return_json
+
+    def json(self, *args, **kwargs):
+        return self.return_json
+
+    def raise_for_status(self):
+        pass
+
+
+class DummySession:
+    def __init__(self, return_json):
+        self.return_json = return_json
+
+    def post(self, url, json, *args, **kwargs):
+        assert "query" in json
+        if len(json.keys()) > 1:
+            assert "variables" in json
+        return DummyRequest(self.return_json)
+
+
+class TestChaingraphAPI:
+    def setup_method(self):
+        self.monkeypatch = MonkeyPatch()
+        self.api = ChaingraphAPI("https://dummy.com/v1/graphql")
+
+    def test_get_balance(self):
+        return_json = {
+            "data": {
+                "search_output": [
+                    {"value_satoshis": "1000"},
+                    {"value_satoshis": "1000"},
+                    {"value_satoshis": "1000"},
+                ]
+            }
+        }
+        self.monkeypatch.setattr(_capi, "session", DummySession(return_json))
+        balance = self.api.get_balance(BITCOIN_CASHADDRESS_CATKN)
+        assert balance == 3000
+
+        # zero return
+        return_json = {"data": {"search_output": []}}
+        self.monkeypatch.setattr(_capi, "session", DummySession(return_json))
+        balance = self.api.get_balance(BITCOIN_CASHADDRESS_CATKN)
+        assert balance == 0
+
+    def test_get_transactions(self):
+        return_json = {
+            "data": {
+                "block": [{"height": "793970"}],
+                "search_output": [
+                    {
+                        "transaction_hash": "\\x2c39cebc1ea104243f87d78a522ec1d499d98ffc2f145c08d474889573300dd7",
+                        "transaction": {
+                            "block_inclusions": [{"block": {"height": "788696"}}]
+                        },
+                        "spent_by": [
+                            {
+                                "transaction": {
+                                    "hash": "\\x616c8f5c64847645a9052d9aec822abf6fb526ec7b01cc918e392cdf24df8f89",
+                                    "block_inclusions": [
+                                        {"block": {"height": "789986"}}
+                                    ],
+                                }
+                            }
+                        ],
+                    },
+                    {
+                        "transaction_hash": "\\x616c8f5c64847645a9052d9aec822abf6fb526ec7b01cc918e392cdf24df8f89",
+                        "transaction": {
+                            "block_inclusions": [{"block": {"height": "789986"}}]
+                        },
+                        "spent_by": [
+                            {
+                                "transaction": {
+                                    "hash": "\\x2cd47128e4af9ab1c3df0bce0305c2bbf5ad7fdecbba3c0b73766294bc88eaf8",
+                                    "block_inclusions": [
+                                        {"block": {"height": "790193"}}
+                                    ],
+                                }
+                            }
+                        ],
+                    },
+                    {
+                        "transaction_hash": "\\xd07ee04f7e5792ae848b778c8b802283aff77413865582ebba3f3c7c016e82a9",
+                        "transaction": {
+                            "block_inclusions": [{"block": {"height": "793668"}}]
+                        },
+                        "spent_by": [
+                            {
+                                "transaction": {
+                                    "hash": "\\xae3cdb099d52da7dd4b1e16762b5788fd151e69836a45aba53adcecb02fccb4a",
+                                    "block_inclusions": [],
+                                }
+                            }
+                        ],
+                    },
+                    {
+                        "transaction_hash": "\\xae3cdb099d52da7dd4b1e16762b5788fd151e69836a45aba53adcecb02fccb4a",
+                        "transaction": {"block_inclusions": []},
+                        "spent_by": [],
+                    },
+                ],
+            }
+        }
+        self.monkeypatch.setattr(_capi, "session", DummySession(return_json))
+        transactions = self.api.get_transactions(BITCOIN_CASHADDRESS_CATKN)
+
+        assert transactions == [
+            "ae3cdb099d52da7dd4b1e16762b5788fd151e69836a45aba53adcecb02fccb4a",
+            "d07ee04f7e5792ae848b778c8b802283aff77413865582ebba3f3c7c016e82a9",
+            "2cd47128e4af9ab1c3df0bce0305c2bbf5ad7fdecbba3c0b73766294bc88eaf8",
+            "616c8f5c64847645a9052d9aec822abf6fb526ec7b01cc918e392cdf24df8f89",
+            "2c39cebc1ea104243f87d78a522ec1d499d98ffc2f145c08d474889573300dd7",
+        ]
+
+        # zero return
+        return_json = {"data": {"block": [{"height": "793970"}], "search_output": []}}
+        self.monkeypatch.setattr(_capi, "session", DummySession(return_json))
+        transactions = self.api.get_transactions(BITCOIN_CASHADDRESS_CATKN)
+
+        assert transactions == []
+
+    def test_get_transaction(self):
+        return_json = {
+            "data": {
+                "transaction": [
+                    {
+                        "hash": "\\x446f83e975d2870de740917df1b5221aa4bc52c6e2540188f5897c4ce775b7f4",
+                        "fee_satoshis": "525",
+                        "input_value_satoshis": "18746",
+                        "output_value_satoshis": "18221",
+                        "block_inclusions": [{"block": {"height": "792781"}}],
+                        "inputs": [
+                            {
+                                "value_satoshis": "10000",
+                                "unlocking_bytecode": "\\x4177033dfa31b3ab4ad8a147d0b7bd10da60e7fe1df51bf1767f5ba7273767d7ffad55feec5c201ea89c6c07a1c8368d8a378aae2f48ddd2076324769b2c23a1ac4121031aa8f87cde6c87de9bf1bdb9e575801a754d2a600be4d1fc89e36eae6db63bc6",
+                                "outpoint": {
+                                    "locking_bytecode": "\\x76a9148ee26d6c9f58369f94864dc3630cdeb17fae2f2d88ac",
+                                    "token_category": None,
+                                    "nonfungible_token_capability": None,
+                                    "nonfungible_token_commitment": None,
+                                    "fungible_token_amount": None,
+                                },
+                            },
+                            {
+                                "value_satoshis": "8746",
+                                "unlocking_bytecode": "\\x41b818b5c19459d64c4f16ac8fbaff844a6c0d05de8cf563173737d56908de56033a1e367f3c7cae8cf3240af06659bcde09d543bc064e208a31d576bbf074bb714121031aa8f87cde6c87de9bf1bdb9e575801a754d2a600be4d1fc89e36eae6db63bc6",
+                                "outpoint": {
+                                    "locking_bytecode": "\\x76a9148ee26d6c9f58369f94864dc3630cdeb17fae2f2d88ac",
+                                    "token_category": None,
+                                    "nonfungible_token_capability": None,
+                                    "nonfungible_token_commitment": None,
+                                    "fungible_token_amount": None,
+                                },
+                            },
+                        ],
+                        "outputs": [
+                            {
+                                "value_satoshis": "1000",
+                                "locking_bytecode": "\\x76a9148ee26d6c9f58369f94864dc3630cdeb17fae2f2d88ac",
+                                "token_category": "\\x8473d94f604de351cdee3030f6c354d36b257861ad8e95bbc0a06fbab2a2f9cf",
+                                "nonfungible_token_capability": None,
+                                "nonfungible_token_commitment": None,
+                                "fungible_token_amount": "140000000000",
+                            },
+                            {
+                                "value_satoshis": "0",
+                                "locking_bytecode": "\\x6a0442434d52206b2000be5ce5527cd653c49cdba486e2fd0ec4214da2f71d7e56ad027b2139f448676973742e67697468756275736572636f6e74656e742e636f6d2f6d722d7a776574732f38346230303537383038616632306466333932383135666232376434613636312f726177",
+                                "token_category": None,
+                                "nonfungible_token_capability": None,
+                                "nonfungible_token_commitment": None,
+                                "fungible_token_amount": None,
+                            },
+                            {
+                                "value_satoshis": "17221",
+                                "locking_bytecode": "\\x76a9148ee26d6c9f58369f94864dc3630cdeb17fae2f2d88ac",
+                                "token_category": "\\x8473d94f604de351cdee3030f6c354d36b257861ad8e95bbc0a06fbab2a2f9cf",
+                                "nonfungible_token_capability": "minting",
+                                "nonfungible_token_commitment": "\\x",
+                                "fungible_token_amount": "0",
+                            },
+                        ],
+                    }
+                ]
+            }
+        }
+
+        self.monkeypatch.setattr(_capi, "session", DummySession(return_json))
+        transaction = self.api.get_transaction(BITCOIN_CASHADDRESS_CATKN)
+        tx = Transaction(
+            "446f83e975d2870de740917df1b5221aa4bc52c6e2540188f5897c4ce775b7f4",
+            792781,
+            18746,
+            18221,
+            525,
+        )
+        tx.inputs = [
+            TxPart(
+                "bitcoincash:qz8wymtvnavrd8u5sexuxccvm6chlt3095hczr7px4",
+                10000,
+                data_hex="4177033dfa31b3ab4ad8a147d0b7bd10da60e7fe1df51bf1767f5ba7273767d7ffad55feec5c201ea89c6c07a1c8368d8a378aae2f48ddd2076324769b2c23a1ac4121031aa8f87cde6c87de9bf1bdb9e575801a754d2a600be4d1fc89e36eae6db63bc6",
+            ),
+            TxPart(
+                "bitcoincash:qz8wymtvnavrd8u5sexuxccvm6chlt3095hczr7px4",
+                8746,
+                data_hex="41b818b5c19459d64c4f16ac8fbaff844a6c0d05de8cf563173737d56908de56033a1e367f3c7cae8cf3240af06659bcde09d543bc064e208a31d576bbf074bb714121031aa8f87cde6c87de9bf1bdb9e575801a754d2a600be4d1fc89e36eae6db63bc6",
+            ),
+        ]
+        tx.outputs = [
+            TxPart(
+                "bitcoincash:qz8wymtvnavrd8u5sexuxccvm6chlt3095hczr7px4",
+                1000,
+                category_id="8473d94f604de351cdee3030f6c354d36b257861ad8e95bbc0a06fbab2a2f9cf",
+                token_amount=140000000000,
+                data_hex="76a9148ee26d6c9f58369f94864dc3630cdeb17fae2f2d88ac",
+            ),
+            TxPart(
+                None,
+                0,
+                data_hex="6a0442434d52206b2000be5ce5527cd653c49cdba486e2fd0ec4214da2f71d7e56ad027b2139f448676973742e67697468756275736572636f6e74656e742e636f6d2f6d722d7a776574732f38346230303537383038616632306466333932383135666232376434613636312f726177",
+            ),
+            TxPart(
+                "bitcoincash:qz8wymtvnavrd8u5sexuxccvm6chlt3095hczr7px4",
+                17221,
+                category_id="8473d94f604de351cdee3030f6c354d36b257861ad8e95bbc0a06fbab2a2f9cf",
+                nft_capability="minting",
+                data_hex="76a9148ee26d6c9f58369f94864dc3630cdeb17fae2f2d88ac",
+            ),
+        ]
+
+        assert transaction == tx
+
+        # unconfirmed tx
+        return_json = {
+            "data": {
+                "transaction": [
+                    {
+                        "hash": "\\x2dc926aac9ffb12ffa7dec784440d76e75c545d9ab4e46ea40e6b4ae73ed448f",
+                        "fee_satoshis": "255",
+                        "input_value_satoshis": "900000",
+                        "output_value_satoshis": "899745",
+                        "block_inclusions": [],
+                        "inputs": [
+                            {
+                                "value_satoshis": "900000",
+                                "unlocking_bytecode": "\\x473044022024d7be8afd3100656889cddc309d2f5fc343a345fe7d7a22191163f463c5aac502200bbcebf4dc1361a2931f585c33a9fdf9816cbc919341b863609551030bcdb97d4141046bad1c4c33157c12dd812e734917f05a65b502658eeb4f164decc087c54f9fca4005df3499ad93f698294ab13259d7da578461930a9cb7312d526ab2d8f82012",
+                                "outpoint": {
+                                    "locking_bytecode": "\\x76a914f3fe91589a61c3d7ec9eb4f28ee3e36ead0e4ba988ac",
+                                    "token_category": None,
+                                    "nonfungible_token_capability": None,
+                                    "nonfungible_token_commitment": None,
+                                    "fungible_token_amount": None,
+                                },
+                            }
+                        ],
+                        "outputs": [
+                            {
+                                "value_satoshis": "899745",
+                                "locking_bytecode": "\\x76a914a522e4f6ca57aef5bf893d29029c3e9fc54a67f088ac",
+                                "token_category": None,
+                                "nonfungible_token_capability": None,
+                                "nonfungible_token_commitment": None,
+                                "fungible_token_amount": None,
+                            }
+                        ],
+                    }
+                ]
+            }
+        }
+        self.monkeypatch.setattr(_capi, "session", DummySession(return_json))
+        transaction = self.api.get_transaction(BITCOIN_CASHADDRESS_CATKN)
+        tx = Transaction(
+            "2dc926aac9ffb12ffa7dec784440d76e75c545d9ab4e46ea40e6b4ae73ed448f",
+            None,
+            900000,
+            899745,
+            255,
+        )
+        tx.inputs = [
+            TxPart(
+                "bitcoincash:qrelay2cnfsu84lvn6609rhrudh26rjt4y6ddw55lf",
+                900000,
+                data_hex="473044022024d7be8afd3100656889cddc309d2f5fc343a345fe7d7a22191163f463c5aac502200bbcebf4dc1361a2931f585c33a9fdf9816cbc919341b863609551030bcdb97d4141046bad1c4c33157c12dd812e734917f05a65b502658eeb4f164decc087c54f9fca4005df3499ad93f698294ab13259d7da578461930a9cb7312d526ab2d8f82012",
+            )
+        ]
+        tx.outputs = [
+            TxPart(
+                "bitcoincash:qzjj9e8keft6aadl3y7jjq5u860u2jn87qxwpv9nzl",
+                899745,
+                data_hex="76a914a522e4f6ca57aef5bf893d29029c3e9fc54a67f088ac",
+            )
+        ]
+
+        assert transaction == tx
+
+    def test_get_tx_amount(self):
+        return_json = {"data": {"output": [{"value_satoshis": "1000"}]}}
+        self.monkeypatch.setattr(_capi, "session", DummySession(return_json))
+        amount = self.api.get_tx_amount(
+            "446f83e975d2870de740917df1b5221aa4bc52c6e2540188f5897c4ce775b7f4", 0
+        )
+        assert amount == 1000
+
+        # zero return
+        return_json = {"data": {"output": []}}
+        self.monkeypatch.setattr(_capi, "session", DummySession(return_json))
+        with pytest.raises(RuntimeError):
+            # a tx that does not exist
+            amount = self.api.get_tx_amount(
+                "546f83e975d2870de740917df1b5221aa4bc52c6e2540188f5897c4ce775b7f4", 0
+            )
+
+    def test_get_unspent(self):
+        return_json = {
+            "data": {
+                "block": [{"height": "794046"}],
+                "search_output": [
+                    {
+                        "transaction_hash": "\\x8aa279c9c46a812273c12fe78efff995ab6493cffb130ef54da73d4268a1bc9f",
+                        "output_index": "0",
+                        "value_satoshis": "1000",
+                        "token_category": "\\xb3d668379a421820fe89cf1bda4bfd7295202a516a0fa5ca0c8011e4c2fc256d",
+                        "fungible_token_amount": "0",
+                        "nonfungible_token_capability": "none",
+                        "nonfungible_token_commitment": "\\x0a",
+                        "locking_bytecode": "\\x76a9148ee26d6c9f58369f94864dc3630cdeb17fae2f2d88ac",
+                        "transaction": {
+                            "block_inclusions": [{"block": {"height": "792782"}}]
+                        },
+                    },
+                    {
+                        "transaction_hash": "\\x9aa279c9c46a812273c12fe78efff995ab6493cffb130ef54da73d4268a1bc9f",
+                        "output_index": "0",
+                        "value_satoshis": "1000",
+                        "token_category": "\\xc3d668379a421820fe89cf1bda4bfd7295202a516a0fa5ca0c8011e4c2fc256d",
+                        "fungible_token_amount": "0",
+                        "nonfungible_token_capability": "none",
+                        "nonfungible_token_commitment": "\\x",
+                        "locking_bytecode": "\\x76a9148ee26d6c9f58369f94864dc3630cdeb17fae2f2d88ac",
+                        "transaction": {
+                            "block_inclusions": [{"block": {"height": "792782"}}]
+                        },
+                    },
+                    {
+                        "transaction_hash": "\\x1c04b42cdd4fe595040a478315c31d9276abcb00cf8e7d2f9e52f81bade279a3",
+                        "output_index": "0",
+                        "value_satoshis": "1000",
+                        "token_category": "\\x55255e66ab1280fae24896c084c360d5027c1b4ef5b1a5588c4b7af246fdcf7a",
+                        "fungible_token_amount": "1000",
+                        "nonfungible_token_capability": None,
+                        "nonfungible_token_commitment": None,
+                        "locking_bytecode": "\\x76a9148ee26d6c9f58369f94864dc3630cdeb17fae2f2d88ac",
+                        "transaction": {
+                            "block_inclusions": [{"block": {"height": "792785"}}]
+                        },
+                    },
+                    {
+                        "transaction_hash": "\\x5b2f18d2c214560c4fa21dd2ff18bfa2126e6693dde20d5c516fbaf56c634fdd",
+                        "output_index": "1",
+                        "value_satoshis": "2512699",
+                        "token_category": None,
+                        "fungible_token_amount": None,
+                        "nonfungible_token_capability": None,
+                        "nonfungible_token_commitment": None,
+                        "locking_bytecode": "\\x76a9148ee26d6c9f58369f94864dc3630cdeb17fae2f2d88ac",
+                        "transaction": {
+                            "block_inclusions": [{"block": {"height": "794043"}}]
+                        },
+                    },
+                    {
+                        "transaction_hash": "\\x6b2f18d2c214560c4fa21dd2ff18bfa2126e6693dde20d5c516fbaf56c634fdd",
+                        "output_index": "1",
+                        "value_satoshis": "2512699",
+                        "token_category": None,
+                        "fungible_token_amount": None,
+                        "nonfungible_token_capability": None,
+                        "nonfungible_token_commitment": None,
+                        "locking_bytecode": "\\x76a9148ee26d6c9f58369f94864dc3630cdeb17fae2f2d88ac",
+                        "transaction": {"block_inclusions": []},
+                    },
+                ],
+            }
+        }
+        self.monkeypatch.setattr(_capi, "session", DummySession(return_json))
+        unspents = self.api.get_unspent(BITCOIN_CASHADDRESS_CATKN)
+        script = "76a9148ee26d6c9f58369f94864dc3630cdeb17fae2f2d88ac"
+        assert unspents == [
+            Unspent(
+                1000,
+                1265,
+                script,
+                "8aa279c9c46a812273c12fe78efff995ab6493cffb130ef54da73d4268a1bc9f",
+                0,
+                "b3d668379a421820fe89cf1bda4bfd7295202a516a0fa5ca0c8011e4c2fc256d",
+                "none",
+                b"\n",
+                None,
+            ),
+            Unspent(
+                1000,
+                1265,
+                script,
+                "9aa279c9c46a812273c12fe78efff995ab6493cffb130ef54da73d4268a1bc9f",
+                0,
+                "c3d668379a421820fe89cf1bda4bfd7295202a516a0fa5ca0c8011e4c2fc256d",
+                "none",
+                None,
+                None,
+            ),
+            Unspent(
+                1000,
+                1262,
+                script,
+                "1c04b42cdd4fe595040a478315c31d9276abcb00cf8e7d2f9e52f81bade279a3",
+                0,
+                "55255e66ab1280fae24896c084c360d5027c1b4ef5b1a5588c4b7af246fdcf7a",
+                None,
+                None,
+                1000,
+            ),
+            Unspent(
+                2512699,
+                4,
+                script,
+                "5b2f18d2c214560c4fa21dd2ff18bfa2126e6693dde20d5c516fbaf56c634fdd",
+                1,
+                None,
+                None,
+                None,
+                None,
+            ),
+            Unspent(
+                2512699,
+                0,
+                script,
+                "6b2f18d2c214560c4fa21dd2ff18bfa2126e6693dde20d5c516fbaf56c634fdd",
+                1,
+                None,
+                None,
+                None,
+                None,
+            ),
+        ]
+
+        # zero return
+        return_json = {"data": {"block": [{"height": "794046"}], "search_output": []}}
+        self.monkeypatch.setattr(_capi, "session", DummySession(return_json))
+        unspents = self.api.get_unspent(BITCOIN_CASHADDRESS_CATKN)
+        assert unspents == []
+
+    def test_get_raw_transaction(self):
+        return_json = {"data": {"transaction": [{"dummy": "dummy"}]}}
+        self.monkeypatch.setattr(_capi, "session", DummySession(return_json))
+        tx = self.api.get_raw_transaction(
+            "446f83e975d2870de740917df1b5221aa4bc52c6e2540188f5897c4ce775b7f4",
+        )
+        assert tx == {"dummy": "dummy"}
+
+        # zero return
+        return_json = {"data": {"transaction": []}}
+        self.monkeypatch.setattr(_capi, "session", DummySession(return_json))
+        with pytest.raises(RuntimeError):
+            # a tx that does not exist
+            tx = self.api.get_raw_transaction(
+                "546f83e975d2870de740917df1b5221aa4bc52c6e2540188f5897c4ce775b7f4",
+            )
diff --git a/tests/network/test_meta.py b/tests/network/test_meta.py
index aef7980a..162da1a2 100644
--- a/tests/network/test_meta.py
+++ b/tests/network/test_meta.py
@@ -3,12 +3,22 @@
 
 class TestUnspent:
     def test_init(self):
-        unspent = Unspent(10000, 7, "script", "txid", 0)
+        unspent = Unspent(
+            10000, 7, "script", "txid", 0, "category_id", "none", "nft_commitment", 50
+        )
         assert unspent.amount == 10000
         assert unspent.confirmations == 7
         assert unspent.script == "script"
         assert unspent.txid == "txid"
         assert unspent.txindex == 0
+        assert unspent.category_id == "category_id"
+        assert unspent.nft_commitment == "nft_commitment"
+        assert unspent.nft_capability == "none"
+        assert unspent.token_amount == 50
+        # CashToken properties
+        assert unspent.has_amount is True
+        assert unspent.has_nft is True
+        assert unspent.has_cashtoken is True
 
     def test_dict_conversion(self):
         unspent = Unspent(10000, 7, "script", "txid", 0)
@@ -29,3 +39,31 @@ def test_repr(self):
             "Unspent(amount=10000, confirmations=7, "
             "script='script', txid='txid', txindex=0)"
         )
+
+    def test_gt(self):
+        unspent = Unspent(10000, 7, "script", "txid", 0)
+        unspent1 = Unspent(20000, 7, "script", "txid", 0)
+        unspent2 = Unspent(10000, 7, "script", "txid", 0, "category_id", "none")
+        unspent3 = Unspent(30000, 7, "script", "txid", 0, "category_id", "none")
+        unspent4 = Unspent(10000, 7, "script", "txid", 0, "category_id", "mutable")
+        unspent5 = Unspent(
+            20000, 7, "script", "txid", 0, "category_id", token_amount=50
+        )
+        unspent6 = Unspent(
+            20000, 7, "script", "txid", 0, "category_id", token_amount=20
+        )
+        unspent7 = Unspent(
+            30000, 7, "script", "txid", 0, "category_id", token_amount=20
+        )
+
+        assert unspent1 > unspent
+        assert unspent2 > unspent
+        assert unspent4 > unspent2
+        assert not unspent2 > unspent4
+        assert not unspent > unspent2
+        assert unspent3 > unspent2
+        assert unspent5 > unspent
+        assert not unspent > unspent5
+        assert unspent5 > unspent7
+        assert not unspent6 > unspent5
+        assert unspent7 > unspent6
diff --git a/tests/network/test_services.py b/tests/network/test_services.py
index d470223c..efef3a2f 100644
--- a/tests/network/test_services.py
+++ b/tests/network/test_services.py
@@ -6,6 +6,7 @@
 from bitcash.network.meta import Unspent
 from bitcash.network.services import (
     BitcoinDotComAPI,
+    ChaingraphAPI,
     NetworkAPI,
     get_endpoints_for,
     set_service_timeout,
@@ -124,7 +125,8 @@ def test_get_raw_transaction_mainnet(self):
         time.sleep(1)
         results = NetworkAPI.get_raw_transaction(MAIN_TX, network="mainnet")
         assert isinstance(results, dict)
-        assert len(results) == 16
+        # assert len(results) == 16  # BitcoinDotCOM
+        assert len(results) == 7  # Chaingraph
 
     # Testnet
     @pytest.mark.skip
@@ -177,19 +179,47 @@ def test_invalid_endpoint_url_mainnet(self):
     def test_get_single_endpoint_for_env_variable(self):
         os.environ["BITCOINCOM_API_MAINNET"] = VALID_ENDPOINT_URLS[0]
         endpoints = get_endpoints_for("mainnet")
-        assert len(endpoints) == 1
-        assert isinstance(endpoints[0], BitcoinDotComAPI)
+        assert len(endpoints) == 3
+        assert isinstance(endpoints[0], ChaingraphAPI)  # default
+        assert isinstance(endpoints[1], ChaingraphAPI)  # default
+        assert isinstance(endpoints[2], BitcoinDotComAPI)  # env
         os.environ.pop("BITCOINCOM_API_MAINNET")
+        os.environ["CHAINGRAPH_API"] = VALID_ENDPOINT_URLS[0]
+        os.environ["CHAINGRAPH_API_MAINNET"] = "%mainnet"
+        endpoints = get_endpoints_for("mainnet")
+        assert len(endpoints) == 3
+        assert isinstance(endpoints[0], ChaingraphAPI)  # env
+        assert isinstance(endpoints[1], BitcoinDotComAPI)  # default
+        assert isinstance(endpoints[2], BitcoinDotComAPI)  # default
+        assert endpoints[0].node_like == "%mainnet"
+        os.environ.pop("CHAINGRAPH_API")
+        os.environ.pop("CHAINGRAPH_API_MAINNET")
 
     def test_get_multiple_endpoint_for_env_variable(self):
         os.environ["BITCOINCOM_API_MAINNET_1"] = VALID_ENDPOINT_URLS[0]
         os.environ["BITCOINCOM_API_MAINNET_2"] = VALID_ENDPOINT_URLS[1]
         endpoints = get_endpoints_for("mainnet")
-        assert len(endpoints) == 2
-        assert isinstance(endpoints[0], BitcoinDotComAPI)
-        assert isinstance(endpoints[1], BitcoinDotComAPI)
+        assert len(endpoints) == 4
+        assert isinstance(endpoints[0], ChaingraphAPI)  # default
+        assert isinstance(endpoints[1], ChaingraphAPI)  # default
+        assert isinstance(endpoints[2], BitcoinDotComAPI)  # env
+        assert isinstance(endpoints[3], BitcoinDotComAPI)  # env
         os.environ.pop("BITCOINCOM_API_MAINNET_1")
         os.environ.pop("BITCOINCOM_API_MAINNET_2")
+        os.environ["CHAINGRAPH_API_1"] = VALID_ENDPOINT_URLS[0]
+        os.environ["CHAINGRAPH_API_2"] = VALID_ENDPOINT_URLS[1]
+        os.environ["CHAINGRAPH_API_MAINNET_2"] = "%mainnet"
+        endpoints = get_endpoints_for("mainnet")
+        assert len(endpoints) == 4
+        assert isinstance(endpoints[0], ChaingraphAPI)  # default
+        assert isinstance(endpoints[1], ChaingraphAPI)  # default
+        assert isinstance(endpoints[2], BitcoinDotComAPI)  # env
+        assert isinstance(endpoints[3], BitcoinDotComAPI)  # env
+        assert endpoints[0].node_like == "%"
+        assert endpoints[1].node_like == "%mainnet"
+        os.environ.pop("CHAINGRAPH_API_1")
+        os.environ.pop("CHAINGRAPH_API_2")
+        os.environ.pop("CHAINGRAPH_API_MAINNET_2")
 
     def test_get_balance_mainnet_return_type(self):
         time.sleep(1)
diff --git a/tests/samples.py b/tests/samples.py
index 81eff02b..17122083 100644
--- a/tests/samples.py
+++ b/tests/samples.py
@@ -1,30 +1,35 @@
 BINARY_ADDRESS = b"\x00\x92F\x1b\xdeb\x83\xb4a\xec\xe7\xdd\xf4\xdb\xf1\xe0\xa4\x8b\xd1\x13\xd8&E\xb4\xbf"
 BITCOIN_ADDRESS = "1ELReFsTCUY2mfaDTy32qxYiT49z786eFg"
 BITCOIN_ADDRESS_COMPRESSED = "1ExJJsNLQDNVVM1s1sdyt1o5P3GC5r32UG"
-BITCOIN_ADDRESS_PAY2SH = "39SrGQEfFXcTYJhBvjZeQja66Cpz82EEUn"
+BITCOIN_ADDRESS_PAY2SH20 = "39SrGQEfFXcTYJhBvjZeQja66Cpz82EEUn"
 BITCOIN_ADDRESS_TEST = "mtrNwJxS1VyHYn3qBY1Qfsm3K3kh1mGRMS"
 BITCOIN_ADDRESS_TEST_COMPRESSED = "muUFbvTKDEokGTVUjScMhw1QF2rtv5hxCz"
-BITCOIN_ADDRESS_TEST_PAY2SH = "2NFKbBHzzh32q5DcZJNgZE9sF7gYmtPbawk"
+BITCOIN_ADDRESS_TEST_PAY2SH20 = "2NFKbBHzzh32q5DcZJNgZE9sF7gYmtPbawk"
 BITCOIN_ADDRESS_REGTEST = "mtrNwJxS1VyHYn3qBY1Qfsm3K3kh1mGRMS"
 BITCOIN_ADDRESS_REGTEST_COMPRESSED = "muUFbvTKDEokGTVUjScMhw1QF2rtv5hxCz"
-BITCOIN_ADDRESS_REGTEST_PAY2SH = "2NFKbBHzzh32q5DcZJNgZE9sF7gYmtPbawk"
+BITCOIN_ADDRESS_REGTEST_PAY2SH20 = "2NFKbBHzzh32q5DcZJNgZE9sF7gYmtPbawk"
 BITCOIN_CASHADDRESS = "bitcoincash:qzfyvx77v2pmgc0vulwlfkl3uzjgh5gnmqk5hhyaa6"
 BITCOIN_CASHADDRESS_COMPRESSED = (
     "bitcoincash:qzvsaasdvw6mt9j2rs3gyps673gj86flev4sthhcc0"
 )
-BITCOIN_CASHADDRESS_PAY2SH = "bitcoincash:pp23x8hm0g8d6nrkesamaqeml3v6daeudvpa7zhktf"
+BITCOIN_CASHADDRESS_CATKN = "bitcoincash:zzfyvx77v2pmgc0vulwlfkl3uzjgh5gnmq37yf2mzf"
+BITCOIN_CASHADDRESS_PAY2SH20 = "bitcoincash:pp23x8hm0g8d6nrkesamaqeml3v6daeudvpa7zhktf"
+BITCOIN_CASHADDRESS_PAY2SH32 = "bitcoincash:pvch8mmxy0rtfrlarg7ucrxxfzds5pamg73h7370aa87d80gyhqxqaw3dsfwg"
 
 BITCOIN_CASHADDRESS_TEST = "bchtest:qzfyvx77v2pmgc0vulwlfkl3uzjgh5gnmqjxnsx26x"
 BITCOIN_CASHADDRESS_TEST_COMPRESSED = (
     "bchtest:qzvsaasdvw6mt9j2rs3gyps673gj86flev3z0s40ln"
 )
-BITCOIN_CASHADDRESS_TEST_PAY2SH = "bchtest:pp23x8hm0g8d6nrkesamaqeml3v6daeudv90694pv4"
+BITCOIN_CASHADDRESS_TEST_CATKN = "bchtest:zzfyvx77v2pmgc0vulwlfkl3uzjgh5gnmq4vqwgv94"
+BITCOIN_CASHADDRESS_TEST_PAY2SH20 = "bchtest:pp23x8hm0g8d6nrkesamaqeml3v6daeudv90694pv4"
+BITCOIN_CASHADDRESS_TEST_PAY2SH32 = "bchtest:pvch8mmxy0rtfrlarg7ucrxxfzds5pamg73h7370aa87d80gyhqxq7fqng6m6"
 
 BITCOIN_CASHADDRESS_REGTEST = "bchreg:qzfyvx77v2pmgc0vulwlfkl3uzjgh5gnmqg6939eeq"
 BITCOIN_CASHADDRESS_REGTEST_COMPRESSED = (
     "bchreg:qzvsaasdvw6mt9j2rs3gyps673gj86flevt7e3kuu4"
 )
-BITCOIN_CASHADDRESS_REGTEST_PAY2SH = "bchreg:pp23x8hm0g8d6nrkesamaqeml3v6daeudvlnvykj0n"
+BITCOIN_CASHADDRESS_REGTEST_CATKN = "bchreg:zzfyvx77v2pmgc0vulwlfkl3uzjgh5gnmq0sk0tlxn"
+BITCOIN_CASHADDRESS_REGTEST_PAY2SH20 = "bchreg:pp23x8hm0g8d6nrkesamaqeml3v6daeudvlnvykj0n"
 
 VALID_ENDPOINT_URLS = [
     "https://rest.bch.actorforth.org/v2/",
@@ -57,7 +62,8 @@
 
 PUBKEY_HASH = b"\x92F\x1b\xdeb\x83\xb4a\xec\xe7\xdd\xf4\xdb\xf1\xe0\xa4\x8b\xd1\x13\xd8"
 PUBKEY_HASH_COMPRESSED = b'\x99\x0e\xf6\rc\xb5\xb5\x96J\x1c"\x82\x06\x1a\xf4Q#\xe9?\xcb'
-PUBKEY_HASH_P2SH = b"U\x13\x1e\xfbz\x0e\xddLv\xcc;\xbe\x83;\xfcY\xa6\xf7<k"
+PUBKEY_HASH_P2SH20 = b"U\x13\x1e\xfbz\x0e\xddLv\xcc;\xbe\x83;\xfcY\xa6\xf7<k"
+PUBKEY_HASH_P2SH32 = b"1s\xeff#\xc6\xb4\x8f\xfd\x1a=\xcc\x0c\xc6H\x9b\n\x07\xbbG\xa3\x7fG\xcf\xefO\xe6\x9d\xe8%\xc0`"
 PUBLIC_KEY_COMPRESSED = b"\x03=\\(u\xc9\xbd\x11hu\xa7\x1a]\xb6L\xff\xcb\x139k\x16=\x03\x9b\x1d\x93'\x82H\x91\x80C4"
 PUBLIC_KEY_UNCOMPRESSED = (
     b"\x04=\\(u\xc9\xbd\x11hu\xa7\x1a]\xb6L\xff\xcb\x139k\x16=\x03"
@@ -160,3 +166,15 @@
     19,
     27,
 ]
+
+
+# CashToken prefixes
+CASHTOKEN_CATAGORY_ID = "00fb7b8704f843caf33c436e3386a469e1d004403c388a8b054282d02034f598"
+CASHTOKEN_CAPABILITY = "none"
+CASHTOKEN_COMMITMENT = b"commitment"
+CASHTOKEN_AMOUNT = 50
+PREFIX_CAPABILITY = b'\xef\x98\xf54 \xd0\x82B\x05\x8b\x8a8<@\x04\xd0\xe1i\xa4\x863nC<\xf3\xcaC\xf8\x04\x87{\xfb\x00 '
+PREFIX_CAPABILITY_AMOUNT = b'\xef\x98\xf54 \xd0\x82B\x05\x8b\x8a8<@\x04\xd0\xe1i\xa4\x863nC<\xf3\xcaC\xf8\x04\x87{\xfb\x0002'
+PREFIX_CAPABILITY_COMMITMENT = b'\xef\x98\xf54 \xd0\x82B\x05\x8b\x8a8<@\x04\xd0\xe1i\xa4\x863nC<\xf3\xcaC\xf8\x04\x87{\xfb\x00`\ncommitment'
+PREFIX_CAPABILITY_COMMITMENT_AMOUNT = b'\xef\x98\xf54 \xd0\x82B\x05\x8b\x8a8<@\x04\xd0\xe1i\xa4\x863nC<\xf3\xcaC\xf8\x04\x87{\xfb\x00p\ncommitment2'
+PREFIX_AMOUNT = b'\xef\x98\xf54 \xd0\x82B\x05\x8b\x8a8<@\x04\xd0\xe1i\xa4\x863nC<\xf3\xcaC\xf8\x04\x87{\xfb\x00\x102'
diff --git a/tests/test_cashaddress.py b/tests/test_cashaddress.py
index 38724f18..cddbce1a 100644
--- a/tests/test_cashaddress.py
+++ b/tests/test_cashaddress.py
@@ -26,6 +26,14 @@
     CONVERT_BITS_INVALID_DATA_PAYLOAD,
     CONVERT_BITS_NO_PAD_PAYLOAD,
     CONVERT_BITS_NO_PAD_RETURN,
+    BITCOIN_CASHADDRESS_PAY2SH20,
+    BITCOIN_CASHADDRESS_PAY2SH32,
+    BITCOIN_CASHADDRESS_CATKN,
+    PREFIX_AMOUNT,
+    PREFIX_CAPABILITY,
+    PREFIX_CAPABILITY_AMOUNT,
+    PREFIX_CAPABILITY_COMMITMENT,
+    PREFIX_CAPABILITY_COMMITMENT_AMOUNT,
 )
 
 
@@ -224,6 +232,33 @@ def test_eq(self):
         with pytest.raises(ValueError):
             address == 1
 
+    def test_to_from_script(self):
+        address = Address.from_string(BITCOIN_CASHADDRESS)
+        assert address == Address.from_script(address.scriptcode)
+
+        address = Address.from_string(BITCOIN_CASHADDRESS_PAY2SH20)
+        assert address == Address.from_script(address.scriptcode)
+
+        address = Address.from_string(BITCOIN_CASHADDRESS_PAY2SH32)
+        assert address == Address.from_script(address.scriptcode)
+
+        # cashtoken
+        address = Address.from_string(BITCOIN_CASHADDRESS)
+        address_catkn = Address.from_string(BITCOIN_CASHADDRESS_CATKN)
+        # no cashtoken data
+        assert address == Address.from_script(address_catkn.scriptcode)
+        # with cashtoken data
+        for script in [
+            PREFIX_AMOUNT,
+            PREFIX_CAPABILITY,
+            PREFIX_CAPABILITY_AMOUNT,
+            PREFIX_CAPABILITY_COMMITMENT,
+            PREFIX_CAPABILITY_COMMITMENT_AMOUNT,
+        ]:
+            assert address_catkn == Address.from_script(
+                script + address_catkn.scriptcode
+            )
+
 
 def test_parse_cashaddress():
     # good address
diff --git a/tests/test_cashtoken.py b/tests/test_cashtoken.py
new file mode 100644
index 00000000..56972063
--- /dev/null
+++ b/tests/test_cashtoken.py
@@ -0,0 +1,587 @@
+import pytest
+import json
+import pathlib
+
+
+from _pytest.monkeypatch import MonkeyPatch
+from bitcash import cashtoken as _cashtoken
+from bitcash.network.meta import Unspent
+from bitcash.cashtoken import (
+    verify_cashtoken_output_data,
+    parse_cashtoken_prefix,
+    generate_cashtoken_prefix,
+    prepare_output,
+    Unspents,
+    select_cashtoken_utxo,
+    _calculate_dust_value
+)
+from bitcash.exceptions import InsufficientFunds, InvalidCashToken, InvalidAddress
+from bitcash.cashaddress import Address
+from .samples import (
+    CASHTOKEN_CATAGORY_ID,
+    CASHTOKEN_CAPABILITY,
+    CASHTOKEN_COMMITMENT,
+    CASHTOKEN_AMOUNT,
+    PREFIX_CAPABILITY,
+    PREFIX_CAPABILITY_AMOUNT,
+    PREFIX_CAPABILITY_COMMITMENT,
+    PREFIX_CAPABILITY_COMMITMENT_AMOUNT,
+    PREFIX_AMOUNT,
+    BITCOIN_CASHADDRESS,
+    BITCOIN_CASHADDRESS_CATKN,
+)
+
+
+# read token-prefix-valid.json
+# test vectors from https://github.com/bitjson/cashtokens
+@pytest.fixture
+def test_vectors(request):
+    file = pathlib.Path(request.node.fspath.strpath)
+    config = file.with_name("token-prefix-valid.json")
+    with config.open() as fio:
+        data = json.load(fio)
+    return data
+
+
+def test_verify_cashtoken_output_data():
+    # test bad inputs
+    # missing cashtoken fields
+    with pytest.raises(InvalidCashToken):
+        verify_cashtoken_output_data(CASHTOKEN_CATAGORY_ID)
+    # bad capability
+    with pytest.raises(InvalidCashToken):
+        verify_cashtoken_output_data(CASHTOKEN_CATAGORY_ID, "bad_capability")
+    # bad commitment
+    with pytest.raises(InvalidCashToken):
+        verify_cashtoken_output_data(
+            CASHTOKEN_CATAGORY_ID, nft_commitment=b"no capability"
+        )
+    with pytest.raises(ValueError):
+        verify_cashtoken_output_data(
+            CASHTOKEN_CATAGORY_ID, CASHTOKEN_CAPABILITY, "str_commitment"
+        )
+    with pytest.raises(InvalidCashToken):
+        verify_cashtoken_output_data(
+            CASHTOKEN_CATAGORY_ID,
+            CASHTOKEN_CAPABILITY,
+            b"bad_length" * 40,
+        )
+    with pytest.raises(InvalidCashToken):
+        verify_cashtoken_output_data(
+            CASHTOKEN_CATAGORY_ID,
+            CASHTOKEN_CAPABILITY,
+            b"",
+        )
+    # bad token_amount
+    with pytest.raises(InvalidCashToken):
+        verify_cashtoken_output_data(CASHTOKEN_CATAGORY_ID, token_amount=0)
+    with pytest.raises(InvalidCashToken):
+        verify_cashtoken_output_data(
+            CASHTOKEN_CATAGORY_ID, token_amount=9223372036854775808
+        )
+
+
+def test_cashtoken_prefix_script(test_vectors):
+    for script in [
+        PREFIX_CAPABILITY,
+        PREFIX_CAPABILITY_AMOUNT,
+        PREFIX_CAPABILITY_COMMITMENT,
+        PREFIX_CAPABILITY_COMMITMENT_AMOUNT,
+        PREFIX_AMOUNT,
+        b"",
+    ]:
+        cashtoken = parse_cashtoken_prefix(script)
+        assert script == generate_cashtoken_prefix(*cashtoken)
+
+    # test vectors from https://github.com/bitjson/cashtokens
+    # change COMMITMENT_LENGTH
+    COMMITMENT_LENGTH = 1500
+    monkeypatch = MonkeyPatch()
+    monkeypatch.setattr(_cashtoken, "COMMITMENT_LENGTH", COMMITMENT_LENGTH)
+    for test_vector in test_vectors:
+        script = bytes.fromhex(test_vector["prefix"])
+        category_id = test_vector["data"]["category"]
+        token_amount = int(test_vector["data"]["amount"])
+        nft = test_vector["data"].get("nft", None)
+        if nft is None:
+            nft_capability = None
+            nft_commitment = None
+        else:
+            nft_capability = test_vector["data"]["nft"]["capability"]
+            nft_commitment = test_vector["data"]["nft"]["commitment"]
+            nft_commitment = bytes.fromhex(nft_commitment)
+            if nft_commitment == b"":
+                nft_commitment = None
+        if token_amount == 0:
+            token_amount = None
+        assert parse_cashtoken_prefix(script) == (
+            category_id,
+            nft_capability,
+            nft_commitment,
+            token_amount,
+        )
+
+
+class TestPrepareOutput:
+    def test_output(self):
+        output = (BITCOIN_CASHADDRESS, 20, "bch")
+        output = prepare_output(output)
+        _ = Address.from_string(BITCOIN_CASHADDRESS_CATKN).scriptcode
+        assert output == (_, 2000000000, None, None, None, None)
+
+        cashtoken = (
+            CASHTOKEN_CATAGORY_ID,
+            CASHTOKEN_CAPABILITY,
+            CASHTOKEN_COMMITMENT,
+            CASHTOKEN_AMOUNT,
+        )
+        output = (
+            BITCOIN_CASHADDRESS_CATKN,
+            20,
+            "bch",
+            *cashtoken,
+        )
+        output = prepare_output(output)
+        assert output == (
+            (
+                generate_cashtoken_prefix(*cashtoken)
+                + Address.from_string(BITCOIN_CASHADDRESS_CATKN).scriptcode
+            ),
+            2000000000,
+            *cashtoken,
+        )
+
+        # already prepared
+        output == prepare_output(output)
+        # bad length
+        with pytest.raises(RuntimeError):
+            output = prepare_output(output[1:])
+        # bad prepared out
+        with pytest.raises(RuntimeError):
+            output = ("", *output[1:])
+            output = prepare_output(output)
+
+    def test_token_signal(self):
+        output = (BITCOIN_CASHADDRESS, 20, "bch", "341234", "none", None, None)
+        with pytest.raises(InvalidAddress):
+            prepare_output(output)
+
+    def test_dust_limit(self):
+        output = (BITCOIN_CASHADDRESS, 20, "satoshi")
+        with pytest.raises(InsufficientFunds):
+            prepare_output(output)
+
+
+class TestUnspents:
+    def test_empty(self):
+        unspents = [Unspent(1000, 42, "script", "txid", 0)]
+        cashtoken = Unspents(unspents)
+        assert cashtoken.tokendata == {}
+        assert cashtoken.amount == 1000
+
+    def test_multi_amounts(self):
+        tokendata = {
+            "category1": {"token_amount": 50},
+            "category2": {"token_amount": 30},
+        }
+        unspents = [
+            Unspent(1000, 42, "script", "txid", 0, "category1", token_amount=25),
+            Unspent(1000, 42, "script", "txid", 0, "category1", token_amount=25),
+            Unspent(1000, 42, "script", "txid", 0, "category2", token_amount=30),
+        ]
+        cashtoken = Unspents(unspents)
+        assert tokendata == cashtoken.tokendata
+        assert cashtoken.amount == 3000
+
+    def test_multi_nfts(self):
+        tokendata = {
+            "category1": {
+                "nft": [
+                    {"capability": "mutable"},
+                    {"capability": "none", "commitment": b"commitment"},
+                ]
+            },
+            "category2": {"nft": [{"capability": "minting"}]},
+        }
+        unspents = [
+            Unspent(
+                1000, 42, "script", "txid", 0, "category1", nft_capability="mutable"
+            ),
+            Unspent(
+                1000,
+                42,
+                "script",
+                "txid",
+                0,
+                "category1",
+                nft_capability="none",
+                nft_commitment=b"commitment",
+            ),
+            Unspent(
+                1000, 42, "script", "txid", 0, "category2", nft_capability="minting"
+            ),
+        ]
+        cashtoken = Unspents(unspents)
+        assert tokendata == cashtoken.tokendata
+        assert cashtoken.amount == 3000
+
+    def test_all(self):
+        tokendata = {
+            "category1": {
+                "nft": [
+                    {"capability": "mutable"},
+                    {"capability": "none", "commitment": b"commitment"},
+                ]
+            },
+            "category2": {
+                "token_amount": 50,
+                "nft": [{"capability": "minting"}, {"capability": "minting"}],
+            },
+        }
+        unspents = [
+            Unspent(
+                1000, 42, "script", "txid", 0, "category1", nft_capability="mutable"
+            ),
+            Unspent(
+                1000,
+                42,
+                "script",
+                "txid",
+                0,
+                "category1",
+                nft_capability="none",
+                nft_commitment=b"commitment",
+            ),
+            Unspent(
+                1000, 42, "script", "txid", 0, "category2", nft_capability="minting"
+            ),
+            Unspent(1000, 42, "script", "txid", 0, "category2", token_amount=25),
+            Unspent(
+                1000,
+                42,
+                "script",
+                "txid",
+                0,
+                "category2",
+                nft_capability="minting",
+                token_amount=25,
+            ),
+        ]
+        cashtoken = Unspents(unspents)
+        assert tokendata == cashtoken.tokendata
+        assert cashtoken.amount == 5000
+
+    def test_subtract(self):
+        tokendata = {
+            "category1": {
+                "nft": [
+                    {"capability": "mutable"},
+                    {"capability": "none", "commitment": b"commitment"},
+                ]
+            },
+            "category2": {
+                "token_amount": 50,
+                "nft": [{"capability": "minting"}, {"capability": "minting"}],
+            },
+            "category3": {"token_amount": 50},
+            "category4": {"nft": [{"capability": "none"}]},
+        }
+
+        # No token
+        cashtoken = Unspents([])
+        cashtoken.amount = 1000
+        cashtoken.tokendata = tokendata
+        cashtoken.subtract_output((b"", 500, None, None, None, None))
+        assert cashtoken.amount == 500
+        assert cashtoken.tokendata == tokendata
+
+        # New token
+        cashtoken = Unspents(
+            [
+                Unspent(500, 12, "script", "category_new", 0),
+                Unspent(500, 12, "script", "txid", 2, "category1", "minting"),
+            ]
+        )
+        cashtoken.subtract_output((b"", 500, "category_new", "none", None, 30))
+        assert cashtoken.amount == 500
+        assert cashtoken.tokendata == {
+            "category1": {"nft": [{"capability": "minting"}]}
+        }
+
+        # raise errors
+        # bad genesis
+        with pytest.raises(InsufficientFunds):
+            cashtoken = Unspents(
+                [
+                    Unspent(500, 12, "script", "category_new", 1),
+                ]
+            )
+            cashtoken.subtract_output((b"", 500, "category_new", "none", None, 30))
+        cashtoken = Unspents([])
+        cashtoken.amount = 1000
+        cashtoken.tokendata = tokendata
+        # category does not exist
+        with pytest.raises(InsufficientFunds):
+            cashtoken.subtract_output((b"", 500, "category0", "mutable", None, None))
+        # bad token amount
+        with pytest.raises(InsufficientFunds):
+            cashtoken.subtract_output((b"", 500, "category1", None, None, 50))
+        with pytest.raises(InsufficientFunds):
+            cashtoken.subtract_output((b"", 500, "category2", None, None, 500))
+        # bad nft
+        with pytest.raises(InsufficientFunds):
+            cashtoken.subtract_output((b"", 500, "category3", "mutable", None, None))
+        with pytest.raises(InsufficientFunds):
+            cashtoken.subtract_output(
+                (b"", 500, "category4", "none", b"commitment", None)
+            )
+        with pytest.raises(InsufficientFunds):
+            cashtoken.subtract_output(
+                (b"", 500, "category4", "mutable", b"commitment", None)
+            )
+        with pytest.raises(InsufficientFunds):
+            cashtoken.subtract_output(
+                (b"", 500, "category4", "minting", b"commitment", None)
+            )
+
+        # simple subtraction
+        cashtoken = Unspents([])
+        cashtoken.amount = 500
+        cashtoken.subtract_output((b"", 500, None, None, None, None))
+        assert cashtoken.amount == 0
+
+        # fine tune subtraction
+        tokendata = {"category": {"token_amount": 50, "nft": [{"capability": "none"}]}}
+        cashtoken = Unspents([])
+        cashtoken.amount = 1000
+        cashtoken.tokendata = tokendata
+        cashtoken.subtract_output((b"", 500, "category", None, None, 50))
+        assert cashtoken.tokendata == {"category": {"nft": [{"capability": "none"}]}}
+        cashtoken.subtract_output((b"", 50, "category", "none", None, None))
+        assert cashtoken.tokendata == {}
+
+        tokendata = {"category": {"token_amount": 50}}
+        cashtoken = Unspents([])
+        cashtoken.amount = 1000
+        cashtoken.tokendata = tokendata
+        cashtoken.subtract_output((b"", 500, "category", None, None, 50))
+        assert cashtoken.tokendata == {}
+
+        tokendata = {
+            "category": {
+                "nft": [
+                    {"capability": "none"},
+                    {"capability": "none", "commitment": b"commitment"},
+                ]
+            }
+        }
+        cashtoken = Unspents([])
+        cashtoken.amount = 1000
+        cashtoken.tokendata = tokendata
+        cashtoken.subtract_output((b"", 500, "category", "none", b"commitment", None))
+        assert cashtoken.tokendata == {"category": {"nft": [{"capability": "none"}]}}
+
+        tokendata = {"category": {"nft": [{"capability": "mutable"}]}}
+        cashtoken = Unspents([])
+        cashtoken.amount = 1000
+        cashtoken.tokendata = tokendata
+        cashtoken.subtract_output((b"", 500, "category", "none", b"commitment", None))
+        assert cashtoken.tokendata == {}
+
+        tokendata = {"category": {"nft": [{"capability": "minting"}]}}
+        cashtoken = Unspents([])
+        cashtoken.amount = 1000
+        cashtoken.tokendata = tokendata
+        cashtoken.subtract_output((b"", 500, "category", "none", b"commitment", None))
+        assert cashtoken.tokendata == tokendata
+
+        tokendata = {"category": {"nft": [{"capability": "mutable"}]}}
+        cashtoken = Unspents([])
+        cashtoken.amount = 1000
+        cashtoken.tokendata = tokendata
+        cashtoken.subtract_output(
+            (b"", 500, "category", "mutable", b"commitment", None)
+        )
+        assert cashtoken.tokendata == {}
+
+        tokendata = {"category": {"nft": [{"capability": "minting"}]}}
+        cashtoken = Unspents([])
+        cashtoken.amount = 1000
+        cashtoken.tokendata = tokendata
+        cashtoken.subtract_output(
+            (b"", 500, "category", "mutable", b"commitment", None)
+        )
+        assert cashtoken.tokendata == tokendata
+
+        tokendata = {"category": {"nft": [{"capability": "minting"}]}}
+        cashtoken = Unspents([])
+        cashtoken.amount = 1000
+        cashtoken.tokendata = tokendata
+        cashtoken.subtract_output(
+            (b"", 500, "category", "minting", b"commitment", None)
+        )
+        assert cashtoken.tokendata == tokendata
+
+    def test_get_outputs(self):
+        tokendata = {
+            "c1": {
+                "nft": [
+                    {"capability": "mutable"},
+                    {"capability": "none", "commitment": b"commitment"},
+                ]
+            },
+            "c2": {
+                "token_amount": 50,
+                "nft": [{"capability": "minting"}, {"capability": "minting"}],
+            },
+            "c3": {"token_amount": 50},
+            "c4": {"nft": [{"capability": "none"}]},
+        }
+
+        cashtokenoutput = [None for i in range(6)]
+        cashtokenoutput[0] = (546, "c1", "mutable", None, None)
+        cashtokenoutput[1] = (546, "c1", "none", b"commitment", None)
+        cashtokenoutput[2] = (546, "c2", "minting", None, 50)
+        cashtokenoutput[3] = (546, "c2", "minting", None, None)
+        cashtokenoutput[4] = (546, "c3", None, None, 50)
+        cashtokenoutput[5] = (546, "c4", "none", None, None)
+        for i in range(6):
+            dust = _calculate_dust_value(
+                BITCOIN_CASHADDRESS_CATKN,
+                *cashtokenoutput[i][1:]
+            )
+            _ = list(cashtokenoutput[i])
+            _[0] = dust
+            cashtokenoutput[i] = tuple(_)
+
+        cashtoken = Unspents([])
+        cashtoken.amount = sum([_[0] for _ in cashtokenoutput])
+        cashtoken.tokendata = tokendata
+        (outputs, leftover_amount) = cashtoken.get_outputs(BITCOIN_CASHADDRESS_CATKN)
+
+        assert len(outputs) == 6
+        assert outputs[0][1:] == cashtokenoutput[0]
+        assert outputs[1][1:] == cashtokenoutput[1]
+        assert outputs[2][1:] == cashtokenoutput[2]
+        assert outputs[3][1:] == cashtokenoutput[3]
+        assert outputs[4][1:] == cashtokenoutput[4]
+        assert outputs[5][1:] == cashtokenoutput[5]
+        assert leftover_amount == 0
+
+        cashtoken = Unspents([])
+        cashtoken.amount = 546
+        (outputs, leftover_amount) = cashtoken.get_outputs(BITCOIN_CASHADDRESS_CATKN)
+
+        assert len(outputs) == 1
+        assert outputs[0][1:] == (546, None, None, None, None)
+        assert leftover_amount == 546
+
+
+def test_select_cashtoken_utxo():
+    unspent1 = Unspent(50, 1234, "script", "txid", 1, "c1", "minting")
+    unspent2 = Unspent(50, 1234, "script", "txid", 1, "c1", "none")
+    unspent3 = Unspent(50, 1234, "script", "txid", 1, "c1", "mutable")
+    unspent4 = Unspent(50, 1234, "script", "c2", 1)
+    unspent41 = Unspent(50, 1234, "script", "c2", 0)  # genesis
+    unspent5 = Unspent(50, 1234, "script", "txid", 1, "c2", "mutable")
+    unspent6 = Unspent(50, 1234, "script", "txid", 1, "c1", "none", b"commitment")
+    unspent7 = Unspent(50, 1234, "script", "txid", 1, "c1", None, None, 10)
+    unspent8 = Unspent(50, 1234, "script", "txid", 1, "c1", "mutable", None, 10)
+    unspent9 = Unspent(50, 1234, "script", "txid", 1, "c1", None, None, 60)
+
+    output1 = (b"", 512, *("c1", "mutable", None, None))
+    output2 = (b"", 512, *("c1", "none", b"commitment", None))
+    output3 = (b"", 512, *("c2", "minting", None, 50))
+    output4 = (b"", 512, *("c2", None, None, 50))
+    output5 = (b"", 512, *("c1", None, None, 50))
+    outputs = [output1, output2, output3, output4]
+
+    # unused unspents
+    # no immutable commitment
+    unspents, unspents_used = select_cashtoken_utxo([unspent2], outputs)
+    assert len(unspents) == 1 and len(unspents_used) == 0
+    # no tokens in nft
+    unspents, unspents_used = select_cashtoken_utxo(
+        [Unspent(50, 1234, "script", "txid", 1, "c1", token_amount=1)], outputs
+    )
+    assert len(unspents) == 1 and len(unspents_used) == 0
+    # no nft in token amount
+    unspents, unspents_used = select_cashtoken_utxo(
+        [Unspent(50, 1234, "script", "txid", 1, "c1", "minting")], [output5]
+    )
+    assert len(unspents) == 1 and len(unspents_used) == 0
+    # no nft
+    unspents, unspents_used = select_cashtoken_utxo([unspent5], outputs)
+    assert len(unspents) == 1 and len(unspents_used) == 0
+    # no genesis
+    unspents, unspents_used = select_cashtoken_utxo([unspent4], outputs)
+    assert len(unspents) == 1 and len(unspents_used) == 0
+
+    # test minting
+    unspents, unspents_used = select_cashtoken_utxo([unspent1], outputs)
+    assert unspents == [] and unspents_used == [unspent1]
+    unspents, unspents_used = select_cashtoken_utxo([unspent1], [output2])
+    assert unspents == [] and unspents_used == [unspent1]
+
+    # test mutable
+    unspents, unspents_used = select_cashtoken_utxo([unspent1, unspent3], [output1])
+    assert unspents == [unspent1] and unspents_used == [unspent3]
+    unspents, unspents_used = select_cashtoken_utxo([unspent1, unspent3], [output2])
+    assert unspents == [unspent1] and unspents_used == [unspent3]
+
+    # test immutable
+    unspents, unspents_used = select_cashtoken_utxo(
+        [unspent1, unspent2, unspent3], [output2]
+    )
+    assert unspents == [unspent2, unspent1] and unspents_used == [unspent3]
+    unspents, unspents_used = select_cashtoken_utxo(
+        [unspent1, unspent2, unspent3], [output2]
+    )
+    assert unspents == [unspent2, unspent1] and unspents_used == [unspent3]
+    unspents, unspents_used = select_cashtoken_utxo(
+        [unspent1, unspent6, unspent3], [output2]
+    )
+    assert unspents == [unspent3, unspent1] and unspents_used == [unspent6]
+
+    # test genesis
+    unspents, unspents_used = select_cashtoken_utxo([unspent41], outputs)
+    assert unspents == [] and unspents_used == [unspent41]
+
+    # test token amount
+    # under funded
+    unspents, unspents_used = select_cashtoken_utxo([unspent7], [output5])
+    assert unspents == [] and unspents_used == [unspent7]
+    # over funded
+    unspents, unspents_used = select_cashtoken_utxo([unspent7, unspent9], [output5])
+    assert unspents == [] and unspents_used == [unspent7, unspent9]
+    # over funded
+    unspents, unspents_used = select_cashtoken_utxo([unspent8, unspent9], [output5])
+    # unspent8 has an nft too, sorted last
+    assert unspents == [unspent8] and unspents_used == [unspent9]
+    # over over funded
+    unspents, unspents_used = select_cashtoken_utxo(
+        [unspent9, unspent8, unspent7], [output5]
+    )
+    # unspent8 has an nft too, sorted last
+    # unspent7 is considered first due to sorting mechanism, hence both are
+    # spent
+    assert unspents == [unspent8] and unspents_used == [unspent7, unspent9]
+    # over over over funded
+    unspents, unspents_used = select_cashtoken_utxo(
+        [unspent9, unspent8, unspent7], [(b"", 512, "c1", None, None, 75)]
+    )
+    assert unspents == [] and unspents_used == [unspent7, unspent9, unspent8]
+
+
+def test_calculate_dust_value():
+    for script in [
+        PREFIX_CAPABILITY,
+        PREFIX_CAPABILITY_AMOUNT,
+        PREFIX_CAPABILITY_COMMITMENT,
+        PREFIX_CAPABILITY_COMMITMENT_AMOUNT,
+        PREFIX_AMOUNT,
+        b"",
+    ]:
+        cashtoken = parse_cashtoken_prefix(script)
+        dust = _calculate_dust_value(BITCOIN_CASHADDRESS_CATKN, *cashtoken)
+        assert dust == 546 + len(script) * 3
diff --git a/tests/test_format.py b/tests/test_format.py
index 56c076dd..1dbe22ad 100644
--- a/tests/test_format.py
+++ b/tests/test_format.py
@@ -1,10 +1,8 @@
 import pytest
 from bitcash import crypto
 from _pytest.monkeypatch import MonkeyPatch
-from bitcash.exceptions import InvalidAddress
 
 from bitcash.format import (
-    Address,
     address_to_public_key_hash,
     bytes_to_wif,
     coords_to_public_key,
@@ -14,22 +12,30 @@
     verify_sig,
     wif_checksum_check,
     wif_to_bytes,
+    hex_to_asm,
+    address_to_cashtokenaddress,
+    cashtokenaddress_to_address
 )
 from .samples import (
     BITCOIN_ADDRESS,
     BITCOIN_ADDRESS_COMPRESSED,
-    BITCOIN_CASHADDRESS_PAY2SH,
+    BITCOIN_CASHADDRESS_CATKN,
+    BITCOIN_CASHADDRESS_PAY2SH20,
+    BITCOIN_CASHADDRESS_PAY2SH32,
     BITCOIN_ADDRESS_TEST,
+    BITCOIN_CASHADDRESS_TEST_CATKN,
     BITCOIN_ADDRESS_TEST_COMPRESSED,
     BITCOIN_ADDRESS_REGTEST,
     BITCOIN_ADDRESS_REGTEST_COMPRESSED,
-    BITCOIN_CASHADDRESS_TEST_PAY2SH,
+    BITCOIN_CASHADDRESS_TEST_PAY2SH20,
+    BITCOIN_CASHADDRESS_TEST_PAY2SH32,
     BITCOIN_CASHADDRESS_REGTEST,
     BITCOIN_CASHADDRESS_REGTEST_COMPRESSED,
-    BITCOIN_CASHADDRESS_REGTEST_PAY2SH,
+    BITCOIN_CASHADDRESS_REGTEST_PAY2SH20,
     PRIVATE_KEY_BYTES,
     PUBKEY_HASH,
-    PUBKEY_HASH_P2SH,
+    PUBKEY_HASH_P2SH20,
+    PUBKEY_HASH_P2SH32,
     BITCOIN_CASHADDRESS,
     BITCOIN_CASHADDRESS_TEST,
     BITCOIN_CASHADDRESS_TEST_COMPRESSED,
@@ -311,11 +317,58 @@ def test_address_to_public_key_hash():
         address_to_public_key_hash(BITCOIN_CASHADDRESS_REGTEST_COMPRESSED)
         == PUBKEY_HASH_COMPRESSED
     )
-    assert address_to_public_key_hash(BITCOIN_CASHADDRESS_PAY2SH) == PUBKEY_HASH_P2SH
+    assert address_to_public_key_hash(BITCOIN_CASHADDRESS_PAY2SH20) == PUBKEY_HASH_P2SH20
     assert (
-        address_to_public_key_hash(BITCOIN_CASHADDRESS_TEST_PAY2SH) == PUBKEY_HASH_P2SH
+        address_to_public_key_hash(BITCOIN_CASHADDRESS_TEST_PAY2SH20) ==
+        PUBKEY_HASH_P2SH20
     )
     assert (
-        address_to_public_key_hash(BITCOIN_CASHADDRESS_REGTEST_PAY2SH)
-        == PUBKEY_HASH_P2SH
+        address_to_public_key_hash(BITCOIN_CASHADDRESS_PAY2SH32) == PUBKEY_HASH_P2SH32
     )
+    assert (
+        address_to_public_key_hash(BITCOIN_CASHADDRESS_TEST_PAY2SH32) == PUBKEY_HASH_P2SH32
+    )
+    assert (
+        address_to_public_key_hash(BITCOIN_CASHADDRESS_REGTEST_PAY2SH20)
+        == PUBKEY_HASH_P2SH20
+    )
+
+
+def test_to_and_from_cashtokenaddress():
+    cashtokenaddress = address_to_cashtokenaddress(BITCOIN_CASHADDRESS)
+    assert cashtokenaddress == BITCOIN_CASHADDRESS_CATKN
+    assert cashtokenaddress_to_address(cashtokenaddress) == BITCOIN_CASHADDRESS
+    cashtokenaddress = address_to_cashtokenaddress(BITCOIN_CASHADDRESS_TEST)
+    assert cashtokenaddress == BITCOIN_CASHADDRESS_TEST_CATKN
+    assert cashtokenaddress_to_address(cashtokenaddress) == BITCOIN_CASHADDRESS_TEST
+
+    # test vectors from https://github.com/bitjson/cashtokens
+    address = address_to_cashtokenaddress("bitcoincash:qr7fzmep8g7h7ymfxy74lgc0v950j3r2959lhtxxsl")
+    assert "bitcoincash:zr7fzmep8g7h7ymfxy74lgc0v950j3r295z4y4gq0v" == address
+    address = address_to_cashtokenaddress("bchtest:qr7fzmep8g7h7ymfxy74lgc0v950j3r295pdnvy3hr")
+    assert "bchtest:zr7fzmep8g7h7ymfxy74lgc0v950j3r295x8qj2hgs" == address
+    address = address_to_cashtokenaddress("bchreg:qr7fzmep8g7h7ymfxy74lgc0v950j3r295m39d8z59")
+    assert "bchreg:zr7fzmep8g7h7ymfxy74lgc0v950j3r295umknfytk" == address
+    address = address_to_cashtokenaddress("bitcoincash:ppawqn2h74a4t50phuza84kdp3794pq3ccvm92p8sh")
+    assert "bitcoincash:rpawqn2h74a4t50phuza84kdp3794pq3cct3k50p0y" == address
+    address = address_to_cashtokenaddress("bitcoincash:pvqqqqqqqqqqqqqqqqqqqqqqzg69v7ysqqqqqqqqqqqqqqqqqqqqqpkp7fqn0")
+    assert "bitcoincash:rvqqqqqqqqqqqqqqqqqqqqqqzg69v7ysqqqqqqqqqqqqqqqqqqqqqn9alsp2y" == address
+
+
+def test_hex_to_asm():
+    asm = hex_to_asm("76a9147ff07a9532d16a3fe14112e8c856093b81c25a6a88ac")
+    assert asm == ("OP_DUP OP_HASH160 7ff07a9532d16a3fe14112e8c856093b81c25a6a"
+                   " OP_EQUALVERIFY OP_CHECKSIG")
+    asm = hex_to_asm("6a0442434d52206b2000be5ce5527cd653c49cdba486e2fd0ec4214"
+                     "da2f71d7e56ad027b2139f448676973742e67697468756275736572"
+                     "636f6e74656e742e636f6d2f6d722d7a776574732f3834623030353"
+                     "7383038616632306466333932383135666232376434613636312f72"
+                     "6177")
+    assert asm == ("OP_RETURN 1380795202 6b2000be5ce5527cd653c49cdba486e2fd0"
+                   "ec4214da2f71d7e56ad027b2139f4 676973742e6769746875627573"
+                   "6572636f6e74656e742e636f6d2f6d722d7a776574732f3834623030"
+                   "3537383038616632306466333932383135666232376434613636312f"
+                   "726177")
+    # empty test
+    asm = hex_to_asm("6a4c00147ff07a9532d16a3fe14112e8c856093b81c25a6a")
+    assert asm == ("OP_RETURN  7ff07a9532d16a3fe14112e8c856093b81c25a6a")
diff --git a/tests/test_transaction.py b/tests/test_transaction.py
index fb38facb..d0a0c86f 100644
--- a/tests/test_transaction.py
+++ b/tests/test_transaction.py
@@ -11,13 +11,17 @@
     estimate_tx_fee,
     sanitize_tx_data,
 )
+from bitcash.op import OpCodes
+from bitcash.cashaddress import Address
 from bitcash.utils import hex_to_bytes
 from bitcash.wallet import PrivateKey
 from .samples import (
     WALLET_FORMAT_MAIN,
     BITCOIN_CASHADDRESS,
+    BITCOIN_CASHADDRESS_CATKN,
     BITCOIN_CASHADDRESS_COMPRESSED,
-    BITCOIN_CASHADDRESS_PAY2SH,
+    BITCOIN_CASHADDRESS_PAY2SH20,
+    BITCOIN_CASHADDRESS_PAY2SH32,
 )
 
 
@@ -73,8 +77,28 @@
         1,
     )
 ]
-OUTPUTS = [(BITCOIN_CASHADDRESS, 50000), (BITCOIN_CASHADDRESS_COMPRESSED, 83658760)]
-MESSAGES = [(b"hello", 0), (b"there", 0)]
+OUTPUTS = [
+    (
+        Address.from_string(BITCOIN_CASHADDRESS).scriptcode,
+        50000,
+        None,
+        None,
+        None,
+        None,
+    ),
+    (
+        Address.from_string(BITCOIN_CASHADDRESS_COMPRESSED).scriptcode,
+        83658760,
+        None,
+        None,
+        None,
+        None,
+    ),
+]
+MESSAGES = [
+    (OpCodes.OP_RETURN.binary + b"\x05" + b"hello", 0, None, None, None, None),
+    (OpCodes.OP_RETURN.binary + b"\x05" + b"there", 0, None, None, None, None),
+]
 OUTPUT_BLOCK = (
     "50c30000000000001976a91492461bde6283b461ece7ddf4dbf1e0a48bd113d888ac"
     "0888fc04000000001976a914990ef60d63b5b5964a1c2282061af45123e93fcb88ac"
@@ -106,11 +130,12 @@
 
 class TestTxIn:
     def test_init(self):
-        txin = TxIn(b"script", b"\x06", b"txid", b"\x04", 0)
+        txin = TxIn(b"script", b"\x06", b"txid", b"\x04", 0, b"a")
         assert txin.script == b"script"
         assert txin.script_len == b"\x06"
         assert txin.txid == b"txid"
         assert txin.txindex == b"\x04"
+        assert txin.token_prefix == b"a"
 
     def test_equality(self):
         txin1 = TxIn(b"script", b"\x06", b"txid", b"\x04", 0)
@@ -121,15 +146,15 @@ def test_equality(self):
 
     def test_repr(self):
         txin = TxIn(b"script", b"\x06", b"txid", b"\x04", 0)
-        assert repr(txin) == "TxIn(b'script', {}, b'txid', {}, 0)" "".format(
-            repr(b"\x06"), repr(b"\x04")
+        assert repr(txin) == "TxIn(b'script', {}, b'txid', {}, 0, {})" "".format(
+            repr(b"\x06"), repr(b"\x04"), repr(b"")
         )
 
 
 class TestSanitizeTxData:
     def test_no_input(self):
         with pytest.raises(ValueError):
-            sanitize_tx_data([], [], 70, "")
+            sanitize_tx_data([], [], 70, BITCOIN_CASHADDRESS)
 
     def test_message(self):
         unspents_original = [Unspent(10000, 0, "", "", 0), Unspent(10000, 0, "", "", 0)]
@@ -145,7 +170,7 @@ def test_message(self):
         )
 
         assert len(outputs) == 3
-        assert outputs[2][0] == b"hello"
+        assert outputs[2][0] == OpCodes.OP_RETURN.binary + b"\x05" + b"hello"
         assert outputs[2][1] == 0
 
     def test_message_pushdata(self):
@@ -165,7 +190,7 @@ def test_message_pushdata(self):
         )
 
         assert len(outputs) == 3
-        assert outputs[2][0] == b"\x05" + b"hello"
+        assert outputs[2][0] == OpCodes.OP_RETURN.binary + b"\x05" + b"hello"
         assert outputs[2][1] == 0
 
     def test_fee_applied(self):
@@ -196,11 +221,12 @@ def test_zero_remaining(self):
         )
 
         assert unspents == unspents_original
-        assert outputs == [(BITCOIN_CASHADDRESS_COMPRESSED, 2000)]
+        _ = Address.from_string(BITCOIN_CASHADDRESS_COMPRESSED).scriptcode
+        assert outputs == [(_, 2000, None, None, None, None)]
 
     def test_combine_remaining(self):
         unspents_original = [Unspent(1000, 0, "", "", 0), Unspent(1000, 0, "", "", 0)]
-        outputs_original = [(BITCOIN_CASHADDRESS_COMPRESSED, 500, "satoshi")]
+        outputs_original = [(BITCOIN_CASHADDRESS_COMPRESSED, 600, "satoshi")]
 
         unspents, outputs = sanitize_tx_data(
             unspents_original,
@@ -213,8 +239,8 @@ def test_combine_remaining(self):
 
         assert unspents == unspents_original
         assert len(outputs) == 2
-        assert outputs[1][0] == RETURN_ADDRESS
-        assert outputs[1][1] == 1500
+        assert outputs[1][0] == Address.from_string(RETURN_ADDRESS).scriptcode
+        assert outputs[1][1] == 1400
 
     def test_combine_insufficient_funds(self):
         unspents_original = [Unspent(1000, 0, "", "", 0), Unspent(1000, 0, "", "", 0)]
@@ -245,7 +271,7 @@ def test_no_combine_remaining(self):
 
         assert unspents == [Unspent(3000, 0, "", "", 0)]
         assert len(outputs) == 2
-        assert outputs[1][0] == RETURN_ADDRESS
+        assert outputs[1][0] == Address.from_string(RETURN_ADDRESS).scriptcode
         assert outputs[1][1] == 1000
 
     def test_no_combine_remaining_small_inputs(self):
@@ -264,10 +290,9 @@ def test_no_combine_remaining_small_inputs(self):
             combine=False,
             message=None,
         )
-        print(unspents)
         assert unspents == [Unspent(1500, 0, "", "", 0), Unspent(1600, 0, "", "", 0)]
         assert len(outputs) == 2
-        assert outputs[1][0] == RETURN_ADDRESS
+        assert outputs[1][0] == Address.from_string(RETURN_ADDRESS).scriptcode
         assert outputs[1][1] == 1100
 
     def test_no_combine_with_fee(self):
@@ -300,8 +325,8 @@ def test_no_combine_with_fee(self):
         assert unspents_single == [Unspent(5000, 0, "", "", 0)]
         assert len(outputs) == 2
         assert len(outputs_single) == 2
-        assert outputs[1][0] == RETURN_ADDRESS
-        assert outputs_single[1][0] == RETURN_ADDRESS
+        assert outputs[1][0] == Address.from_string(RETURN_ADDRESS).scriptcode
+        assert outputs_single[1][0] == Address.from_string(RETURN_ADDRESS).scriptcode
         assert outputs[1][1] == outputs_single[1][1]
 
     def test_no_combine_insufficient_funds(self):
@@ -318,14 +343,14 @@ def test_no_combine_insufficient_funds(self):
                 message=None,
             )
 
-    def test_with_P2SH_outputs(self):
+    def test_with_P2SH20_outputs(self):
         # tx:af386b52b9804c4d37d0bcf9ca124b34264d2f0a306ea11ee74c90d939402cb7
         unspents_original = [
             Unspent(5691944, 0, "", "", 0),
             Unspent(17344, 0, "", "", 0),
         ]
         outputs_original = [
-            (BITCOIN_CASHADDRESS_PAY2SH, 11065, "satoshi"),
+            (BITCOIN_CASHADDRESS_PAY2SH20, 11065, "satoshi"),
         ]
 
         unspents, outputs = sanitize_tx_data(
@@ -339,10 +364,10 @@ def test_with_P2SH_outputs(self):
 
         assert outputs[1][1] == 5697851
 
-        # multi PAY2SH test
+        # multi PAY2SH20 test
         outputs_original = [
-            (BITCOIN_CASHADDRESS_PAY2SH, 11065, "satoshi"),
-            (BITCOIN_CASHADDRESS_PAY2SH, 11065, "satoshi"),
+            (BITCOIN_CASHADDRESS_PAY2SH20, 11065, "satoshi"),
+            (BITCOIN_CASHADDRESS_PAY2SH20, 11065, "satoshi"),
         ]
 
         unspents, outputs = sanitize_tx_data(
@@ -356,6 +381,136 @@ def test_with_P2SH_outputs(self):
 
         assert outputs[2][1] == 5686754
 
+    def test_with_P2SH32_outputs(self):
+        # based on
+        # tx:af386b52b9804c4d37d0bcf9ca124b34264d2f0a306ea11ee74c90d939402cb7
+        unspents_original = [
+            Unspent(5691944, 0, "", "", 0),
+            Unspent(17344, 0, "", "", 0),
+        ]
+        outputs_original = [
+            (BITCOIN_CASHADDRESS_PAY2SH32, 11065, "satoshi"),
+        ]
+
+        unspents, outputs = sanitize_tx_data(
+            unspents_original,
+            outputs_original,
+            fee=1,
+            leftover=RETURN_ADDRESS,
+            combine=True,
+            message=None,
+        )
+
+        assert outputs[1][1] == 5697839
+
+        # multi PAY2SH32 test
+        outputs_original = [
+            (BITCOIN_CASHADDRESS_PAY2SH32, 11065, "satoshi"),
+            (BITCOIN_CASHADDRESS_PAY2SH32, 11065, "satoshi"),
+        ]
+
+        unspents, outputs = sanitize_tx_data(
+            unspents_original,
+            outputs_original,
+            fee=1,
+            leftover=RETURN_ADDRESS,
+            combine=True,
+            message=None,
+        )
+
+        assert outputs[2][1] == 5686730
+
+
+class TestSanitizeTxDataCashToken:
+    def test_combine(self):
+        unspents_original = [
+            Unspent(1000, 0, "script", "txid", 0),
+            Unspent(1000, 0, "script", "txid", 1, "caff", "none"),
+            Unspent(1000, 0, "script", "txid", 1, "caff", "minting"),
+            Unspent(1000, 0, "script", "txid", 1, "caf2", "minting"),
+        ]
+        outputs_original = [
+            [BITCOIN_CASHADDRESS_CATKN, 1000, "satoshi", "caff", "none", None, None]
+        ]
+
+        unspents, outputs = sanitize_tx_data(
+            unspents_original,
+            outputs_original,
+            0,
+            BITCOIN_CASHADDRESS_CATKN,
+            combine=True,
+        )
+        assert unspents == unspents_original
+
+        assert len(outputs) == 3
+        assert outputs[0][1:] == (1000, "caff", "none", None, None)
+        assert outputs[1][1:] == (558, "caff", "minting", None, None)
+        assert outputs[2][1:] == (2442, "caf2", "minting", None, None)
+
+    def test_no_combine(self):
+        unspents_original = [
+            Unspent(1000, 0, "script", "txid", 0),
+            Unspent(1000, 0, "script", "txid", 1, "caff", "none"),
+            Unspent(1000, 0, "script", "txid", 1, "caff", "minting"),
+        ]
+        outputs_original = [
+            [BITCOIN_CASHADDRESS_CATKN, 1100, "satoshi", "caff", "none", None, None]
+        ]
+        script = Address.from_string(BITCOIN_CASHADDRESS_CATKN).scriptcode
+
+        unspents, outputs = sanitize_tx_data(
+            unspents_original,
+            outputs_original,
+            0,
+            BITCOIN_CASHADDRESS_CATKN,
+            combine=False,
+        )
+
+        assert len(unspents) == 2
+        assert len(outputs) == 2
+        assert outputs[0][1:] == (1100, "caff", "none", None, None)
+        assert outputs[1] == (script, 900, None, None, None, None)
+
+    def test_genesis(self):
+        unspents_original = [
+            Unspent(1000, 0, "script", "cafe", 0),
+            Unspent(1000, 0, "script", "caca", 1, "caff", "none"),
+            Unspent(1000, 0, "script", "txid", 1, "caff", "minting"),
+        ]
+        outputs_original = [
+            [BITCOIN_CASHADDRESS_CATKN, 800, "satoshi", "cafe", "none", None, None]
+        ]
+
+        unspents, outputs = sanitize_tx_data(
+            unspents_original,
+            outputs_original,
+            0,
+            BITCOIN_CASHADDRESS_CATKN,
+            combine=False,
+        )
+
+        assert len(unspents) == 2
+        assert unspents[0] == unspents_original[0]
+        assert len(outputs) == 2
+        assert outputs[0][1:] == (800, "cafe", "none", None, None)
+        assert outputs[1][1:] == (1200, "caff", "none", None, None)
+
+        # fail genesis
+        outputs_original = [
+            [BITCOIN_CASHADDRESS_CATKN, 800, "satoshi", "caca", "none", None, None]
+        ]
+
+        # caca is not genesis, since txindex = 1. Thus it is treated as
+        # normal cashtoken output. But unspents don't have caca cashtoken
+        with pytest.raises(InsufficientFunds):
+            unspents, outputs = sanitize_tx_data(
+                unspents_original,
+                outputs_original,
+                0,
+                BITCOIN_CASHADDRESS_CATKN,
+                combine=False,
+            )
+
 
 class TestCreateSignedTransaction:
     def test_matching(self):
@@ -367,15 +522,28 @@ def test_matching(self):
 
 class TestEstimateTxFee:
     def test_accurate_compressed(self):
-        assert estimate_tx_fee(1, 2, 0, 70, True) == 15820
-        assert estimate_tx_fee(1, 2, 2, 70, True) == 20300
-        assert estimate_tx_fee(1, 0, 2, 70, True) == 15540
+        # 2 p2pkh
+        output_script_list = [b"\x00" * 25] * 2
+        assert estimate_tx_fee(1, output_script_list, 70, True) == 15820
+        # 2 p2pkh 2 p2sh20
+        output_script_list = [b"\x00" * 25] * 2 + [b"\x00" * 23] * 2
+        assert estimate_tx_fee(1, output_script_list, 70, True) == 20300
+        # 2 p2sh20
+        output_script_list = [b"\x00" * 23] * 2
+        assert estimate_tx_fee(1, output_script_list, 70, True) == 15540
+        # 2 p2sh32
+        output_script_list = [b"\x00" * 35] * 2
+        assert estimate_tx_fee(1, output_script_list, 70, True) == 17220
 
     def test_accurate_uncompressed(self):
-        assert estimate_tx_fee(1, 2, 0, 70, False) == 18060
+        # 2 p2pkh
+        output_script_list = [b"\x00" * 25] * 2
+        assert estimate_tx_fee(1, output_script_list, 70, False) == 18060
 
     def test_none(self):
-        assert estimate_tx_fee(5, 5, 0, 0, True) == 0
+        # 5 p2pkh
+        output_script_list = [b"\x00" * 34] * 5
+        assert estimate_tx_fee(5, output_script_list, 0, True) == 0
 
 
 class TestConstructOutputBlock:
@@ -391,17 +559,25 @@ def test_long_message(self):
         amount = b"\x00\x00\x00\x00\x00\x00\x00\x00"
         _, outputs = sanitize_tx_data(
             UNSPENTS,
-            [(out[0], out[1], "satoshi") for out in OUTPUTS],
+            [
+                (Address.from_script(out[0]).cash_address(), out[1], "satoshi")
+                for out in OUTPUTS
+            ],
             0,
             RETURN_ADDRESS,
             message="hello" * 50,
         )
+        print(outputs)
         assert construct_output_block(outputs).count(amount) == 2
 
     def test_pushdata_message(self):
-        BYTES = len(b"hello").to_bytes(1, byteorder="little") + b"hello"
+        BYTES = (
+            OpCodes.OP_RETURN.binary
+            + len(b"hello").to_bytes(1, byteorder="little")
+            + b"hello"
+        )
         assert construct_output_block(
-            OUTPUTS + [(BYTES, 0)], custom_pushdata=True
+            OUTPUTS + [(BYTES, 0, None, None, None, None)]
         ) == hex_to_bytes(OUTPUT_BLOCK_MESSAGE_PUSHDATA)
 
     def test_long_pushdata(self):
@@ -412,7 +588,10 @@ def test_long_pushdata(self):
         with pytest.raises(ValueError):
             sanitize_tx_data(
                 UNSPENTS,
-                [(out[0], out[1], "satoshi") for out in OUTPUTS],
+                [
+                    (Address.from_script(out[0]).cash_address(), out[1], "satoshi")
+                    for out in OUTPUTS
+                ],
                 0,
                 RETURN_ADDRESS,
                 message=BYTES * 40,
diff --git a/tests/test_utils.py b/tests/test_utils.py
index 21b7c455..f41993f3 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -1,3 +1,4 @@
+import io
 from bitcash.utils import (
     Decimal,
     bytes_to_hex,
@@ -8,6 +9,7 @@
     int_to_hex,
     int_to_unknown_bytes,
     int_to_varint,
+    varint_to_int,
 )
 
 BIG_INT = 123456789**5
@@ -69,6 +71,24 @@ def test_val_more_than_4294967295(self):
         assert int_to_varint(10000000000) == b"\xff\x00\xe4\x0bT\x02\x00\x00\x00"
 
 
+class TestVarIntToInt:
+    def test_val_less_than_253(self):
+        stream = io.BytesIO(b"\x14T")
+        assert varint_to_int(stream) == 20
+
+    def test_val_less_than_65535(self):
+        stream = io.BytesIO(b"\xfd\xff\xffT")
+        assert varint_to_int(stream) == 65535
+
+    def test_val_less_than_4294967295(self):
+        stream = io.BytesIO(b"\xfe\xfe\xff\xff\xffT")
+        assert varint_to_int(stream) == 4294967294
+
+    def test_val_more_than_4294967295(self):
+        stream = io.BytesIO(b"\xff\x00\xe4\x0bT\x02\x00\x00\x00T")
+        assert varint_to_int(stream) == 10000000000
+
+
 def test_hex_to_bytes():
     assert hex_to_bytes(HEX) == BYTES_BIG
     assert hex_to_bytes(ODD_HEX) == ODD_HEX_BYTES
diff --git a/tests/test_wallet.py b/tests/test_wallet.py
index 02e3b11c..65e98857 100644
--- a/tests/test_wallet.py
+++ b/tests/test_wallet.py
@@ -35,9 +35,12 @@
     WALLET_FORMAT_REGTEST,
     BITCOIN_CASHADDRESS,
     BITCOIN_CASHADDRESS_TEST,
+    BITCOIN_CASHADDRESS_TEST_CATKN,
     BITCOIN_CASHADDRESS_REGTEST,
-    BITCOIN_ADDRESS_TEST_PAY2SH,
-    BITCOIN_ADDRESS_REGTEST_PAY2SH,
+    BITCOIN_CASHADDRESS_REGTEST_CATKN,
+    BITCOIN_ADDRESS_TEST_PAY2SH20,
+    BITCOIN_ADDRESS_REGTEST_PAY2SH20,
+    BITCOIN_CASHADDRESS_CATKN,
 )
 
 
@@ -165,6 +168,7 @@ def test_init_default(self):
     def test_address(self):
         private_key = PrivateKey(WALLET_FORMAT_MAIN)
         assert private_key.address == BITCOIN_CASHADDRESS
+        assert private_key.cashtoken_address == BITCOIN_CASHADDRESS_CATKN
 
     def test_to_wif(self):
         private_key = PrivateKey(WALLET_FORMAT_MAIN)
@@ -214,7 +218,7 @@ def test_from_int(self):
     def test_repr(self):
         assert (
             repr(PrivateKey(WALLET_FORMAT_MAIN))
-            == "<PrivateKey: bitcoincash:qzfyvx77v2pmgc0vulwlfkl3uzjgh5gnmqk5hhyaa6>"
+            == f"<PrivateKey: {BITCOIN_CASHADDRESS}>"
         )
 
     def test_pay2sh(self):
@@ -238,7 +242,7 @@ def test_pay2sh(self):
             fee=1,
             leftover="bitcoincash:qpqpu8xr56gmccalfssssjm2pcpv6d2fhur48wjdzf",
         )
-        out = tx[476:]
+        out = tx[478:]
 
         # test outputs
         assert out[:2] == "02"
@@ -265,6 +269,7 @@ def test_init_default(self):
     def test_address(self):
         private_key = PrivateKeyTestnet(WALLET_FORMAT_TEST)
         assert private_key.address == BITCOIN_CASHADDRESS_TEST
+        assert private_key.cashtoken_address == BITCOIN_CASHADDRESS_TEST_CATKN
 
     def test_to_wif(self):
         private_key = PrivateKeyTestnet(WALLET_FORMAT_TEST)
@@ -351,7 +356,7 @@ def test_from_int(self):
     def test_repr(self):
         assert (
             repr(PrivateKeyTestnet(WALLET_FORMAT_MAIN))
-            == "<PrivateKeyTestnet: bchtest:qzfyvx77v2pmgc0vulwlfkl3uzjgh5gnmqjxnsx26x>"
+            == f"<PrivateKeyTestnet: {BITCOIN_CASHADDRESS_TEST}>"
         )
 
 
@@ -367,6 +372,7 @@ def test_init_default(self):
     def test_address(self):
         private_key = PrivateKeyRegtest(WALLET_FORMAT_REGTEST)
         assert private_key.address == BITCOIN_CASHADDRESS_REGTEST
+        assert private_key.cashtoken_address == BITCOIN_CASHADDRESS_REGTEST_CATKN
 
     def test_to_wif(self):
         private_key = PrivateKeyRegtest(WALLET_FORMAT_REGTEST)
@@ -456,5 +462,5 @@ def test_from_int(self):
     def test_repr(self):
         assert (
             repr(PrivateKeyRegtest(WALLET_FORMAT_REGTEST))
-            == "<PrivateKeyRegtest: bchreg:qzfyvx77v2pmgc0vulwlfkl3uzjgh5gnmqg6939eeq>"
+            == f"<PrivateKeyRegtest: {BITCOIN_CASHADDRESS_REGTEST}>"
         )
diff --git a/tests/token-prefix-valid.json b/tests/token-prefix-valid.json
new file mode 100644
index 00000000..bfeaa549
--- /dev/null
+++ b/tests/token-prefix-valid.json
@@ -0,0 +1,633 @@
+[
+  {
+    "prefix": "efaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1001",
+    "data": {
+      "amount": "1",
+      "category": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+    }
+  },
+  {
+    "prefix": "ef21430000000000000000000000000000000000000000000000000000000034121001",
+    "data": {
+      "amount": "1",
+      "category": "1234000000000000000000000000000000000000000000000000000000004321"
+    }
+  },
+  {
+    "prefix": "ef21436587090000000000000000000000000000000000000000000090785634121001",
+    "data": {
+      "amount": "1",
+      "category": "1234567890000000000000000000000000000000000000000000000987654321"
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb1001",
+    "data": {
+      "amount": "1",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb10fc",
+    "data": {
+      "amount": "252",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb10fdfd00",
+    "data": {
+      "amount": "253",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb10fdffff",
+    "data": {
+      "amount": "65535",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb10fe00000100",
+    "data": {
+      "amount": "65536",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb10fe01000100",
+    "data": {
+      "amount": "65537",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb10feffffffff",
+    "data": {
+      "amount": "4294967295",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb10ff0000000001000000",
+    "data": {
+      "amount": "4294967296",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb10ff0100000001000000",
+    "data": {
+      "amount": "4294967297",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb10ffffffffffffffff7f",
+    "data": {
+      "amount": "9223372036854775807",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb20",
+    "data": {
+      "amount": "0",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "",
+        "capability": "none"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb3001",
+    "data": {
+      "amount": "1",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "",
+        "capability": "none"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb30fc",
+    "data": {
+      "amount": "252",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "",
+        "capability": "none"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb30fdfd00",
+    "data": {
+      "amount": "253",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "",
+        "capability": "none"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb30fdffff",
+    "data": {
+      "amount": "65535",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "",
+        "capability": "none"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb30fe00000100",
+    "data": {
+      "amount": "65536",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "",
+        "capability": "none"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb30feffffffff",
+    "data": {
+      "amount": "4294967295",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "",
+        "capability": "none"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb30ff0000000001000000",
+    "data": {
+      "amount": "4294967296",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "",
+        "capability": "none"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb30ffffffffffffffff7f",
+    "data": {
+      "amount": "9223372036854775807",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "",
+        "capability": "none"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb6001cc",
+    "data": {
+      "amount": "0",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "cc",
+        "capability": "none"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb60051234567890",
+    "data": {
+      "amount": "0",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "1234567890",
+        "capability": "none"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb7001cc01",
+    "data": {
+      "amount": "1",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "cc",
+        "capability": "none"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb7001ccfc",
+    "data": {
+      "amount": "252",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "cc",
+        "capability": "none"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb7001ccfdfd00",
+    "data": {
+      "amount": "253",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "cc",
+        "capability": "none"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb7001ccfdffff",
+    "data": {
+      "amount": "65535",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "cc",
+        "capability": "none"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb7001ccfe00000100",
+    "data": {
+      "amount": "65536",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "cc",
+        "capability": "none"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb7001ccfeffffffff",
+    "data": {
+      "amount": "4294967295",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "cc",
+        "capability": "none"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb7001ccff0000000001000000",
+    "data": {
+      "amount": "4294967296",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "cc",
+        "capability": "none"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb7001ccffffffffffffffff7f",
+    "data": {
+      "amount": "9223372036854775807",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "cc",
+        "capability": "none"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb700accccccccccccccccccccfdffff",
+    "data": {
+      "amount": "65535",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "cccccccccccccccccccc",
+        "capability": "none"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb7028ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccfe00000100",
+    "data": {
+      "amount": "65536",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
+        "capability": "none"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb7029ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccfe00000100",
+    "data": {
+      "amount": "65536",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
+        "capability": "none"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb60fdfd00cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
+    "data": {
+      "amount": "0",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
+        "capability": "none"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb70fdfd00ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccfe00000100",
+    "data": {
+      "amount": "65536",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
+        "capability": "none"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb70fde903ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccfe00000100",
+    "data": {
+      "amount": "65536",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
+        "capability": "none"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb21",
+    "data": {
+      "amount": "0",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "",
+        "capability": "mutable"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb31feffffffff",
+    "data": {
+      "amount": "4294967295",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "",
+        "capability": "mutable"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb6101cc",
+    "data": {
+      "amount": "0",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "cc",
+        "capability": "mutable"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb7101ccff0000000001000000",
+    "data": {
+      "amount": "4294967296",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "cc",
+        "capability": "mutable"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb7102ccccffffffffffffffff7f",
+    "data": {
+      "amount": "9223372036854775807",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "cccc",
+        "capability": "mutable"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb710acccccccccccccccccccc01",
+    "data": {
+      "amount": "1",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "cccccccccccccccccccc",
+        "capability": "mutable"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb7128ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccfc",
+    "data": {
+      "amount": "252",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
+        "capability": "mutable"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb7129ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccfc",
+    "data": {
+      "amount": "252",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
+        "capability": "mutable"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb71fdfd00cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc01",
+    "data": {
+      "amount": "1",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
+        "capability": "mutable"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb22",
+    "data": {
+      "amount": "0",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "",
+        "capability": "minting"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb3201",
+    "data": {
+      "amount": "1",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "",
+        "capability": "minting"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb32fdfd00",
+    "data": {
+      "amount": "253",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "",
+        "capability": "minting"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb32fe00000100",
+    "data": {
+      "amount": "65536",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "",
+        "capability": "minting"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb32ff0000000001000000",
+    "data": {
+      "amount": "4294967296",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "",
+        "capability": "minting"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb32ffffffffffffffff7f",
+    "data": {
+      "amount": "9223372036854775807",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "",
+        "capability": "minting"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb6201cc",
+    "data": {
+      "amount": "0",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "cc",
+        "capability": "minting"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb6229cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
+    "data": {
+      "amount": "0",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
+        "capability": "minting"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb7201ccfdffff",
+    "data": {
+      "amount": "65535",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "cc",
+        "capability": "minting"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb7202ccccfe00000100",
+    "data": {
+      "amount": "65536",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "cccc",
+        "capability": "minting"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb720accccccccccccccccccccff0100000001000000",
+    "data": {
+      "amount": "4294967297",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "cccccccccccccccccccc",
+        "capability": "minting"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb7228ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccffffffffffffffff7f",
+    "data": {
+      "amount": "9223372036854775807",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
+        "capability": "minting"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb7229ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccffffffffffffffff7f",
+    "data": {
+      "amount": "9223372036854775807",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
+        "capability": "minting"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb62fdfd00cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
+    "data": {
+      "amount": "0",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
+        "capability": "minting"
+      }
+    }
+  },
+  {
+    "prefix": "efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb72fdfd00ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccfe00000100",
+    "data": {
+      "amount": "65536",
+      "category": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "nft": {
+        "commitment": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
+        "capability": "minting"
+      }
+    }
+  }
+]
+