Esempio n. 1
0
    def decode_bytecode(compiled):
        """
        Decode an encoded contract to it's components
        :param compiled: the encoded bytecode to decode as got from the 'compile' function
        :return: a named tuple with a decoded contract
        """
        if isinstance(compiled, str):
            if not utils.prefix_match(identifiers.BYTECODE, compiled):
                raise ValueError(
                    f"Invalid input, expecting {identifiers.BYTECODE}_ prefix")
            # unpack the transaction
            raw_contract = hashing.decode_rlp(compiled)
        elif isinstance(compiled, bytes):
            # unpack the transaction
            raw_contract = hashing.decode_rlp(compiled)
        else:
            raise ValueError(f"Invalid input type")

        if not isinstance(raw_contract, list) or len(raw_contract) < 6:
            raise ValueError(f"Invalid contract structure")

        # print(raw_contract)
        tag = hashing._int_decode(raw_contract[0])
        vsn = hashing._int_decode(raw_contract[1])
        if tag != identifiers.OBJECT_TAG_SOPHIA_BYTE_CODE:
            raise ValueError(
                f"Invalid input, expecting object type {identifiers.OBJECT_TAG_SOPHIA_BYTE_CODE}, got {tag}"
            )
        # this is the hash
        contract_data = dict(
            raw=raw_contract,
            tag=tag,
            vsn=vsn,
            src_hash=raw_contract[2],
            type_info=[],
            bytecode=raw_contract[4],
            compiler_version=hashing._binary_decode(raw_contract[5], str),
            # payable=raw_contract[6]
        )
        # print(type_info)
        for t in raw_contract[3]:
            contract_data["type_info"].append(
                dict(
                    fun_hash=t[0],
                    fun_name=hashing._binary_decode(t[1], str),
                    arg_type=t[2],
                    out_type=t[3],
                ))
        return namedtupled.map(contract_data, _nt_name="ContractBin")
Esempio n. 2
0
def signed_tx_to_obj(tx_str):
    tx = hashing.decode_rlp(tx_str)

    if hashing._int_decode(tx[0]) != 11:
        raise Exception("invalid tag")

    if len(tx) != 4:
        raise Exception("invalid tx")

    return transactions._tx_native(op=transactions.UNPACK_TX,
                                   tx=hashing.encode("tx", tx[3]))
Esempio n. 3
0
def _tx_native(op, **kwargs):

    def std_fee(tx_raw, fee_idx, base_gas_multiplier=1):
        # calculates the standard minimum transaction fee
        tx_copy = tx_raw  # create a copy of the input
        tx_copy[fee_idx] = _int(0, 8)  # replace fee with a byte array of lenght 8
        return (defaults.BASE_GAS * base_gas_multiplier + len(rlp.encode(tx_copy)) * defaults.GAS_PER_BYTE) * defaults.GAS_PRICE

    def contract_fee(tx_raw, fee_idx, gas, base_gas_multiplier=1):
        # estimate the contract creation fee
        tx_copy = tx_raw  # create a copy of the input
        tx_copy[fee_idx] = _int(0, 8)  # replace fee with a byte array of lenght 8
        return (defaults.BASE_GAS * base_gas_multiplier + gas + len(rlp.encode(tx_copy)) * defaults.GAS_PER_BYTE) * defaults.GAS_PRICE

    def oracle_fee(tx_raw, fee_idx, relative_ttl):
        # estimate oracle fees
        tx_copy = tx_raw  # create a copy of the input
        tx_copy[fee_idx] = _int(0, 8)  # replace fee with a byte array of lenght 8
        fee = (defaults.BASE_GAS + len(rlp.encode(tx_copy)) * defaults.GAS_PER_BYTE)
        fee += math.ceil(32000 * relative_ttl / math.floor(60 * 24 * 365 / defaults.KEY_BLOCK_INTERVAL))
        return fee * defaults.GAS_PRICE

    def build_tx_object(tx_data, tx_raw, fee_idx, min_fee):
        if tx_data.get("fee") < min_fee:
            tx_native[fee_idx] = _int(min_fee)
            tx_data["fee"] = min_fee
        tx_encoded = encode_rlp(idf.TRANSACTION, tx_native)
        tx = dict(
            data=tx_data,
            tx=tx_encoded,
            hash=TxBuilder.compute_tx_hash(tx_encoded),
        )
        return namedtupled.map(tx, _nt_name="TxObject")

    # prepare tag and version
    if op == PACK_TX:
        tag = kwargs.get("tag", 0)
        vsn = kwargs.get("vsn", 1)
        tx_data = kwargs
    elif op == UNPACK_TX:
        tx_native = decode_rlp(kwargs.get("tx", []))
        tag = _int_decode(tx_native[0])
    else:
        raise Exception("Invalid operation")

    # check the tags
    if tag == idf.OBJECT_TAG_SPEND_TRANSACTION:
        tx_field_fee_index = 5
        if op == PACK_TX:  # pack transaction
            tx_native = [
                _int(tag),
                _int(vsn),
                _id(idf.ID_TAG_ACCOUNT, kwargs.get("sender_id")),
                _id(idf.ID_TAG_ACCOUNT, kwargs.get("recipient_id")),
                _int(kwargs.get("amount")),
                _int(kwargs.get("fee")),  # index 5
                _int(kwargs.get("ttl")),
                _int(kwargs.get("nonce")),
                _binary(kwargs.get("payload"))
            ]
            min_fee = std_fee(tx_native, tx_field_fee_index)
        elif op == UNPACK_TX:  # unpack transaction
            tx_data = dict(
                tag=tag,
                vsn=_int_decode(tx_native[1]),
                sender_id=encode(idf.ACCOUNT_ID, tx_native[2][1:]),
                recipient_id=encode(idf.ACCOUNT_ID, tx_native[3][1:]),
                amount=_int_decode(tx_native[4]),
                fee=_int_decode(tx_native[5]),
                ttl=_int_decode(tx_native[6]),
                nonce=_int_decode(tx_native[7]),
                payload=_binary_decode(tx_native[8]),
            )
            min_fee = tx_data.get("fee")
        else:
            raise Exception("Invalid operation")
        return build_tx_object(tx_data, tx_native, tx_field_fee_index, min_fee)
    elif tag == idf.OBJECT_TAG_NAME_SERVICE_PRECLAIM_TRANSACTION:
        tx_field_fee_index = 5
        if op == PACK_TX:  # pack transaction
            tx_native = [
                _int(tag),
                _int(vsn),
                _id(idf.ID_TAG_ACCOUNT, kwargs.get("account_id")),
                _int(kwargs.get("nonce")),
                _id(idf.ID_TAG_COMMITMENT, kwargs.get("commitment_id")),
                _int(kwargs.get("fee")),
                _int(kwargs.get("ttl"))
            ]
            min_fee = std_fee(tx_native, tx_field_fee_index)
        elif op == UNPACK_TX:  # unpack transaction
            tx_data = dict(
                tag=tag,
                vsn=_int_decode(tx_native[1]),
                account_id=encode(idf.ACCOUNT_ID, tx_native[2][1:]),
                nonce=_int_decode(tx_native[3]),
                commitment_id=encode(idf.COMMITMENT, tx_native[4][1:]),
                fee=_int_decode(tx_native[5]),
                ttl=_int_decode(tx_native[6]),
            )
            min_fee = tx_data.get("fee")
        else:
            raise Exception("Invalid operation")
        return build_tx_object(tx_data, tx_native, tx_field_fee_index, min_fee)

    elif tag == idf.OBJECT_TAG_NAME_SERVICE_CLAIM_TRANSACTION:
        tx_field_fee_index = 6
        if op == PACK_TX:  # pack transaction
            tx_native = [
                _int(tag),
                _int(vsn),
                _id(idf.ID_TAG_ACCOUNT, kwargs.get("account_id")),
                _int(kwargs.get("nonce")),
                decode(kwargs.get("name")),
                _binary(kwargs.get("name_salt")),
                _int(kwargs.get("fee")),
                _int(kwargs.get("ttl"))
            ]
            min_fee = std_fee(tx_native, tx_field_fee_index)
        elif op == UNPACK_TX:  # unpack transaction
            tx_data = dict(
                tag=tag,
                vsn=_int_decode(tx_native[1]),
                account_id=encode(idf.ACCOUNT_ID, tx_native[2][1:]),
                nonce=_int_decode(tx_native[3]),
                name=_binary_decode(tx_native[4], str),
                name_salt=_binary_decode(tx_native[5], int),
                fee=_int_decode(tx_native[6]),
                ttl=_int_decode(tx_native[7]),
            )
            min_fee = tx_data.get("fee")
        else:
            raise Exception("Invalid operation")
        return build_tx_object(tx_data, tx_native, tx_field_fee_index, min_fee)

    elif tag == idf.OBJECT_TAG_NAME_SERVICE_UPDATE_TRANSACTION:
        tx_field_fee_index = 8
        if op == PACK_TX:  # pack transaction
            # first asseble the pointers
            def pointer_tag(pointer):
                return {
                    "account_pubkey": idf.ID_TAG_ACCOUNT,
                    "oracle_pubkey": idf.ID_TAG_ORACLE,
                    "contract_pubkey": idf.ID_TAG_CONTRACT,
                    "channel_pubkey": idf.ID_TAG_CHANNEL
                }.get(pointer.get("key"))
            ptrs = [[_binary(p.get("key")), _id(pointer_tag(p), p.get("id"))] for p in kwargs.get("pointers", [])]
            # then build the transaction
            tx_native = [
                _int(tag),
                _int(vsn),
                _id(idf.ID_TAG_ACCOUNT, kwargs.get("account_id")),
                _int(kwargs.get("nonce")),
                _id(idf.ID_TAG_NAME, kwargs.get("name_id")),
                _int(kwargs.get("name_ttl")),
                ptrs,
                _int(kwargs.get("client_ttl")),
                _int(kwargs.get("fee")),
                _int(kwargs.get("ttl"))
            ]
            min_fee = std_fee(tx_native, tx_field_fee_index)
        elif op == UNPACK_TX:  # unpack transaction
            tx_data = dict(
                tag=tag,
                vsn=_int_decode(tx_native[1]),
                account_id=encode(idf.ACCOUNT_ID, tx_native[2][1:]),
                nonce=_int_decode(tx_native[3]),
                name=encode(idf.NAME, tx_native[4][1:]),
                name_ttl=_int_decode(tx_native[5]),
                pointers=[],  # TODO: decode pointers
                client_ttl=_int_decode(tx_native[7]),
                fee=_int_decode(tx_native[8]),
                ttl=_int_decode(tx_native[9]),
            )
            min_fee = tx_data.get("fee")
        else:
            raise Exception("Invalid operation")
        return build_tx_object(tx_data, tx_native, tx_field_fee_index, min_fee)

    elif tag == idf.OBJECT_TAG_NAME_SERVICE_TRANSFER_TRANSACTION:
        tx_field_fee_index = 6
        if op == PACK_TX:  # pack transaction
            tx_native = [
                _int(tag),
                _int(vsn),
                _id(idf.ID_TAG_ACCOUNT, kwargs.get("account_id")),
                _int(kwargs.get("nonce")),
                _id(idf.ID_TAG_NAME, kwargs.get("name_id")),
                _id(idf.ID_TAG_ACCOUNT, kwargs.get("recipient_id")),
                _int(kwargs.get("fee")),
                _int(kwargs.get("ttl")),
            ]
            min_fee = std_fee(tx_native, tx_field_fee_index)
        elif op == UNPACK_TX:  # unpack transaction
            tx_data = dict(
                tag=tag,
                vsn=_int_decode(tx_native[1]),
                account_id=encode(idf.ACCOUNT_ID, tx_native[2][1:]),
                nonce=_int_decode(tx_native[3]),
                name=encode(idf.NAME, tx_native[4][1:]),
                recipient_id=encode(idf.ACCOUNT_ID, tx_native[5][1:]),
                fee=_int_decode(tx_native[6]),
                ttl=_int_decode(tx_native[7]),
            )
            min_fee = tx_data.get("fee")
        else:
            raise Exception("Invalid operation")
        return build_tx_object(tx_data, tx_native, tx_field_fee_index, min_fee)

    elif tag == idf.OBJECT_TAG_NAME_SERVICE_REVOKE_TRANSACTION:
        tx_field_fee_index = 5
        if op == PACK_TX:  # pack transaction
            tx_native = [
                _int(tag),
                _int(vsn),
                _id(idf.ID_TAG_ACCOUNT, kwargs.get("account_id")),
                _int(kwargs.get("nonce")),
                _id(idf.ID_TAG_NAME, kwargs.get("name_id")),
                _int(kwargs.get("fee")),
                _int(kwargs.get("ttl")),
            ]
            min_fee = std_fee(tx_native, tx_field_fee_index)
        elif op == UNPACK_TX:  # unpack transaction
            tx_data = dict(
                tag=tag,
                vsn=_int_decode(tx_native[1]),
                account_id=encode(idf.ACCOUNT_ID, tx_native[2][1:]),
                nonce=_int_decode(tx_native[3]),
                name=encode(idf.NAME, tx_native[4][1:]),
                fee=_int_decode(tx_native[5]),
                ttl=_int_decode(tx_native[6]),
            )
            min_fee = tx_data.get("fee")
        else:
            raise Exception("Invalid operation")
        return build_tx_object(tx_data, tx_native, tx_field_fee_index, min_fee)

    elif tag == idf.OBJECT_TAG_CONTRACT_CREATE_TRANSACTION:
        tx_field_fee_index = 6
        if op == PACK_TX:  # pack transaction
            tx_native = [
                _int(tag),
                _int(vsn),
                _id(idf.ID_TAG_ACCOUNT, kwargs.get("owner_id")),
                _int(kwargs.get("nonce")),
                _binary(decode(kwargs.get("code"))),
                _int(kwargs.get("vm_version")) + _int(kwargs.get("abi_version"), 2),
                _int(kwargs.get("fee")),
                _int(kwargs.get("ttl")),
                _int(kwargs.get("deposit")),
                _int(kwargs.get("amount")),
                _int(kwargs.get("gas")),
                _int(kwargs.get("gas_price")),
                _binary(decode(kwargs.get("call_data"))),
            ]
            # TODO: verify the fee caluclation for the contract
            min_fee = contract_fee(tx_native, tx_field_fee_index, kwargs.get("gas"),  base_gas_multiplier=5)
        elif op == UNPACK_TX:  # unpack transaction
            vml = len(tx_native[5])  # this is used to extract the abi and vm version from the 5th field
            tx_data = dict(
                tag=tag,
                vsn=_int_decode(tx_native[1]),
                owner_id=encode(idf.ACCOUNT_ID, tx_native[2][1:]),
                nonce=_int_decode(tx_native[3]),
                code=encode(idf.BYTECODE, tx_native[4][1:]),
                vm_version=_int_decode(tx_native[5][0:vml - 2]),
                abi_version=_int_decode(tx_native[5][vml - 2:]),
                fee=_int_decode(tx_native[6]),
                ttl=_int_decode(tx_native[7]),
                deposit=_int_decode(tx_native[8]),
                amount=_int_decode(tx_native[9]),
                gas=_int_decode(tx_native[10]),
                gas_price=_int_decode(tx_native[11]),
                call_data=encode(idf.BYTECODE, tx_native[12][1:]),
            )
            min_fee = tx_data.get("fee")
        else:
            raise Exception("Invalid operation")
        return build_tx_object(tx_data, tx_native, tx_field_fee_index, min_fee)

    elif tag == idf.OBJECT_TAG_CONTRACT_CALL_TRANSACTION:
        tx_field_fee_index = 6
        if op == PACK_TX:  # pack transaction
            tx_native = [
                _int(tag),
                _int(vsn),
                _id(idf.ID_TAG_ACCOUNT, kwargs.get("caller_id")),
                _int(kwargs.get("nonce")),
                _id(idf.ID_TAG_CONTRACT, kwargs.get("contract_id")),
                _int(kwargs.get("abi_version")),
                _int(kwargs.get("fee")),
                _int(kwargs.get("ttl")),
                _int(kwargs.get("amount")),
                _int(kwargs.get("gas")),
                _int(kwargs.get("gas_price")),
                _binary(decode(kwargs.get("call_data"))),
            ]
            min_fee = contract_fee(tx_native, tx_field_fee_index, kwargs.get("gas"),  base_gas_multiplier=30)
        elif op == UNPACK_TX:  # unpack transaction
            vml = len(tx_native[5])  # this is used to extract the abi and vm version from the 5th field
            tx_data = dict(
                tag=tag,
                vsn=_int_decode(tx_native[1]),
                caller_id=encode(idf.ACCOUNT_ID, tx_native[2][1:]),
                nonce=_int_decode(tx_native[3]),
                contract_id=encode(idf.CONTRACT_ID, tx_native[4][1:]),
                abi_version=_int_decode(tx_native[5]),
                fee=_int_decode(tx_native[6]),
                ttl=_int_decode(tx_native[7]),
                amount=_int_decode(tx_native[8]),
                gas=_int_decode(tx_native[9]),
                gas_price=_int_decode(tx_native[10]),
                call_data=encode(idf.BYTECODE, tx_native[11][1:]),
            )
            min_fee = tx_data.get("fee")
        else:
            raise Exception("Invalid operation")
        return build_tx_object(tx_data, tx_native, tx_field_fee_index, min_fee)

    elif tag == idf.OBJECT_TAG_CHANNEL_CREATE_TRANSACTION:
        tx_native = [
            _int(tag),
            _int(vsn),
            _id(idf.ID_TAG_ACCOUNT, kwargs.get("initiator")),
            _int(kwargs.get("initiator_amount")),
            _id(idf.ID_TAG_ACCOUNT, kwargs.get("responder")),
            _int(kwargs.get("responder_amount")),
            _int(kwargs.get("channel_reserve")),
            _int(kwargs.get("lock_period")),
            _int(kwargs.get("ttl")),
            _int(kwargs.get("fee")),
            # _[id(delegate_ids)], TODO: handle delegate ids
            _binary(kwargs.get("state_hash")),
            _int(kwargs.get("nonce")),
        ]
        tx_field_fee_index = 9
        min_fee = std_fee(tx_native, tx_field_fee_index)
    elif tag == idf.OBJECT_TAG_CHANNEL_DEPOSIT_TRANSACTION:
        tx_native = [
            _int(tag),
            _int(vsn),
            _id(idf.ID_TAG_CHANNEL, kwargs.get("channel_id")),
            _id(idf.ID_TAG_ACCOUNT, kwargs.get("from_id")),
            _int(kwargs.get("amount")),
            _int(kwargs.get("ttl")),
            _int(kwargs.get("fee")),
            _binary(kwargs.get("state_hash")),
            _int(kwargs.get("round")),
            _int(kwargs.get("nonce")),
        ]
        tx_field_fee_index = 6
        min_fee = std_fee(tx_native, tx_field_fee_index)
    elif tag == idf.OBJECT_TAG_CHANNEL_WITHDRAW_TRANSACTION:
        tx_native = [
            _int(tag),
            _int(vsn),
            _id(idf.ID_TAG_CHANNEL, kwargs.get("channel_id")),
            _id(idf.ID_TAG_ACCOUNT, kwargs.get("to_id")),
            _int(kwargs.get("amount")),
            _int(kwargs.get("ttl")),
            _int(kwargs.get("fee")),
            _binary(kwargs.get("state_hash")),
            _int(kwargs.get("round")),
            _int(kwargs.get("nonce")),
        ]
        tx_field_fee_index = 6
        min_fee = std_fee(tx_native, tx_field_fee_index)
    elif tag == idf.OBJECT_TAG_CHANNEL_CLOSE_MUTUAL_TRANSACTION:
        tx_native = [
            _int(tag),
            _int(vsn),
            _id(idf.ID_TAG_CHANNEL, kwargs.get("channel_id")),
            _id(idf.ID_TAG_ACCOUNT, kwargs.get("from_id")),
            _int(kwargs.get("initiator_amount_final")),
            _int(kwargs.get("responder_amount_final")),
            _int(kwargs.get("ttl")),
            _int(kwargs.get("fee")),
            _int(kwargs.get("nonce")),
        ]
        tx_field_fee_index = 7
        min_fee = std_fee(tx_native, tx_field_fee_index)
    elif tag == idf.OBJECT_TAG_CHANNEL_CLOSE_SOLO_TRANSACTION:
        tx_native = [
            _int(tag),
            _int(vsn),
            _id(idf.ID_TAG_CHANNEL, kwargs.get("channel_id")),
            _id(idf.ID_TAG_ACCOUNT, kwargs.get("from_id")),
            _binary(kwargs.get("payload")),
            # _poi(kwargs.get("poi")), TODO: implement support for _poi
            _int(kwargs.get("ttl")),
            _int(kwargs.get("fee")),
            _int(kwargs.get("nonce")),
        ]
        tx_field_fee_index = 7
        min_fee = std_fee(tx_native, tx_field_fee_index)
    elif tag == idf.OBJECT_TAG_CHANNEL_SLASH_TRANSACTION:
        tx_native = [
            _int(tag),
            _int(vsn),
            _id(idf.ID_TAG_CHANNEL, kwargs.get("channel_id")),
            _id(idf.ID_TAG_ACCOUNT, kwargs.get("from_id")),
            _binary(kwargs.get("payload")),
            # _poi(kwargs.get("poi")), TODO: implement support for _poi
            _int(kwargs.get("ttl")),
            _int(kwargs.get("fee")),
            _int(kwargs.get("nonce")),
        ]
        tx_field_fee_index = 7
        min_fee = std_fee(tx_native, tx_field_fee_index)
    elif tag == idf.OBJECT_TAG_CHANNEL_SETTLE_TRANSACTION:
        tx_native = [
            _int(tag),
            _int(vsn),
            _id(idf.ID_TAG_CHANNEL, kwargs.get("channel_id")),
            _id(idf.ID_TAG_ACCOUNT, kwargs.get("from_id")),
            _int(kwargs.get("initiator_amount_final")),
            _int(kwargs.get("responder_amount_final")),
            _int(kwargs.get("ttl")),
            _int(kwargs.get("fee")),
            _int(kwargs.get("nonce")),
        ]
        tx_field_fee_index = 7
        min_fee = std_fee(tx_native, tx_field_fee_index)
    elif tag == idf.OBJECT_TAG_CHANNEL_SNAPSHOT_TRANSACTION:
        tx_native = [
            _int(tag),
            _int(vsn),
            _id(idf.ID_TAG_CHANNEL, kwargs.get("channel_id")),
            _id(idf.ID_TAG_ACCOUNT, kwargs.get("from_id")),
            _binary(kwargs.get("payload")),
            _int(kwargs.get("ttl")),
            _int(kwargs.get("fee")),
            _int(kwargs.get("nonce")),
        ]
        tx_field_fee_index = 6
        min_fee = std_fee(tx_native, tx_field_fee_index)
    elif tag == idf.OBJECT_TAG_CHANNEL_FORCE_PROGRESS_TRANSACTION:
        tx_native = [
            _int(tag),
            _int(vsn),
            _id(idf.ID_TAG_CHANNEL, kwargs.get("channel_id")),
            _id(idf.ID_TAG_ACCOUNT, kwargs.get("from_id")),
            _binary(kwargs.get("payload")),
            _int(kwargs.get("round")),
            _binary(kwargs.get("update")),
            _binary(kwargs.get("state_hash")),
            # _trees(kwargs.get("offchain_trees")), TODO: implement support for _trees
            _int(kwargs.get("ttl")),
            _int(kwargs.get("fee")),
            _int(kwargs.get("nonce")),
        ]
        tx_field_fee_index = 9
        min_fee = std_fee(tx_native, tx_field_fee_index)
    elif tag == idf.OBJECT_TAG_ORACLE_REGISTER_TRANSACTION:
        tx_field_fee_index = 9
        if op == PACK_TX:  # pack transaction
            oracle_ttl = kwargs.get("oracle_ttl", {})
            tx_native = [
                _int(tag),
                _int(vsn),
                _id(idf.ID_TAG_ACCOUNT, kwargs.get("account_id")),
                _int(kwargs.get("nonce")),
                _binary(kwargs.get("query_format")),
                _binary(kwargs.get("response_format")),
                _int(kwargs.get("query_fee")),
                _int(0 if oracle_ttl.get("type") == idf.ORACLE_TTL_TYPE_DELTA else 1),
                _int(oracle_ttl.get("value")),
                _int(kwargs.get("fee")),
                _int(kwargs.get("ttl")),
                _int(kwargs.get("vm_version")),
            ]
            min_fee = oracle_fee(tx_native, tx_field_fee_index, oracle_ttl.get("value"))
        elif op == UNPACK_TX:  # unpack transaction
            vml = len(tx_native[5])  # this is used to extract the abi and vm version from the 5th field
            tx_data = dict(
                tag=tag,
                vsn=_int_decode(tx_native[1]),
                account_id=encode(idf.ACCOUNT_ID, tx_native[2][1:]),
                nonce=_int_decode(tx_native[3]),
                query_format=_binary_decode(tx_native[4]),
                response_format=_binary_decode(tx_native[5]),
                query_fee=_int_decode(tx_native[6]),
                oracle_ttl=dict(
                    type=idf.ORACLE_TTL_TYPE_DELTA if _int_decode(tx_native[7]) else idf.ORACLE_TTL_TYPE_BLOCK,
                    value=_int_decode(tx_native[8]),
                ),
                fee=_int_decode(tx_native[9]),
                ttl=_int_decode(tx_native[10]),
                vm_version=_int_decode(tx_native[11]),
            )
            min_fee = tx_data.get("fee")
        else:
            raise Exception("Invalid operation")
        return build_tx_object(tx_data, tx_native, tx_field_fee_index, min_fee)

    elif tag == idf.OBJECT_TAG_ORACLE_QUERY_TRANSACTION:
        tx_field_fee_index = 11
        if op == PACK_TX:  # pack transaction
            query_ttl = kwargs.get("query_ttl", {})
            response_ttl = kwargs.get("response_ttl", {})
            tx_native = [
                _int(tag),
                _int(vsn),
                _id(idf.ID_TAG_ACCOUNT, kwargs.get("sender_id")),
                _int(kwargs.get("nonce")),
                _id(idf.ID_TAG_ORACLE, kwargs.get("oracle_id")),
                _binary(kwargs.get("query")),
                _int(kwargs.get("query_fee")),
                _int(0 if query_ttl.get("type") == idf.ORACLE_TTL_TYPE_DELTA else 1),
                _int(query_ttl.get("value")),
                _int(0 if response_ttl.get("type") == idf.ORACLE_TTL_TYPE_DELTA else 1),
                _int(response_ttl.get("value")),
                _int(kwargs.get("fee")),
                _int(kwargs.get("ttl")),
            ]
            min_fee = oracle_fee(tx_native, tx_field_fee_index, query_ttl.get("value"))
        elif op == UNPACK_TX:  # unpack transaction
            vml = len(tx_native[5])  # this is used to extract the abi and vm version from the 5th field
            tx_data = dict(
                tag=tag,
                vsn=_int_decode(tx_native[1]),
                sender_id=encode(idf.ACCOUNT_ID, tx_native[2][1:]),
                nonce=_int_decode(tx_native[3]),
                oracle_id=encode(idf.ORACLE_ID, tx_native[4][1:]),
                query=_binary_decode(tx_native[5]),
                query_fee=_int_decode(tx_native[6]),
                query_ttl=dict(
                    type=idf.ORACLE_TTL_TYPE_DELTA if _int_decode(tx_native[7]) else idf.ORACLE_TTL_TYPE_BLOCK,
                    value=_int_decode(tx_native[8]),
                ),
                response_ttl=dict(
                    type=idf.ORACLE_TTL_TYPE_DELTA if _int_decode(tx_native[9]) else idf.ORACLE_TTL_TYPE_BLOCK,
                    value=_int_decode(tx_native[10]),
                ),
                fee=_int_decode(tx_native[11]),
                ttl=_int_decode(tx_native[12]),
            )
            min_fee = tx_data.get("fee")
        else:
            raise Exception("Invalid operation")
        return build_tx_object(tx_data, tx_native, tx_field_fee_index, min_fee)

    elif tag == idf.OBJECT_TAG_ORACLE_RESPONSE_TRANSACTION:
        tx_field_fee_index = 8
        if op == PACK_TX:  # pack transaction
            response_ttl = kwargs.get("response_ttl", {})
            tx_native = [
                _int(tag),
                _int(vsn),
                _id(idf.ID_TAG_ORACLE, kwargs.get("oracle_id")),
                _int(kwargs.get("nonce")),
                decode(kwargs.get("query_id")),
                _binary(kwargs.get("response")),
                _int(0 if response_ttl.get("type") == idf.ORACLE_TTL_TYPE_DELTA else 1),
                _int(response_ttl.get("value")),
                _int(kwargs.get("fee")),
                _int(kwargs.get("ttl")),
            ]
            min_fee = oracle_fee(tx_native, tx_field_fee_index, response_ttl.get("value"))
        elif op == UNPACK_TX:  # unpack transaction
            vml = len(tx_native[5])  # this is used to extract the abi and vm version from the 5th field
            tx_data = dict(
                tag=tag,
                vsn=_int_decode(tx_native[1]),
                oracle_id=encode(idf.ORACLE_ID, tx_native[2][1:]),
                nonce=_int_decode(tx_native[3]),
                query_id=encode(idf.ORACLE_QUERY_ID, tx_native[4][1:]),
                response=_binary(tx_native[5]),
                response_ttl=dict(
                    type=idf.ORACLE_TTL_TYPE_DELTA if _int_decode(tx_native[6]) else idf.ORACLE_TTL_TYPE_BLOCK,
                    value=_int_decode(tx_native[7]),
                ),
                fee=_int_decode(tx_native[8]),
                ttl=_int_decode(tx_native[9]),
            )
            min_fee = tx_data.get("fee")
        else:
            raise Exception("Invalid operation")
        return build_tx_object(tx_data, tx_native, tx_field_fee_index, min_fee)

    elif tag == idf.OBJECT_TAG_ORACLE_EXTEND_TRANSACTION:
        tx_field_fee_index = 6
        if op == PACK_TX:  # pack transaction
            oracle_ttl = kwargs.get("oracle_ttl", {})
            tx_native = [
                _int(tag),
                _int(vsn),
                _id(idf.ID_TAG_ORACLE, kwargs.get("oracle_id")),
                _int(kwargs.get("nonce")),
                _int(0 if oracle_ttl.get("type", {}) == idf.ORACLE_TTL_TYPE_DELTA else 1),
                _int(oracle_ttl.get("value")),
                _int(kwargs.get("fee")),
                _int(kwargs.get("ttl")),
            ]
            min_fee = oracle_fee(tx_native, tx_field_fee_index, oracle_ttl.get("value"))
        elif op == UNPACK_TX:  # unpack transaction
            vml = len(tx_native[5])  # this is used to extract the abi and vm version from the 5th field
            tx_data = dict(
                tag=tag,
                vsn=_int_decode(tx_native[1]),
                oracle_id=encode(idf.ORACLE_ID, tx_native[2][1:]),
                nonce=_int_decode(tx_native[3]),
                oracle_ttl=dict(
                    type=idf.ORACLE_TTL_TYPE_DELTA if _int_decode(tx_native[4]) else idf.ORACLE_TTL_TYPE_BLOCK,
                    value=_int_decode(tx_native[5]),
                ),
                fee=_int_decode(tx_native[6]),
                ttl=_int_decode(tx_native[7]),
            )
            min_fee = tx_data.get("fee")
        else:
            raise Exception("Invalid operation")
        return build_tx_object(tx_data, tx_native, tx_field_fee_index, min_fee)
    else:
        raise UnsupportedTransactionType(f"Unusupported transaction tag {tag}")