##############################################################################
#
#                        Crossbar.io FX
#     Copyright (C) Crossbar.io Technologies GmbH. All rights reserved.
#
##############################################################################

import pprint
import uuid

import flatbuffers
import numpy as np

from zlmdb import time_ns
from zlmdb import table, MapBytes20FlatBuffers, MapBytes32FlatBuffers, MapUuidUuid, MapUuidFlatBuffers,\
    MapBytes16FlatBuffers, MapBytes20Bytes16, MapBytes20TimestampBytes20, MapUuidBytes20Uint8FlatBuffers

from .common import pack_uint256, unpack_uint256
from .gen.xbr import PaymentChannelType as PaymentChannelTypeGen
from .gen.xbr import PaymentChannelState as PaymentChannelStateGen
from .gen.xbr import PayingChannelRequestState as PayingChannelRequestStateGen
from .gen.xbr import Member as MemberGen
from .gen.xbr import Actor as ActorGen
from .gen.xbr import TokenApproval as TokenApprovalGen
from .gen.xbr import TokenTransfer as TokenTransferGen
from .gen.xbr import PaymentChannel as PaymentChannelGen
from .gen.xbr import Offer as OfferGen
from .gen.xbr import Market as MarketGen
from .gen.xbr import PaymentChannelBalance as PaymentChannelBalanceGen
from .gen.xbr import Transaction as TransactionGen
from .gen.xbr import PayingChannelRequest as PayingChannelRequestGen
from .gen.xbr import Block as BlockGen

PaymentChannelType = PaymentChannelTypeGen.PaymentChannelType
PaymentChannelState = PaymentChannelStateGen.PaymentChannelState
PayingChannelRequestState = PayingChannelRequestStateGen.PayingChannelRequestState


class _BlockGen(BlockGen.Block):
    """
    Expand methods on the class code generated by flatc.

    FIXME: come up with a PR for flatc to generated this stuff automatically.
    """

    @classmethod
    def GetRootAsOffer(cls, buf, offset):
        n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
        x = _BlockGen()
        x.Init(buf, n + offset)
        return x

    def BlockNumberAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def BlockHashAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None


class Block(object):

    def __init__(self, from_fbs=None):
        self._from_fbs = from_fbs

        # uint64
        self._timestamp = None

        # [uint8] (uint256)
        self._block_number = None

        # [uint8]
        self._block_hash = None

        # uint32
        self._cnt_events = None

    def marshal(self):
        obj = {
            'timestamp': int(self.timestamp) if self.timestamp else None,
            'block_number': pack_uint256(self.block_number) if self.block_number else 0,
            'block_hash': bytes(self.block_hash) if self.block_hash else None,
        }
        return obj

    def __str__(self):
        return '\n{}\n'.format(pprint.pformat(self.marshal()))

    @property
    def timestamp(self):
        if self._timestamp is None and self._from_fbs:
            self._timestamp = np.datetime64(self._from_fbs.Timestamp(), 'ns')
        return self._timestamp

    @timestamp.setter
    def timestamp(self, value):
        assert value is None or isinstance(value, np.datetime64)
        self._timestamp = value

    @property
    def block_hash(self):
        if self._block_hash is None and self._from_fbs:
            if self._from_fbs.BlockHashLength():
                self._block_hash = self._from_fbs.BlockHashAsBytes()
        return self._block_hash

    @block_hash.setter
    def block_hash(self, value):
        assert value is None or type(value) == bytes
        self._block_hash = value

    @property
    def block_number(self):
        if self._block_number is None and self._from_fbs:
            if self._from_fbs.BlockNumberLength():
                _block_number = self._from_fbs.BlockNumberAsBytes()
                self._block_number = unpack_uint256(bytes(_block_number))
            else:
                self._block_number = 0
        return self._block_number

    @block_number.setter
    def block_number(self, value):
        assert value is None or type(value) == int
        self._block_number = value

    @property
    def cnt_events(self):
        return self._cnt_events

    @cnt_events.setter
    def cnt_events(self, value):
        assert value is None or type(value) == int
        self._cnt_events = value

    @staticmethod
    def cast(buf):
        return Block(_BlockGen.GetRootAsOffer(buf, 0))

    def build(self, builder):

        block_number = self.block_number
        if block_number:
            block_number = builder.CreateString(pack_uint256(block_number))

        block_hash = self.block_hash
        if block_hash:
            block_hash = builder.CreateString(block_hash)

        BlockGen.BlockStart(builder)

        if self.timestamp:
            BlockGen.BlockAddTimestamp(builder, int(self.timestamp))

        if block_number:
            BlockGen.BlockAddBlockNumber(builder, block_number)

        if block_hash:
            BlockGen.BlockAddBlockHash(builder, block_hash)

        if self.cnt_events:
            BlockGen.BlockAddCntEvents(builder, self.cnt_events)

        final = BlockGen.BlockEnd(builder)

        return final


@table('a4a0553e-24fa-4280-9959-5805f034d861', build=Block.build, cast=Block.cast)
class Blocks(MapBytes32FlatBuffers):
    """
    Blockchain blocks processed.

    Map :class:`zlmdb.MapBytes32FlatBuffers` from ``block_number`` to :class:`crossbarfx.cfxdb.xbr.Block`
    """


class _MemberGen(MemberGen.Member):
    """
    Expand methods on the class code generated by flatc.

    FIXME: come up with a PR for flatc to generated this stuff automatically.
    """

    @classmethod
    def GetRootAsMember(cls, buf, offset):
        n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
        x = _MemberGen()
        x.Init(buf, n + offset)
        return x

    def AddressAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def RegisteredAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None


class Member(object):
    """
    ``XBRNetwork.Member`` event database object.
    """

    def __init__(self, from_fbs=None):
        self._from_fbs = from_fbs

        # [uint8] (address)
        self._address = None

        # uint64 (timestamp)
        self._timestamp = None

        # [uint8] (uint256)
        self._registered = None

        # string (multihash)
        self._eula = None

        # string (multihash)
        self._profile = None

        # enum MemberLevel: uint8
        self._level = None

    def marshal(self):
        obj = {
            'address': self.address,
            'timestamp': self.timestamp,
            'registered': self.registered,
            'eula': self.eula,
            'profile': self.profile,
            'level': self.level,
        }
        return obj

    def __str__(self):
        return '\n{}\n'.format(pprint.pformat(self.marshal()))

    @property
    def address(self):
        if self._address is None and self._from_fbs:
            if self._from_fbs.AddressLength():
                self._address = self._from_fbs.AddressAsBytes()
        return self._address

    @address.setter
    def address(self, value):
        assert value is None or (type(value) == bytes and len(value) == 20)
        self._address = value

    @property
    def timestamp(self):
        if self._timestamp is None and self._from_fbs:
            self._timestamp = np.datetime64(self._from_fbs.Timestamp(), 'ns')
        return self._timestamp

    @timestamp.setter
    def timestamp(self, value):
        assert value is None or isinstance(value, np.datetime64)
        self._timestamp = value

    @property
    def registered(self):
        if self._registered is None and self._from_fbs:
            if self._from_fbs.RegisteredLength():
                _registered = self._from_fbs.RegisteredAsBytes()
                self._registered = unpack_uint256(bytes(_registered))
            else:
                self._registered = 0
        return self._registered

    @registered.setter
    def registered(self, value):
        assert value is None or type(value) == int
        self._registered = value

    @property
    def eula(self):
        if self._eula is None and self._from_fbs:
            eula = self._from_fbs.Eula()
            if eula:
                self._eula = eula.decode('utf8')
        return self._eula

    @eula.setter
    def eula(self, value):
        assert value is None or type(value) == str
        self._eula = value

    @property
    def profile(self):
        if self._profile is None and self._from_fbs:
            profile = self._from_fbs.Profile()
            if profile:
                self._profile = profile.decode('utf8')
        return self._profile

    @profile.setter
    def profile(self, value):
        assert value is None or type(value) == str
        self._profile = value

    @property
    def level(self):
        if self._level is None and self._from_fbs:
            self._level = self._from_fbs.Level()
        return self._level

    @level.setter
    def level(self, value):
        assert value is None or type(value) == int
        self._level = value

    @staticmethod
    def cast(buf):
        return Member(_MemberGen.GetRootAsMember(buf, 0))

    def build(self, builder):

        address = self.address
        if address:
            address = builder.CreateString(address)

        registered = self.registered
        if registered:
            registered = builder.CreateString(pack_uint256(registered))

        eula = self.eula
        if eula:
            eula = builder.CreateString(eula)

        profile = self.profile
        if profile:
            profile = builder.CreateString(profile)

        MemberGen.MemberStart(builder)

        if address:
            MemberGen.MemberAddAddress(builder, address)

        if self.timestamp:
            MemberGen.MemberAddTimestamp(builder, int(self.timestamp))

        if registered:
            MemberGen.MemberAddRegistered(builder, registered)

        if eula:
            MemberGen.MemberAddEula(builder, eula)

        if profile:
            MemberGen.MemberAddProfile(builder, profile)

        if self.level:
            MemberGen.MemberAddLevel(builder, self.level)

        final = MemberGen.MemberEnd(builder)

        return final


@table('d1808139-5a3b-4a4e-abad-152dd4cd1131', build=Member.build, cast=Member.cast)
class Members(MapBytes20FlatBuffers):
    """
    XBR membery by ``member_adr``.

    Map :class:`zlmdb.MapBytes20FlatBuffers` from ``member_adr`` to :class:`crossbarfx.cfxdb.xbr.Member`
    """


class _MarketGen(MarketGen.Market):
    """
    Expand methods on the class code generated by flatc.

    FIXME: come up with a PR for flatc to generated this stuff automatically.
    """

    @classmethod
    def GetRootAsMarket(cls, buf, offset):
        n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
        x = _MarketGen()
        x.Init(buf, n + offset)
        return x

    def MarketAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def OwnerAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(10))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def MakerAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(16))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def ProviderSecurityAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(18))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def ConsumerSecurityAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(20))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def MarketFeeAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(22))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None


class Market(object):
    """
    ``XBRNetwork.Market`` event database object.
    """

    def __init__(self, from_fbs=None):
        self._from_fbs = from_fbs

        # [uint8] (uuid)
        self._market = None

        # uint64 (timestamp)
        self._timestamp = None

        # uint32
        self._seq = None

        # [uint8] (address)
        self._owner = None

        # string (multihash)
        self._terms = None

        # string (multihash)
        self._meta = None

        # [uint8] (address)
        self._maker = None

        # [uint8] (uint256)
        self._provider_security = None

        # [uint8] (uint256)
        self._consumer_security = None

        # [uint8] (uint256)
        self._market_fee = None

    def marshal(self):
        obj = {
            'market': self.market,
            'timestamp': self.timestamp,
            'seq': self.seq,
            'owner': self.owner,
            'terms': self.terms,
            'meta': self.meta,
            'maker': self.maker,
            'provider_security': self.provider_security,
            'consumer_security': self.consumer_security,
            'market_fee': self.market_fee,
        }
        return obj

    def __str__(self):
        return '\n{}\n'.format(pprint.pformat(self.marshal()))

    @property
    def market(self):
        if self._market is None and self._from_fbs:
            if self._from_fbs.MarketLength():
                _market = self._from_fbs.MarketAsBytes()
                self._market = uuid.UUID(bytes=bytes(_market))
        return self._market

    @market.setter
    def market(self, value):
        assert value is None or isinstance(value, uuid.UUID)
        self._market = value

    @property
    def timestamp(self):
        if self._timestamp is None and self._from_fbs:
            self._timestamp = np.datetime64(self._from_fbs.Timestamp(), 'ns')
        return self._timestamp

    @timestamp.setter
    def timestamp(self, value):
        assert value is None or isinstance(value, np.datetime64)
        self._timestamp = value

    @property
    def seq(self):
        if self._seq is None and self._from_fbs:
            self._seq = self._from_fbs.Seq()
        return self._seq or 0

    @seq.setter
    def seq(self, value):
        assert value is None or type(value) == int
        self._seq = value

    @property
    def owner(self):
        if self._owner is None and self._from_fbs:
            if self._from_fbs.OwnerLength():
                self._owner = self._from_fbs.OwnerAsBytes()
        return self._owner

    @owner.setter
    def owner(self, value):
        assert value is None or (type(value) == bytes and len(value) == 20)
        self._owner = value

    @property
    def terms(self):
        if self._terms is None and self._from_fbs:
            terms = self._from_fbs.Terms()
            if terms:
                self._terms = terms.decode('utf8')
        return self._terms

    @terms.setter
    def terms(self, value):
        assert value is None or type(value) == str
        self._terms = value

    @property
    def meta(self):
        if self._meta is None and self._from_fbs:
            meta = self._from_fbs.Meta()
            if meta:
                self._meta = meta.decode('utf8')
        return self._meta

    @meta.setter
    def meta(self, value):
        assert value is None or type(value) == str
        self._meta = value

    @property
    def maker(self):
        if self._maker is None and self._from_fbs:
            if self._from_fbs.MakerLength():
                self._maker = self._from_fbs.MakerAsBytes()
        return self._maker

    @maker.setter
    def maker(self, value):
        assert value is None or (type(value) == bytes and len(value) == 20)
        self._maker = value

    @property
    def provider_security(self):
        if self._provider_security is None and self._from_fbs:
            if self._from_fbs.ProviderSecurityLength():
                _provider_security = self._from_fbs.ProviderSecurityAsBytes()
                self._provider_security = unpack_uint256(bytes(_provider_security))
            else:
                self._provider_security = 0
        return self._provider_security

    @provider_security.setter
    def provider_security(self, value):
        assert value is None or type(value) == int
        self._provider_security = value

    @property
    def consumer_security(self):
        if self._consumer_security is None and self._from_fbs:
            if self._from_fbs.ConsumerSecurityLength():
                _consumer_security = self._from_fbs.ConsumerSecurityAsBytes()
                self._consumer_security = unpack_uint256(bytes(_consumer_security))
            else:
                self._consumer_security = 0
        return self._consumer_security

    @consumer_security.setter
    def consumer_security(self, value):
        assert value is None or type(value) == int
        self._consumer_security = value

    @property
    def market_fee(self):
        if self._market_fee is None and self._from_fbs:
            if self._from_fbs.MarketFeeLength():
                _market_fee = self._from_fbs.MarketFeeAsBytes()
                self._market_fee = unpack_uint256(bytes(_market_fee))
            else:
                self._market_fee = 0
        return self._market_fee

    @market_fee.setter
    def market_fee(self, value):
        assert value is None or type(value) == int
        self._market_fee = value

    @staticmethod
    def cast(buf):
        return Market(_MarketGen.GetRootAsMarket(buf, 0))

    def build(self, builder):

        market = self.market.bytes if self.market else None
        if market:
            market = builder.CreateString(market)

        owner = self.owner
        if owner:
            owner = builder.CreateString(owner)

        terms = self.terms
        if terms:
            terms = builder.CreateString(terms)

        meta = self.meta
        if meta:
            meta = builder.CreateString(meta)

        maker = self.maker
        if maker:
            maker = builder.CreateString(maker)

        provider_security = self.provider_security
        if provider_security:
            provider_security = builder.CreateString(pack_uint256(provider_security))

        consumer_security = self.consumer_security
        if consumer_security:
            consumer_security = builder.CreateString(pack_uint256(consumer_security))

        market_fee = self.market_fee
        if market_fee:
            market_fee = builder.CreateString(pack_uint256(market_fee))

        MarketGen.MarketStart(builder)

        if market:
            MarketGen.MarketAddMarket(builder, market)

        if self.timestamp:
            MarketGen.MarketAddTimestamp(builder, int(self.timestamp))

        if self.seq:
            MarketGen.MarketAddSeq(builder, self.seq)

        if owner:
            MarketGen.MarketAddOwner(builder, owner)

        if terms:
            MarketGen.MarketAddTerms(builder, terms)

        if meta:
            MarketGen.MarketAddMeta(builder, meta)

        if maker:
            MarketGen.MarketAddMaker(builder, maker)

        if provider_security:
            MarketGen.MarketAddProviderSecurity(builder, provider_security)

        if consumer_security:
            MarketGen.MarketAddConsumerSecurity(builder, consumer_security)

        if market_fee:
            MarketGen.MarketAddMarketFee(builder, market_fee)

        final = MarketGen.MarketEnd(builder)

        return final


@table('861b0942-0c3f-4d41-bc35-d8c86af0b2c9', build=Market.build, cast=Market.cast)
class Markets(MapUuidFlatBuffers):
    """
    Persisted market definitions.

    Map :class:`zlmdb.MapUuidFlatBuffers` from ``market_id`` to :class:`crossbarfx.cfxdb.xbr.Market`
    """


class _ActorGen(ActorGen.Actor):
    """
    Expand methods on the class code generated by flatc.

    FIXME: come up with a PR for flatc to generated this stuff automatically.
    """

    @classmethod
    def GetRootAsActor(cls, buf, offset):
        n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
        x = _ActorGen()
        x.Init(buf, n + offset)
        return x

    def MarketAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def ActorAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def JoinedAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(12))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def SecurityAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(14))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None


class Actor(object):
    """
    ``XBRNetwork.Actor`` event database object.
    """

    def __init__(self, from_fbs=None):
        self._from_fbs = from_fbs

        # uint64 (timestamp)
        self._timestamp = None

        # [uint8] (uuid)
        self._market = None

        # [uint8] (address)
        self._actor = None

        # uint8 (ActorType)
        self._actor_type = None

        # [uint8] (uint256)
        self._joined = None

        # [uint8] (uint256)
        self._security = None

        # string (multihash)
        self._meta = None

    def marshal(self):
        obj = {
            'timestamp': self.timestamp,
            'market': self.market,
            'actor': self.actor,
            'actor_type': self.actor_type,
            'joined': self.joined,
            'security': self.security,
            'meta': self.meta,
        }
        return obj

    def __str__(self):
        return '\n{}\n'.format(pprint.pformat(self.marshal()))

    @property
    def timestamp(self):
        if self._timestamp is None and self._from_fbs:
            self._timestamp = np.datetime64(self._from_fbs.Timestamp(), 'ns')
        return self._timestamp

    @timestamp.setter
    def timestamp(self, value):
        assert value is None or isinstance(value, np.datetime64)
        self._timestamp = value

    @property
    def market(self):
        if self._market is None and self._from_fbs:
            if self._from_fbs.MarketLength():
                _market = self._from_fbs.MarketAsBytes()
                self._market = uuid.UUID(bytes=bytes(_market))
        return self._market

    @market.setter
    def market(self, value):
        assert value is None or isinstance(value, uuid.UUID)
        self._market = value

    @property
    def actor(self):
        if self._actor is None and self._from_fbs:
            if self._from_fbs.ActorLength():
                self._actor = self._from_fbs.ActorAsBytes()
        return self._actor

    @actor.setter
    def actor(self, value):
        assert value is None or (type(value) == bytes and len(value) == 20)
        self._actor = value

    @property
    def actor_type(self):
        if self._actor_type is None and self._from_fbs:
            self._actor_type = self._from_fbs.ActorType()
        return self._actor_type

    @actor_type.setter
    def actor_type(self, value):
        assert value is None or type(value) == int
        self._actor_type = value

    @property
    def joined(self):
        if self._joined is None and self._from_fbs:
            if self._from_fbs.JoinedLength():
                _joined = self._from_fbs.JoinedAsBytes()
                self._joined = unpack_uint256(bytes(_joined))
            else:
                self._joined = 0
        return self._joined

    @joined.setter
    def joined(self, value):
        assert value is None or type(value) == int
        self._joined = value

    @property
    def security(self):
        if self._security is None and self._from_fbs:
            if self._from_fbs.SecurityLength():
                security = self._from_fbs.SecurityAsBytes()
                self._security = unpack_uint256(bytes(security))
            else:
                self._security = 0
        return self._security

    @security.setter
    def security(self, value):
        assert value is None or type(value) == int, 'security must be int, was: {}'.format(value)
        self._security = value

    @property
    def meta(self):
        if self._meta is None and self._from_fbs:
            meta = self._from_fbs.Meta()
            if meta:
                self._meta = meta.decode('utf8')
        return self._meta

    @meta.setter
    def meta(self, value):
        assert value is None or type(value) == str
        self._meta = value

    @staticmethod
    def cast(buf):
        return Actor(_ActorGen.GetRootAsActor(buf, 0))

    def build(self, builder):

        market = self.market.bytes if self.market else None
        if market:
            market = builder.CreateString(market)

        actor = self.actor
        if actor:
            actor = builder.CreateString(actor)

        joined = self.joined
        if joined:
            joined = builder.CreateString(pack_uint256(joined))

        security = self.security
        if security:
            security = builder.CreateString(pack_uint256(security))

        meta = self.meta
        if meta:
            meta = builder.CreateString(meta)

        ActorGen.ActorStart(builder)

        if self.timestamp:
            ActorGen.ActorAddTimestamp(builder, int(self.timestamp))

        if market:
            ActorGen.ActorAddMarket(builder, market)

        if actor:
            ActorGen.ActorAddActor(builder, actor)

        if self.actor_type:
            ActorGen.ActorAddActorType(builder, self.actor_type)

        if joined:
            ActorGen.ActorAddJoined(builder, joined)

        if security:
            ActorGen.ActorAddSecurity(builder, security)

        if meta:
            ActorGen.ActorAddMeta(builder, meta)

        final = ActorGen.ActorEnd(builder)

        return final


@table('1863eb64-322a-42dd-9fce-a59c99d5b40e', build=Actor.build, cast=Actor.cast)
class Actors(MapUuidBytes20Uint8FlatBuffers):
    """
    Persisted market actors.

    Map :class:`zlmdb.MapUuidBytes20Uint8FlatBuffers` from ``(market_id, actor_adr, actor_type)`` to :class:`crossbarfx.cfxdb.xbr.Actor`
    """


class _OfferGen(OfferGen.Offer):
    """
    Expand methods on the class code generated by flatc.

    FIXME: come up with a PR for flatc to generated this stuff automatically.
    """

    @classmethod
    def GetRootAsOffer(cls, buf, offset):
        n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
        x = _OfferGen()
        x.Init(buf, n + offset)
        return x

    def OfferAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def SellerAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def KeyAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(14))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def ApiAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(16))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def UriAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(18))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def SignatureAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(22))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def PriceAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(24))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None


class Offer(object):

    def __init__(self, from_fbs=None):
        self._from_fbs = from_fbs

        # uint64
        self._timestamp = None

        # [uint8] (uuid)
        self._offer = None

        # [uint8] (address)
        self._seller = None

        # uint64
        self._seller_session_id = None

        # string
        self._seller_authid = None

        # [uint8] (uuid)
        self._key = None

        # [uint8] (uuid)
        self._api = None

        # string
        self._uri = None

        # uint64
        self._valid_from = None

        # [uint8]
        self._signature = None

        # [uint8] (uint256)
        self._price = None

        # [KeyValue]
        self._categories = None

        # uint64
        self._expires = None

        # uint32
        self._copies = None

        # uint32
        self._remaining = None

    def marshal(self):
        obj = {
            'timestamp': int(self.timestamp) if self.timestamp else None,
            'offer': self.offer.bytes if self.offer else None,
            'seller': bytes(self.seller) if self.seller else None,
            'seller_session_id': self.seller_session_id,
            'seller_authid': self.seller_authid,
            'key': self.key.bytes if self.key else None,
            'api': self.api.bytes if self.api else None,
            'uri': self.uri,
            'valid_from': int(self.valid_from) if self.valid_from else None,
            'signature': bytes(self.signature) if self.signature else None,
            'price': pack_uint256(self.price) if self.price else 0,
            'categories': self.categories,
            'expires': int(self.expires) if self.expires else None,
            'copies': self.copies,
            'remaining': self.remaining,
        }
        return obj

    def __str__(self):
        return '\n{}\n'.format(pprint.pformat(self.marshal()))

    @property
    def timestamp(self):
        if self._timestamp is None and self._from_fbs:
            self._timestamp = np.datetime64(self._from_fbs.Timestamp(), 'ns')
        return self._timestamp

    @timestamp.setter
    def timestamp(self, value):
        assert value is None or isinstance(value, np.datetime64)
        self._timestamp = value

    @property
    def offer(self):
        if self._offer is None and self._from_fbs:
            if self._from_fbs.OfferLength():
                _offer = self._from_fbs.OfferAsBytes()
                self._offer = uuid.UUID(bytes=bytes(_offer))
        return self._offer

    @offer.setter
    def offer(self, value):
        assert value is None or isinstance(value, uuid.UUID)
        self._offer = value

    @property
    def seller(self):
        if self._seller is None and self._from_fbs:
            if self._from_fbs.SellerLength():
                self._seller = self._from_fbs.SellerAsBytes()
        return self._seller

    @seller.setter
    def seller(self, value):
        assert value is None or (type(value) == bytes and len(value) == 20)
        self._seller = value

    @property
    def seller_session_id(self):
        if self._seller_session_id is None and self._from_fbs:
            self._seller_session_id = self._from_fbs.SellerSessionId()
        return self._seller_session_id

    @seller_session_id.setter
    def seller_session_id(self, value):
        assert value is None or type(value) == int
        self._seller_session_id = value

    @property
    def seller_authid(self):
        if self._seller_authid is None and self._from_fbs:
            _seller_authid = self._from_fbs.SellerAuthid()
            if _seller_authid:
                self._seller_authid = _seller_authid.decode('utf8')
        return self._seller_authid

    @seller_authid.setter
    def seller_authid(self, value):
        self._seller_authid = value

    @property
    def key(self):
        if self._key is None and self._from_fbs:
            if self._from_fbs.KeyLength():
                _key = self._from_fbs.KeyAsBytes()
                self._key = uuid.UUID(bytes=bytes(_key))
        return self._key

    @key.setter
    def key(self, value):
        assert value is None or isinstance(value, uuid.UUID)
        self._key = value

    @property
    def api(self):
        if self._api is None and self._from_fbs:
            if self._from_fbs.ApiLength():
                _api = self._from_fbs.ApiAsBytes()
                self._api = uuid.UUID(bytes=bytes(_api))
        return self._api

    @api.setter
    def api(self, value):
        assert value is None or isinstance(value, uuid.UUID)
        self._api = value

    @property
    def uri(self):
        if self._uri is None and self._from_fbs:
            _uri = self._from_fbs.Uri()
            if _uri:
                self._uri = _uri.decode('utf8')
        return self._uri

    @uri.setter
    def uri(self, value):
        self._uri = value

    @property
    def valid_from(self):
        if self._valid_from is None and self._from_fbs:
            self._valid_from = np.datetime64(self._from_fbs.ValidFrom(), 'ns')
        return self._valid_from

    @valid_from.setter
    def valid_from(self, value):
        assert value is None or isinstance(value, np.datetime64)
        self._valid_from = value

    @property
    def signature(self):
        if self._signature is None and self._from_fbs:
            if self._from_fbs.SignatureLength():
                self._signature = self._from_fbs.SignatureAsBytes()
        return self._signature

    @signature.setter
    def signature(self, value):
        assert value is None or type(value) == bytes
        self._signature = value

    @property
    def price(self):
        if self._price is None and self._from_fbs:
            if self._from_fbs.PriceLength():
                _price = self._from_fbs.PriceAsBytes()
                self._price = unpack_uint256(bytes(_price))
            else:
                self._price = 0
        return self._price

    @price.setter
    def price(self, value):
        assert value is None or type(value) == int
        self._price = value

    @property
    def categories(self):
        if self._categories is None and self._from_fbs:
            num = self._from_fbs.CategoriesKeyLength()
            if num > 0:
                categories = {}
                for i in range(num):
                    key = self._from_fbs.CategoriesKey(i).decode('utf8')
                    value = self._from_fbs.CategoriesValue(i).decode('utf8')
                    categories[key] = value
                self._categories = categories
        return self._categories

    @categories.setter
    def categories(self, values):
        assert values is None or type(values) == dict
        if values:
            assert (type(key) == str for key in values.keys())
            assert (type(value) == str for value in values.values())
        self._categories = values

    @property
    def expires(self):
        if self._expires is None and self._from_fbs:
            self._expires = np.datetime64(self._from_fbs.Expires(), 'ns')
        return self._expires

    @expires.setter
    def expires(self, value):
        assert value is None or isinstance(value, np.datetime64)
        self._expires = value

    @property
    def copies(self):
        if self._copies is None and self._from_fbs:
            self._copies = self._from_fbs.Copies()
        return self._copies

    @copies.setter
    def copies(self, value):
        assert value is None or type(value) == int
        self._copies = value

    @property
    def remaining(self):
        if self._remaining is None and self._from_fbs:
            self._remaining = self._from_fbs.Remaining()
        return self._remaining

    @remaining.setter
    def remaining(self, value):
        assert value is None or type(value) == int
        self._remaining = value

    @staticmethod
    def cast(buf):
        return Offer(_OfferGen.GetRootAsOffer(buf, 0))

    def build(self, builder):

        offer = self.offer.bytes if self.offer else None
        if offer:
            offer = builder.CreateString(offer)

        seller = self.seller
        if seller:
            seller = builder.CreateString(seller)

        seller_authid = self.seller_authid
        if seller_authid:
            seller_authid = builder.CreateString(seller_authid)

        key = self.key.bytes if self.key else None
        if key:
            key = builder.CreateString(key)

        api = self.api.bytes if self.api else None
        if api:
            api = builder.CreateString(api)

        uri = self.uri
        if uri:
            uri = builder.CreateString(uri)

        signature = self.signature
        if signature:
            signature = builder.CreateString(signature)

        price = self.price
        if price:
            price = builder.CreateString(pack_uint256(price))

        categories_keys_vec = None
        categories_values_vec = None

        if self._categories:
            categories_keys = []
            categories_values = []
            for _key, _value in sorted(self._categories.items()):
                assert type(_key) == str, 'category key must be string, but was {}: {}'.format(type(_key), _key)
                assert type(_value) == str, 'category value must be string, but was {}: {}'.format(type(_value), _value)
                categories_keys.append(builder.CreateString(_key))
                categories_values.append(builder.CreateString(_value))

            OfferGen.OfferStartCategoriesKeyVector(builder, len(categories_keys))
            for _key in categories_keys:
                builder.PrependUOffsetTRelative(_key)
            categories_keys_vec = builder.EndVector(len(categories_keys))

            OfferGen.OfferStartCategoriesValueVector(builder, len(categories_values))
            for _value in categories_values:
                builder.PrependUOffsetTRelative(_value)
            categories_values_vec = builder.EndVector(len(categories_values))

        OfferGen.OfferStart(builder)

        if self.timestamp:
            OfferGen.OfferAddTimestamp(builder, int(self.timestamp))

        if offer:
            OfferGen.OfferAddOffer(builder, offer)

        if seller:
            OfferGen.OfferAddSeller(builder, seller)

        if self.seller_session_id:
            OfferGen.OfferAddSellerSessionId(builder, self.seller_session_id)

        if seller_authid:
            OfferGen.OfferAddSellerAuthid(builder, seller_authid)

        if key:
            OfferGen.OfferAddKey(builder, key)

        if api:
            OfferGen.OfferAddApi(builder, api)

        if uri:
            OfferGen.OfferAddUri(builder, uri)

        if self.valid_from:
            OfferGen.OfferAddValidFrom(builder, int(self.valid_from))

        if signature:
            OfferGen.OfferAddSignature(builder, signature)

        if price:
            OfferGen.OfferAddPrice(builder, price)

        if categories_keys_vec:
            OfferGen.OfferAddCategoriesKey(builder, categories_keys_vec)

        if categories_values_vec:
            OfferGen.OfferAddCategoriesValue(builder, categories_values_vec)

        if self.expires:
            OfferGen.OfferAddExpires(builder, int(self.expires))

        if self.copies:
            OfferGen.OfferAddCopies(builder, self.copies)

        if self.remaining:
            OfferGen.OfferAddRemaining(builder, self.remaining)

        final = OfferGen.OfferEnd(builder)

        return final


@table('dc6d175b-3dd0-4b1f-a6e8-2aec7f0e3fe5', build=Offer.build, cast=Offer.cast)
class Offers(MapUuidFlatBuffers):
    """
    Persisted data encryption key offers.

    Map :class:`zlmdb.MapBytes32FlatBuffers` from ``offer_id`` to :class:`crossbarfx.cfxdb.xbr.Offer`
    """


@table('ef5f1cdc-4871-4a03-ac1c-c60e80875b8b')
class IndexOfferByKey(MapUuidUuid):
    """
    Index: key_id -> offer_id
    """


class _TokenApprovalGen(TokenApprovalGen.TokenApproval):
    """
    Expand methods on the class code generated by flatc.

    FIXME: come up with a PR for flatc to generated this stuff automatically.
    """

    @classmethod
    def GetRootAsTokenApproval(cls, buf, offset):
        n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
        x = _TokenApprovalGen()
        x.Init(buf, n + offset)
        return x

    def TxHashAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def BlockHashAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def OwnerAddressAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def SpenderAddressAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(10))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def ValueAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(12))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None


class TokenApproval(object):
    """
    ``IERC20.TokenApproval`` event database object.
    """

    def __init__(self, from_fbs=None):
        self._from_fbs = from_fbs

        self._tx_hash = None
        self._block_hash = None
        self._owner_address = None
        self._spender_address = None
        self._value = None

    def marshal(self):
        obj = {
            'tx_hash': self._tx_hash,
            'block_hash': self._block_hash,
            'from_address': self._owner_address,
            'to_address': self._spender_address,
            'value': self._value,
        }
        return obj

    def __str__(self):
        return '\n{}\n'.format(pprint.pformat(self.marshal()))

    @property
    def tx_hash(self):
        if self._tx_hash is None and self._from_fbs:
            if self._from_fbs.TxHashLength():
                self._tx_hash = self._from_fbs.TxHashAsBytes()
        return self._tx_hash

    @tx_hash.setter
    def tx_hash(self, value):
        assert value is None or type(value) == bytes
        self._tx_hash = value

    @property
    def block_hash(self):
        if self._block_hash is None and self._from_fbs:
            if self._from_fbs.TxHashLength():
                self._block_hash = self._from_fbs.BlockHashAsBytes()
        return self._block_hash

    @block_hash.setter
    def block_hash(self, value):
        assert value is None or type(value) == bytes
        self._block_hash = value

    @property
    def owner_address(self):
        if self._owner_address is None and self._from_fbs:
            if self._from_fbs.OwnerAddressLength():
                self._owner_address = self._from_fbs.OwnerAddressAsBytes()
        return self._owner_address

    @owner_address.setter
    def owner_address(self, value):
        assert value is None or type(value) == bytes
        self._owner_address = value

    @property
    def spender_address(self):
        if self._spender_address is None and self._from_fbs:
            if self._from_fbs.TxHashLength():
                self._spender_address = self._from_fbs.SpenderAddressAsBytes()
        return self._spender_address

    @spender_address.setter
    def spender_address(self, value):
        assert value is None or type(value) == bytes
        self._spender_address = value

    @property
    def value(self):
        if self._value is None and self._from_fbs:
            if self._from_fbs.ValueLength():
                _value = self._from_fbs.ValueAsBytes()
                self._value = unpack_uint256(bytes(_value))
            else:
                self._value = 0
        return self._value

    @value.setter
    def value(self, value):
        assert value is None or type(value) == int
        self._value = value

    @staticmethod
    def cast(buf):
        return TokenApproval(_TokenApprovalGen.GetRootAsTokenApproval(buf, 0))

    def build(self, builder):

        tx_hash = self.tx_hash
        if tx_hash:
            tx_hash = builder.CreateString(tx_hash)

        block_hash = self.block_hash
        if block_hash:
            block_hash = builder.CreateString(block_hash)

        owner_address = self.owner_address
        if owner_address:
            owner_address = builder.CreateString(owner_address)

        spender_address = self.spender_address
        if spender_address:
            spender_address = builder.CreateString(spender_address)

        value = self.value
        if value:
            value = builder.CreateString(pack_uint256(value))

        TokenApprovalGen.TokenApprovalStart(builder)

        if tx_hash:
            TokenApprovalGen.TokenApprovalAddTxHash(builder, tx_hash)

        if block_hash:
            TokenApprovalGen.TokenApprovalAddBlockHash(builder, block_hash)

        if owner_address:
            TokenApprovalGen.TokenApprovalAddOwnerAddress(builder, owner_address)

        if spender_address:
            TokenApprovalGen.TokenApprovalAddSpenderAddress(builder, spender_address)

        if value:
            TokenApprovalGen.TokenApprovalAddValue(builder, value)

        final = TokenApprovalGen.TokenApprovalEnd(builder)

        return final


@table('f3d1f052-7160-48a7-b36a-221035fc9373', build=TokenApproval.build, cast=TokenApproval.cast)
class TokenApprovals(MapBytes32FlatBuffers):
    """
    Persisted token approvals archive.

    Map :class:`zlmdb.MapBytes32FlatBuffers` from ``transaction_hash`` to :class:`crossbarfx.cfxdb.xbr.TokenApproval`
    """


class _TokenTransferGen(TokenTransferGen.TokenTransfer):
    """
    Expand methods on the class code generated by flatc.

    FIXME: come up with a PR for flatc to generated this stuff automatically.
    """

    @classmethod
    def GetRootAsTokenTransfer(cls, buf, offset):
        n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
        x = _TokenTransferGen()
        x.Init(buf, n + offset)
        return x

    def TxHashAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def BlockHashAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def FromAddressAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def ToAddressAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(10))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def ValueAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(12))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None


class TokenTransfer(object):
    """
    ``IERC20.TokenTransfer`` event database object.
    """

    def __init__(self, from_fbs=None):
        self._from_fbs = from_fbs

        self._tx_hash = None
        self._block_hash = None
        self._from_address = None
        self._to_address = None
        self._value = None

    def marshal(self):
        obj = {
            'tx_hash': self._tx_hash,
            'block_hash': self._block_hash,
            'from_address': self._from_address,
            'to_address': self._to_address,
            'value': self._value,
        }
        return obj

    def __str__(self):
        return '\n{}\n'.format(pprint.pformat(self.marshal()))

    @property
    def tx_hash(self):
        if self._tx_hash is None and self._from_fbs:
            if self._from_fbs.TxHashLength():
                self._tx_hash = self._from_fbs.TxHashAsBytes()
        return self._tx_hash

    @tx_hash.setter
    def tx_hash(self, value):
        assert value is None or type(value) == bytes
        self._tx_hash = value

    @property
    def block_hash(self):
        if self._block_hash is None and self._from_fbs:
            if self._from_fbs.TxHashLength():
                self._block_hash = self._from_fbs.BlockHashAsBytes()
        return self._block_hash

    @block_hash.setter
    def block_hash(self, value):
        assert value is None or type(value) == bytes
        self._block_hash = value

    @property
    def from_address(self):
        if self._from_address is None and self._from_fbs:
            if self._from_fbs.TxHashLength():
                self._from_address = self._from_fbs.FromAddressAsBytes()
        return self._from_address

    @from_address.setter
    def from_address(self, value):
        assert value is None or type(value) == bytes
        self._from_address = value

    @property
    def to_address(self):
        if self._to_address is None and self._from_fbs:
            if self._from_fbs.TxHashLength():
                self._to_address = self._from_fbs.ToAddressAsBytes()
        return self._to_address

    @to_address.setter
    def to_address(self, value):
        assert value is None or type(value) == bytes
        self._to_address = value

    @property
    def value(self):
        if self._value is None and self._from_fbs:
            if self._from_fbs.TxHashLength():
                _value = self._from_fbs.ValueAsBytes()
                self._value = unpack_uint256(bytes(_value))
            else:
                self._value = 0
        return self._value

    @value.setter
    def value(self, value):
        assert value is None or type(value) == int
        self._value = value

    @staticmethod
    def cast(buf):
        return TokenTransfer(_TokenTransferGen.GetRootAsTokenTransfer(buf, 0))

    def build(self, builder):

        tx_hash = self.tx_hash
        if tx_hash:
            tx_hash = builder.CreateString(tx_hash)

        block_hash = self.block_hash
        if block_hash:
            block_hash = builder.CreateString(block_hash)

        from_address = self.from_address
        if from_address:
            from_address = builder.CreateString(from_address)

        to_address = self.to_address
        if to_address:
            to_address = builder.CreateString(to_address)

        value = self.value
        if value:
            value = builder.CreateString(pack_uint256(value))

        TokenTransferGen.TokenTransferStart(builder)

        if tx_hash:
            TokenTransferGen.TokenTransferAddTxHash(builder, tx_hash)

        if block_hash:
            TokenTransferGen.TokenTransferAddBlockHash(builder, block_hash)

        if from_address:
            TokenTransferGen.TokenTransferAddFromAddress(builder, from_address)

        if to_address:
            TokenTransferGen.TokenTransferAddToAddress(builder, to_address)

        if value:
            TokenTransferGen.TokenTransferAddValue(builder, value)

        final = TokenTransferGen.TokenTransferEnd(builder)

        return final


@table('7dcfffd2-4859-45d6-b9cd-ba7930a7a107', build=TokenTransfer.build, cast=TokenTransfer.cast)
class TokenTransfers(MapBytes32FlatBuffers):
    """
    Persisted token transfers archive.

    Map :class:`zlmdb.MapBytes32FlatBuffers` from ``transaction_hash`` to :class:`crossbarfx.cfxdb.xbr.TokenTransfer`
    """


class _PayingChannelRequestGen(PayingChannelRequestGen.PayingChannelRequest):
    """
    Expand methods on the class code generated by flatc.

    FIXME: come up with a PR for flatc to generated this stuff automatically.
    """

    @classmethod
    def GetRootAsPayingChannelRequest(cls, buf, offset):
        n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
        x = _PayingChannelRequestGen()
        x.Init(buf, n + offset)
        return x

    def RequestAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def MarketAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def SenderAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(10))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def DelegateAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(12))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def RecipientAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(14))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def AmountAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(16))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def TimeoutAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(18))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def ChannelAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(24))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None


class PayingChannelRequest(object):
    """
    ``XBRPayingChannelRequest`` record/event database object.
    """

    def __init__(self, from_fbs=None):
        self._from_fbs = from_fbs

        self._request = None
        self._timestamp = None
        self._market = None
        self._sender = None
        self._delegate = None
        self._recipient = None
        self._amount = None
        self._timeout = None
        self._state = None
        self._error_msg = None
        self._channel = None

    def marshal(self):
        obj = {
            'request': bytes(self.request) if self.request else None,
            'timestamp': self.timestamp,
            'market': bytes(self.market) if self.market else None,
            'sender': bytes(self.sender) if self.sender else None,
            'delegate': bytes(self.delegate) if self.delegate else None,
            'recipient': bytes(self.recipient) if self.recipient else None,
            'amount': self.amount,
            'timeout': self.timeout,
            'state': self.state,
            'error_msg': self.error_msg,
            'channel': self.channel,
        }
        return obj

    def __str__(self):
        return '\n{}\n'.format(pprint.pformat(self.marshal()))

    @property
    def request(self):
        if self._request is None and self._from_fbs:
            if self._from_fbs.RequestLength():
                self._request = self._from_fbs.RequestAsBytes()
        return self._request

    @request.setter
    def request(self, value):
        assert value is None or type(value) == bytes
        self._request = value

    @property
    def timestamp(self):
        if self._timestamp is None and self._from_fbs:
            self._timestamp = np.datetime64(self._from_fbs.Timestamp(), 'ns')
        return self._timestamp

    @timestamp.setter
    def timestamp(self, value):
        assert value is None or isinstance(value, np.datetime64)
        self._timestamp = value

    @property
    def market(self):
        if self._market is None and self._from_fbs:
            if self._from_fbs.MarketLength():
                self._market = self._from_fbs.MarketAsBytes()
        return self._market

    @market.setter
    def market(self, value):
        assert value is None or type(value) == bytes
        self._market = value

    @property
    def sender(self):
        if self._sender is None and self._from_fbs:
            if self._from_fbs.SenderLength():
                self._sender = self._from_fbs.SenderAsBytes()
        return self._sender

    @sender.setter
    def sender(self, value):
        assert value is None or type(value) == bytes
        self._sender = value

    @property
    def delegate(self):
        if self._delegate is None and self._from_fbs:
            if self._from_fbs.DelegateLength():
                self._delegate = self._from_fbs.DelegateAsBytes()
        return self._delegate

    @delegate.setter
    def delegate(self, value):
        assert value is None or type(value) == bytes
        self._delegate = value

    @property
    def recipient(self):
        if self._recipient is None and self._from_fbs:
            if self._from_fbs.RecipientLength():
                self._recipient = self._from_fbs.RecipientAsBytes()
        return self._recipient

    @recipient.setter
    def recipient(self, value):
        assert value is None or type(value) == bytes
        self._recipient = value

    @property
    def amount(self):
        if self._amount is None and self._from_fbs:
            if self._from_fbs.AmountLength():
                _amount = self._from_fbs.AmountAsBytes()
                self._amount = unpack_uint256(bytes(_amount))
            else:
                self._amount = 0
        return self._amount

    @amount.setter
    def amount(self, value):
        assert value is None or type(value) == int, 'amount must be int, was: {}'.format(value)
        self._amount = value

    @property
    def timeout(self):
        if self._timeout is None and self._from_fbs:
            if self._from_fbs.TimeoutLength():
                _timeout = self._from_fbs.TimeoutAsBytes()
                self._timeout = unpack_uint256(bytes(_timeout))
            else:
                self._timeout = 0
        return self._timeout

    @timeout.setter
    def timeout(self, value):
        assert value is None or type(value) == int, 'timeout must be int, was: {}'.format(value)
        self._timeout = value

    @property
    def state(self):
        if self._state is None and self._from_fbs:
            self._state = self._from_fbs.State()
        return self._state

    @state.setter
    def state(self, value):
        assert type(value) == int, 'state must be int, was: {}'.format(value)
        self._state = value

    @property
    def error_msg(self):
        if self._error_msg is None and self._from_fbs:
            error_msg = self._from_fbs.ErrorMsg()
            if error_msg:
                self._error_msg = error_msg.decode('utf8')
        return self._error_msg

    @error_msg.setter
    def error_msg(self, value):
        assert value is None or type(value) == str
        self._error_msg = value

    @property
    def channel(self):
        if self._channel is None and self._from_fbs:
            if self._from_fbs.ChannelLength():
                self._channel = self._from_fbs.ChannelAsBytes()
        return self._channel

    @channel.setter
    def channel(self, value):
        assert value is None or type(value) == bytes, 'value must be bytes, not "{}"'.format(type(value))
        self._channel = value

    @staticmethod
    def cast(buf):
        return PayingChannelRequest(_PayingChannelRequestGen.GetRootAsPayingChannelRequest(buf, 0))

    def build(self, builder):

        request = self.request
        if request:
            request = builder.CreateString(bytes(request))

        market = self.market
        if market:
            market = builder.CreateString(bytes(market))

        sender = self.sender
        if sender:
            sender = builder.CreateString(bytes(sender))

        delegate = self.delegate
        if delegate:
            delegate = builder.CreateString(bytes(delegate))

        recipient = self.recipient
        if recipient:
            recipient = builder.CreateString(bytes(recipient))

        amount = self.amount
        if amount:
            amount = builder.CreateString(pack_uint256(amount))

        timeout = self.timeout
        if timeout:
            timeout = builder.CreateString(pack_uint256(timeout))

        error_msg = self.error_msg
        if error_msg:
            error_msg = builder.CreateString(error_msg)

        channel = self.channel
        if channel:
            channel = builder.CreateString(bytes(channel))

        PayingChannelRequestGen.PayingChannelRequestStart(builder)

        if request:
            PayingChannelRequestGen.PayingChannelRequestAddRequest(builder, request)

        if self.timestamp:
            PayingChannelRequestGen.PayingChannelRequestAddTimestamp(builder, int(self.timestamp))

        if market:
            PayingChannelRequestGen.PayingChannelRequestAddMarket(builder, market)

        if sender:
            PayingChannelRequestGen.PayingChannelRequestAddSender(builder, sender)

        if delegate:
            PayingChannelRequestGen.PayingChannelRequestAddDelegate(builder, delegate)

        if recipient:
            PayingChannelRequestGen.PayingChannelRequestAddRecipient(builder, recipient)

        if amount:
            PayingChannelRequestGen.PayingChannelRequestAddAmount(builder, amount)

        if timeout:
            PayingChannelRequestGen.PayingChannelRequestAddTimeout(builder, timeout)

        if self.state:
            PayingChannelRequestGen.PayingChannelRequestAddState(builder, int(self.state))

        if error_msg:
            PayingChannelRequestGen.PayingChannelRequestAddErrorMsg(builder, error_msg)

        if channel:
            PayingChannelRequestGen.PayingChannelRequestAddChannel(builder, channel)

        final = PayingChannelRequestGen.PayingChannelRequestEnd(builder)

        return final


class _PaymentChannelGen(PaymentChannelGen.PaymentChannel):
    """
    Expand methods on the class code generated by flatc.

    FIXME: come up with a PR for flatc to generated this stuff automatically.
    """

    @classmethod
    def GetRootAsPaymentChannel(cls, buf, offset):
        n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
        x = _PaymentChannelGen()
        x.Init(buf, n + offset)
        return x

    def ChannelAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def MarketAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def SenderAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(10))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def DelegateAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(12))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def RecipientAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(14))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def AmountAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(16))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def OpenAtAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(22))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def ClosingAtAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(24))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def ClosedAtAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(26))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def CloseMmSigAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(28))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def CloseDelSigAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(30))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def CloseBalanceAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(34))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def ClosedTxAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(38))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off + _len]
        return None


class PaymentChannel(object):
    """
    ``XBRPaymentChannel`` record/event database object.
    """

    def __init__(self, from_fbs=None):
        self._from_fbs = from_fbs

        self._type = None
        self._channel = None
        self._market = None
        self._sender = None
        self._delegate = None
        self._recipient = None
        self._amount = None
        self._timeout = None
        self._state = None
        self._open_at = None
        self._closing_at = None
        self._closed_at = None

        self._close_mm_sig = None
        self._close_del_sig = None
        self._close_channel_seq = None
        self._close_balance = None
        self._close_is_final = None

        self._closed_tx = None

    def marshal(self):
        obj = {
            'type': self.type,
            'channel': bytes(self.channel) if self.channel else None,
            'market': bytes(self.market) if self.market else None,
            'sender': bytes(self.sender) if self.sender else None,
            'delegate': bytes(self.delegate) if self.delegate else None,
            'recipient': bytes(self.recipient) if self.recipient else None,
            'amount': pack_uint256(self.amount) if self.amount else 0,
            'timeout': self.timeout,
            'state': self.state,
            'open_at': self.open_at,
            'closing_at': self.closing_at,
            'closed_at': self.closed_at,
            'close_mm_sig': bytes(self.close_mm_sig) if self.close_mm_sig else None,
            'close_del_sig': bytes(self.close_del_sig) if self.close_del_sig else None,
            'close_channel_seq': self.close_channel_seq,
            'close_is_final': self.close_is_final,
            'close_balance': self.close_balance,
            'closed_tx': bytes(self.closed_tx) if self.closed_tx else None,
        }
        return obj

    def __str__(self):
        return '\n{}\n'.format(pprint.pformat(self.marshal()))

    @property
    def type(self):
        if self._type is None and self._from_fbs:
            self._type = self._from_fbs.Type()
        return self._type

    @type.setter
    def type(self, value):
        assert type(value) == int
        self._type = value

    @property
    def channel(self):
        """
        The address of the payment channel.

        :return: The Ethereum address (32 bytes) of the payment
            channel contract instance that live on-chain. Here reused
            as a unique key in this database table as well (off-chain).
        :rtype: bytes
        """
        if self._channel is None and self._from_fbs:
            if self._from_fbs.ChannelLength():
                self._channel = self._from_fbs.ChannelAsBytes()
        return self._channel

    @channel.setter
    def channel(self, value):
        assert value is None or type(value) == bytes
        self._channel = value

    @property
    def market(self):
        if self._market is None and self._from_fbs:
            if self._from_fbs.MarketLength():
                self._market = self._from_fbs.MarketAsBytes()
        return self._market

    @market.setter
    def market(self, value):
        assert value is None or type(value) == bytes
        self._market = value

    @property
    def sender(self):
        if self._sender is None and self._from_fbs:
            if self._from_fbs.SenderLength():
                self._sender = self._from_fbs.SenderAsBytes()
        return self._sender

    @sender.setter
    def sender(self, value):
        assert value is None or type(value) == bytes
        self._sender = value

    @property
    def delegate(self):
        if self._delegate is None and self._from_fbs:
            if self._from_fbs.DelegateLength():
                self._delegate = self._from_fbs.DelegateAsBytes()
        return self._delegate

    @delegate.setter
    def delegate(self, value):
        assert value is None or type(value) == bytes
        self._delegate = value

    @property
    def recipient(self):
        if self._recipient is None and self._from_fbs:
            if self._from_fbs.RecipientLength():
                self._recipient = self._from_fbs.RecipientAsBytes()
        return self._recipient

    @recipient.setter
    def recipient(self, value):
        assert value is None or type(value) == bytes
        self._recipient = value

    @property
    def amount(self):
        if self._amount is None and self._from_fbs:
            if self._from_fbs.AmountLength():
                _amount = self._from_fbs.AmountAsBytes()
                self._amount = unpack_uint256(bytes(_amount))
            else:
                self._amount = 0
        return self._amount

    @amount.setter
    def amount(self, value):
        assert value is None or type(value) == int
        self._amount = value

    @property
    def timeout(self):
        if self._timeout is None and self._from_fbs:
            self._timeout = self._from_fbs.Timeout()
        return self._timeout

    @timeout.setter
    def timeout(self, value):
        assert type(value) == int
        self._timeout = value

    @property
    def state(self):
        if self._state is None and self._from_fbs:
            self._state = self._from_fbs.State()
        return self._state

    @state.setter
    def state(self, value):
        assert type(value) == int
        self._state = value

    @property
    def open_at(self):
        if self._open_at is None and self._from_fbs:
            if self._from_fbs.OpenAtLength():
                _open_at = self._from_fbs.OpenAtAsBytes()
                self._open_at = unpack_uint256(bytes(_open_at))
            else:
                self._open_at = 0
        return self._open_at

    @open_at.setter
    def open_at(self, value):
        assert value is None or type(value) == int
        self._open_at = value

    @property
    def closing_at(self):
        if self._closing_at is None and self._from_fbs:
            if self._from_fbs.ClosingAtLength():
                _closing_at = self._from_fbs.ClosingAtAsBytes()
                self._closing_at = unpack_uint256(bytes(_closing_at))
            else:
                self._closed_at = 0
        return self._closing_at

    @closing_at.setter
    def closing_at(self, value):
        assert value is None or type(value) == int
        self._closing_at = value

    @property
    def closed_at(self):
        if self._closed_at is None and self._from_fbs:
            if self._from_fbs.ClosedAtLength():
                _closed_at = self._from_fbs.ClosedAtAsBytes()
                self._closed_at = unpack_uint256(bytes(_closed_at))
            else:
                self._closed_at = 0
        return self._closed_at

    @closed_at.setter
    def closed_at(self, value):
        assert value is None or type(value) == int
        self._closed_at = value

    @property
    def close_mm_sig(self):
        if self._close_mm_sig is None and self._from_fbs:
            if self._from_fbs.CloseMmSigLength():
                self._close_mm_sig = self._from_fbs.CloseMmSigAsBytes()
        return self._close_mm_sig

    @close_mm_sig.setter
    def close_mm_sig(self, value):
        assert value is None or type(value) == bytes
        self._close_mm_sig = value

    @property
    def close_del_sig(self):
        if self._close_del_sig is None and self._from_fbs:
            if self._from_fbs.CloseDelSigLength():
                self._close_del_sig = self._from_fbs.CloseDelSigAsBytes()
        return self._close_del_sig

    @close_del_sig.setter
    def close_del_sig(self, value):
        assert value is None or type(value) == bytes
        self._close_del_sig = value

    @property
    def close_channel_seq(self):
        if self._close_channel_seq is None and self._from_fbs:
            self._close_channel_seq = self._from_fbs.CloseChannelSeq()
        return self._close_channel_seq

    @close_channel_seq.setter
    def close_channel_seq(self, value):
        assert type(value) == int
        self._close_channel_seq = value

    @property
    def close_balance(self):
        if self._close_balance is None and self._from_fbs:
            if self._from_fbs.CloseBalanceLength():
                _close_balance = self._from_fbs.CloseBalanceAsBytes()
                if _close_balance is not None:
                    self._close_balance = unpack_uint256(bytes(_close_balance))
                else:
                    self._close_balance = 0
            else:
                self._close_balance = 0
        return self._close_balance

    @close_balance.setter
    def close_balance(self, value):
        assert value is None or type(value) == int
        self._close_balance = value

    @property
    def close_is_final(self):
        if self._close_is_final is None and self._from_fbs:
            self._close_is_final = (self._from_fbs.CloseIsFinal() is True)
        return self._close_is_final

    @close_is_final.setter
    def close_is_final(self, value):
        assert value is None or type(value) == bool
        self._close_is_final = value

    @property
    def closed_tx(self):
        if self._closed_tx is None and self._from_fbs:
            if self._from_fbs.ClosedTxLength():
                self._closed_tx = self._from_fbs.ClosedTxAsBytes()
        return self._closed_tx

    @closed_tx.setter
    def closed_tx(self, value):
        assert value is None or type(value) == bytes
        self._closed_tx = value

    @staticmethod
    def cast(buf):
        return PaymentChannel(_PaymentChannelGen.GetRootAsPaymentChannel(buf, 0))

    def build(self, builder):

        channel = self.channel
        if channel:
            channel = builder.CreateString(bytes(channel))

        market = self.market
        if market:
            market = builder.CreateString(bytes(market))

        sender = self.sender
        if sender:
            sender = builder.CreateString(bytes(sender))

        delegate = self.delegate
        if delegate:
            delegate = builder.CreateString(bytes(delegate))

        recipient = self.recipient
        if recipient:
            recipient = builder.CreateString(bytes(recipient))

        amount = self.amount
        if amount:
            amount = builder.CreateString(pack_uint256(amount))

        open_at = self.open_at
        if open_at:
            open_at = builder.CreateString(pack_uint256(open_at))

        closing_at = self.closing_at
        if closing_at:
            closing_at = builder.CreateString(pack_uint256(closing_at))

        closed_at = self.closed_at
        if closed_at:
            closed_at = builder.CreateString(pack_uint256(closed_at))

        close_mm_sig = self.close_mm_sig
        if close_mm_sig:
            close_mm_sig = builder.CreateString(bytes(close_mm_sig))

        close_del_sig = self.close_del_sig
        if close_del_sig:
            close_del_sig = builder.CreateString(bytes(close_del_sig))

        close_balance = self.close_balance
        if close_balance:
            close_balance = builder.CreateString(pack_uint256(close_balance))

        closed_tx = self.closed_tx
        if closed_tx:
            closed_tx = builder.CreateString(bytes(closed_tx))

        PaymentChannelGen.PaymentChannelStart(builder)

        if self.type:
            PaymentChannelGen.PaymentChannelAddType(builder, int(self.type))

        if channel:
            PaymentChannelGen.PaymentChannelAddChannel(builder, channel)

        if market:
            PaymentChannelGen.PaymentChannelAddMarket(builder, market)

        if sender:
            PaymentChannelGen.PaymentChannelAddSender(builder, sender)

        if delegate:
            PaymentChannelGen.PaymentChannelAddDelegate(builder, delegate)

        if recipient:
            PaymentChannelGen.PaymentChannelAddRecipient(builder, recipient)

        if amount:
            PaymentChannelGen.PaymentChannelAddAmount(builder, amount)

        PaymentChannelGen.PaymentChannelAddTimeout(builder, self.timeout)

        if self.state:
            PaymentChannelGen.PaymentChannelAddState(builder, int(self.state))

        if open_at:
            PaymentChannelGen.PaymentChannelAddOpenAt(builder, open_at)

        if closing_at:
            PaymentChannelGen.PaymentChannelAddClosingAt(builder, closing_at)

        if closed_at:
            PaymentChannelGen.PaymentChannelAddClosedAt(builder, closed_at)

        if close_mm_sig:
            PaymentChannelGen.PaymentChannelAddCloseMmSig(builder, close_mm_sig)

        if close_del_sig:
            PaymentChannelGen.PaymentChannelAddCloseDelSig(builder, close_del_sig)

        if self.close_channel_seq:
            PaymentChannelGen.PaymentChannelAddCloseChannelSeq(builder, self.close_channel_seq)

        if close_balance:
            PaymentChannelGen.PaymentChannelAddCloseBalance(builder, close_balance)

        if self.close_is_final:
            PaymentChannelGen.PaymentChannelAddCloseIsFinal(builder, self.close_is_final)

        if closed_tx:
            PaymentChannelGen.PaymentChannelAddClosedTx(builder, closed_tx)

        final = PaymentChannelGen.PaymentChannelEnd(builder)

        return final


@table('8ce6b28c-ad8f-456e-a947-1b19e9b19247', build=PayingChannelRequest.build, cast=PayingChannelRequest.cast)
class PayingChannelRequests(MapBytes16FlatBuffers):
    """
    XBR paying channel requests by ``paying_channel_adr``.

    Map :class:`zlmdb.MapBytes20FlatBuffers` from ``paying_channel_adr`` to :class:`crossbarfx.cfxdb.xbr.PayingChannelRequest`
    """


@table('0b3f5f33-165c-4f52-9e4a-23d0edc8c3a6')
class IndexPayingChannelRequestByRecipient(MapBytes20Bytes16):
    """
    Index: ``recipient_adr -> paying_channel_request_id``.
    """


@table('b3d01946-85ae-49f3-ad96-b78194eb82fe', build=PaymentChannel.build, cast=PaymentChannel.cast)
class PaymentChannels(MapBytes20FlatBuffers):
    """
    XBR payment channels by ``payment_channel_adr``.

    Map :class:`zlmdb.MapBytes20FlatBuffers` from ``payment_channel_adr`` to :class:`crossbarfx.cfxdb.xbr.PaymentChannel`
    """


@table('cffd5253-72f8-41a9-8b76-5e6ff3654e67')
class IndexPaymentChannelByDelegate(MapBytes20TimestampBytes20):
    """
    Index: ``(delegate_adr, created_timestamp) -> payment_channel_adr``
    """


@table('4e7e7c8d-db0d-4dea-8409-ac8f21ce1e10', build=PaymentChannel.build, cast=PaymentChannel.cast)
class PayingChannels(MapBytes20FlatBuffers):
    """
    XBR paying channels by ``paying_channel_adr``.

    Map :class:`zlmdb.MapBytes32FlatBuffers` from ``paying_channel_adr`` to :class:`crossbarfx.cfxdb.xbr.PaymentChannel`
    """


@table('cee954be-fdb2-43cc-8891-529d6c7a0c3b')
class IndexPayingChannelByDelegate(MapBytes20TimestampBytes20):
    """
    Index: ``(delegate_adr, created_timestamp) -> paying_channel_adr``
    """


@table('655a9d5f-0bdf-4c2a-8102-208f6da4a566')
class IndexPayingChannelByRecipient(MapBytes20TimestampBytes20):
    """
    Index: ``(recipient_adr, created_timestamp) -> paying_channel_adr``
    """


class _PaymentChannelBalanceGen(PaymentChannelBalanceGen.PaymentChannelBalance):
    """
    Expand methods on the class code generated by flatc.

    FIXME: come up with a PR for flatc to generated this stuff automatically.
    """

    @classmethod
    def GetRootAsPaymentChannelBalance(cls, buf, offset):
        n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
        x = _PaymentChannelBalanceGen()
        x.Init(buf, n + offset)
        return x

    def RemainingAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def InflightAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None


class PaymentChannelBalance(object):

    def __init__(self, from_fbs=None):
        self._from_fbs = from_fbs

        self._remaining = None
        self._inflight = None
        self._seq = None

    @staticmethod
    def parse(data):
        assert type(data) == dict

        obj = PaymentChannelBalance()

        if 'remaining' in data:
            remaining = data['remaining']
            assert type(remaining) == bytes and len(remaining) == 32
            obj._remaining = unpack_uint256(remaining)

        if 'inflight' in data:
            inflight = data['inflight']
            assert type(inflight) == bytes and len(inflight) == 32
            obj._inflight = unpack_uint256(inflight)

        if 'seq' in data:
            seq = data['seq']
            assert type(seq) == int
            obj._seq = unpack_uint256(seq)

        return obj

    def marshal(self):
        obj = {
            'remaining': pack_uint256(self.remaining) if self.remaining else 0,
            'inflight': pack_uint256(self.inflight) if self.inflight else 0,
            'seq': self.seq or 0
        }
        return obj

    def __str__(self):
        return '\n{}\n'.format(pprint.pformat(self.marshal()))

    @property
    def remaining(self):
        if self._remaining is None and self._from_fbs:
            if self._from_fbs.RemainingLength():
                _remaining = self._from_fbs.RemainingAsBytes()
                self._remaining = unpack_uint256(bytes(_remaining))
            else:
                self._remaining = 0
        return self._remaining

    @remaining.setter
    def remaining(self, value):
        assert value is None or type(value) == int
        self._remaining = value

    @property
    def inflight(self):
        if self._inflight is None and self._from_fbs:
            if self._from_fbs.InflightLength():
                _inflight = self._from_fbs.InflightAsBytes()
                self._inflight = unpack_uint256(bytes(_inflight))
            else:
                self._inflight = 0
        return self._inflight

    @inflight.setter
    def inflight(self, value):
        assert value is None or type(value) == int
        self._inflight = value

    @property
    def seq(self):
        if self._seq is None and self._from_fbs:
            self._seq = self._from_fbs.Seq()
        return self._seq or 0

    @seq.setter
    def seq(self, value):
        assert value is None or type(value) == int
        self._seq = value

    @staticmethod
    def cast(buf):
        return PaymentChannelBalance(_PaymentChannelBalanceGen.GetRootAsPaymentChannelBalance(buf, 0))

    def build(self, builder):

        remaining = self.remaining
        if remaining:
            remaining = builder.CreateString(pack_uint256(remaining))

        inflight = self.inflight
        if inflight:
            inflight = builder.CreateString(pack_uint256(inflight))

        PaymentChannelBalanceGen.PaymentChannelBalanceStart(builder)

        if remaining:
            PaymentChannelBalanceGen.PaymentChannelBalanceAddRemaining(builder, remaining)

        if inflight:
            PaymentChannelBalanceGen.PaymentChannelBalanceAddInflight(builder, inflight)

        if self.seq:
            PaymentChannelBalanceGen.PaymentChannelBalanceAddSeq(builder, self.seq)

        final = PaymentChannelBalanceGen.PaymentChannelBalanceEnd(builder)

        return final


@table('878ac002-a830-488b-bfe9-f06371b8eecb', build=PaymentChannelBalance.build, cast=PaymentChannelBalance.cast)
class PaymentChannelBalances(MapBytes20FlatBuffers):
    """
    XBR payment channels current balances by ``payment_channel_adr``.

    Map :class:`zlmdb.MapBytes20FlatBuffers` from ``payment_channel_adr`` to :class:`crossbarfx.cfxdb.xbr.Balance`
    """


@table('c0931d5d-6d5d-4f9c-b2a3-29664a0f4c07', build=PaymentChannelBalance.build, cast=PaymentChannelBalance.cast)
class PayingChannelBalances(MapBytes20FlatBuffers):
    """
    XBR paying channels current balances by ``paying_channel_adr``.

    Map :class:`zlmdb.MapBytes20FlatBuffers` from ``paying_channel_adr`` to :class:`crossbarfx.cfxdb.xbr.Balance`
    """


class _TransactionGen(TransactionGen.Transaction):
    """
    Expand methods on the class code generated by flatc.

    FIXME: come up with a PR for flatc to generated this stuff automatically.
    """

    @classmethod
    def GetRootAsTransaction(cls, buf, offset):
        n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
        x = _TransactionGen()
        x.Init(buf, n + offset)
        return x

    def TidAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def OfferAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(12))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def AmountAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(14))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def PaymentChannelAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(16))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None

    def PayingChannelAsBytes(self):
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(18))
        if o != 0:
            _off = self._tab.Vector(o)
            _len = self._tab.VectorLen(o)
            return memoryview(self._tab.Bytes)[_off:_off+_len]
        return None


class Transaction(object):
    """
    """
    STATUS_NONE = 0
    STATUS_INFLIGHT = 1
    STATUS_FAILED = 2
    STATUS_SUCCESS = 3

    def __init__(self, from_fbs=None):
        self._from_fbs = from_fbs

        # uint8[] (uuid)
        self._tid = None

        # uint64
        self._created = None

        # uint32
        self._created_payment_channel_seq = None

        # uint32
        self._created_paying_channel_seq = None

        # uint8[] (uuid)
        self._offer = None

        # uint8[] (uint256)
        self._amount = None

        # uint8[] (bytes20)
        self._payment_channel = None

        # uint8[] (bytes20)
        self._paying_channel = None

        # uint8
        self._state = None

        # uint64
        self._completed = None

        # uint32
        self._completed_payment_channel_seq = None

        # uint32
        self._completed_paying_channel_seq = None

    @staticmethod
    def parse(data):
        raise NotImplementedError()

        # obj = Transaction()
        #
        # if 'amount' in data:
        #     amount = data['amount']
        #     assert type(amount) == bytes and len(amount) == 32
        #     obj._amount = unpack_uint256(amount)
        #
        # return obj

    def marshal(self):
        obj = {
            'tid': str(self.tid) if self.tid else None,
            'created': self.created,
            'created_payment_channel_seq': self._created_payment_channel_seq,
            'created_paying_channel_seq': self._created_paying_channel_seq,
            'offer': str(self.offer) if self.offer else None,
            'amount': pack_uint256(self.amount) if self.amount else 0,
            'payment_channel': self.payment_channel,
            'paying_channel': self.paying_channel,
            'state': self.state,
            'completed': self.completed,
            'completed_payment_channel_seq': self._completed_payment_channel_seq,
            'completed_paying_channel_seq': self._completed_paying_channel_seq,
        }
        return obj

    def __str__(self):
        return '\n{}\n'.format(pprint.pformat(self.marshal()))

    @property
    def tid(self):
        if self._tid is None and self._from_fbs:
            if self._from_fbs.OfferLength():
                _tid = self._from_fbs.TidAsBytes()
                self._tid = uuid.UUID(bytes=bytes(_tid))
        return self._tid

    @tid.setter
    def tid(self, value):
        assert value is None or isinstance(value, uuid.UUID)
        self._tid = value

    @property
    def created(self):
        if self._created is None and self._from_fbs:
            self._created = np.datetime64(self._from_fbs.Created(), 'ns')
        return self._created

    @created.setter
    def created(self, value):
        assert value is None or isinstance(value, np.datetime64)
        self._created = value

    @property
    def created_payment_channel_seq(self):
        if self._created_payment_channel_seq is None and self._from_fbs:
            self._created_payment_channel_seq = self._from_fbs.CreatedPaymentChannelSeq()
        return self._created_payment_channel_seq or 0

    @created_payment_channel_seq.setter
    def created_payment_channel_seq(self, value):
        assert value is None or type(value) == int
        self._created_payment_channel_seq = value

    @property
    def created_paying_channel_seq(self):
        if self._created_paying_channel_seq is None and self._from_fbs:
            self._created_paying_channel_seq = self._from_fbs.CreatedPayingChannelSeq()
        return self._created_paying_channel_seq or 0

    @created_paying_channel_seq.setter
    def created_paying_channel_seq(self, value):
        assert value is None or type(value) == int
        self._created_paying_channel_seq = value

    @property
    def offer(self):
        if self._offer is None and self._from_fbs:
            if self._from_fbs.OfferLength():
                _offer = self._from_fbs.OfferAsBytes()
                self._offer = uuid.UUID(bytes=bytes(_offer))
        return self._offer

    @offer.setter
    def offer(self, value):
        assert value is None or isinstance(value, uuid.UUID)
        self._offer = value

    @property
    def amount(self):
        if self._amount is None and self._from_fbs:
            if self._from_fbs.AmountLength():
                _amount = self._from_fbs.AmountAsBytes()
                self._amount = unpack_uint256(bytes(_amount))
            else:
                self._amount = 0
        return self._amount

    @amount.setter
    def amount(self, value):
        assert value is None or type(value) == int
        self._amount = value

    @property
    def payment_channel(self):
        if self._payment_channel is None and self._from_fbs:
            if self._from_fbs.PaymentChannelLength():
                self._payment_channel = self._from_fbs.PaymentChannelAsBytes()
        return self._payment_channel

    @payment_channel.setter
    def payment_channel(self, value):
        assert value is None or (type(value) == bytes and len(value) == 20)
        self._payment_channel = value

    @property
    def paying_channel(self):
        if self._payment_channel is None and self._from_fbs:
            if self._from_fbs.PayingChannelLength():
                self._payment_channel = self._from_fbs.PayingChannelAsBytes()
        return self._payment_channel

    @paying_channel.setter
    def paying_channel(self, value):
        assert value is None or (type(value) == bytes and len(value) == 20)
        self._payment_channel = value

    @property
    def state(self):
        if self._state is None and self._from_fbs:
            self._state = self._from_fbs.State()
        return self._state or 0

    @state.setter
    def state(self, value):
        assert value is None or type(value) == int
        self._state = value

    @property
    def completed(self):
        if self._completed is None and self._from_fbs:
            self._completed = np.datetime64(self._from_fbs.Completed(), 'ns')
        return self._completed

    @completed.setter
    def completed(self, value):
        assert value is None or isinstance(value, np.datetime64)
        self._completed = value

    @property
    def completed_payment_channel_seq(self):
        if self._completed_payment_channel_seq is None and self._from_fbs:
            self._completed_payment_channel_seq = self._from_fbs.CompletedPaymentChannelSeq()
        return self._completed_payment_channel_seq or 0

    @completed_payment_channel_seq.setter
    def completed_payment_channel_seq(self, value):
        assert value is None or type(value) == int
        self._completed_payment_channel_seq = value

    @property
    def completed_paying_channel_seq(self):
        if self._completed_paying_channel_seq is None and self._from_fbs:
            self._completed_paying_channel_seq = self._from_fbs.CompletedPayingChannelSeq()
        return self._completed_paying_channel_seq or 0

    @completed_paying_channel_seq.setter
    def completed_paying_channel_seq(self, value):
        assert value is None or type(value) == int
        self._completed_paying_channel_seq = value

    @staticmethod
    def cast(buf):
        return Transaction(_TransactionGen.GetRootAsTransaction(buf, 0))

    def build(self, builder):

        tid = self.tid.bytes if self.tid else None
        if tid:
            tid = builder.CreateString(tid)

        offer = self.offer.bytes if self.offer else None
        if offer:
            offer = builder.CreateString(offer)

        amount = self.amount
        if amount:
            amount = builder.CreateString(pack_uint256(amount))

        payment_channel = self.payment_channel
        if payment_channel:
            payment_channel = builder.CreateString(payment_channel)

        paying_channel = self.paying_channel
        if paying_channel:
            paying_channel = builder.CreateString(paying_channel)

        TransactionGen.TransactionStart(builder)

        if tid:
            TransactionGen.TransactionAddTid(builder, tid)

        if self.created:
            TransactionGen.TransactionAddCreated(builder, int(self.created))

        if self.created_payment_channel_seq:
            TransactionGen.TransactionAddCreatedPaymentChannelSeq(builder, self.created_payment_channel_seq)

        if self.created_paying_channel_seq:
            TransactionGen.TransactionAddCreatedPayingChannelSeq(builder, self.created_paying_channel_seq)

        if offer:
            TransactionGen.TransactionAddOffer(builder, offer)

        if amount:
            TransactionGen.TransactionAddAmount(builder, amount)

        if payment_channel:
            TransactionGen.TransactionAddPaymentChannel(builder, payment_channel)

        if paying_channel:
            TransactionGen.TransactionAddPayingChannel(builder, paying_channel)

        if self.state:
            TransactionGen.TransactionAddState(builder, int(self.state))

        if self.completed:
            TransactionGen.TransactionAddCompleted(builder, int(self.completed))

        if self.completed_payment_channel_seq:
            TransactionGen.TransactionAddCompletedPaymentChannelSeq(builder, self.completed_payment_channel_seq)

        if self.completed_paying_channel_seq:
            TransactionGen.TransactionAddCompletedPayingChannelSeq(builder, self.completed_paying_channel_seq)

        final = TransactionGen.TransactionEnd(builder)

        return final


@table('87cf8eac-10d8-470d-a645-23e11343e065', build=Transaction.build, cast=Transaction.cast)
class Transactions(MapUuidFlatBuffers):
    """

    """


class Schema(object):
    """
    CFC edge database schema for ZLMDB.
    """

    def __init__(self, db):
        self.db = db

    # blockchain blocks processed
    # blocks: Blocks
    blocks = None

    # token_approvals: TokenApprovals
    token_approvals = None
    """
    Token approvals archive.
    """

    # token_transfers: TokenTransfers
    token_transfers = None
    """
    Token transfers archive.
    """

    # members: Members
    members = None
    """
    XBR network members.
    """

    # markets: Markets
    markets = None
    """
    XBR markets.
    """

    # actors: Actors
    actors = None
    """
    XBR market actors.
    """

    # payment_channels: PaymentChannels
    payment_channels = None
    """
    Payment channels for XBR consumer delegates.
    """

    # idx_payment_channel_by_delegate: IndexPaymentChannelByDelegate
    idx_payment_channel_by_delegate = None
    """
    Maps from XBR consumer delegate address to the currently active payment
    channel address for the given consumer delegate.
    """

    # payment_balances: PaymentChannelBalances
    payment_balances = None
    """
    Current off-chain balances within payment channels.
    """

    # paying_channel_requests: PayingChannelRequests
    paying_channel_requests = None
    """
    Requests for openng paying channels.
    """

    # paying_channels: PayingChannels
    paying_channels = None
    """
    Paying channels for XBR provider delegates.
    """

    # idx_paying_channel_by_delegate: IndexPayingChannelByDelegate
    idx_paying_channel_by_delegate = None
    """
    Maps from XBR provider delegate address to the currently active paying
    channel address for the given provider delegate.
    """

    # idx_paying_channel_requests_by_recipient: IndexPayingChannelByRecipient
    idx_paying_channel_requests_by_recipient = None
    """    
    """

    # paying_balances: PayingChannelBalances
    paying_balances = None
    """
    Current off-chain balances within paying channels.
    """

    # key_offers: Offer
    offers = None
    """
    Data encryption key offers.
    """

    # idx_offer_by_key: IndexOfferByKey
    idx_offer_by_key = None
    """
    Index of key offers by key ID (rather than offer ID, as the object table
    is indexed by).
    """

    # transaction: Transactions
    transactions = None
    """
    """


    @staticmethod
    def attach(db):
        """
        Factory to create a schema from attaching to a database. The schema tables
        will be automatically mapped as persistant maps and attached to the
        database slots.

        :param db: zlmdb.Database
        :return: object of Schema
        """
        schema = Schema(db)

        schema.blocks = db.attach_table(Blocks)

        schema.token_approvals = db.attach_table(TokenApprovals)

        schema.token_transfers = db.attach_table(TokenTransfers)

        schema.members = db.attach_table(Members)

        schema.markets = db.attach_table(Markets)

        schema.actors = db.attach_table(Actors)

        schema.payment_channels = db.attach_table(PaymentChannels)

        schema.idx_payment_channel_by_delegate = db.attach_table(IndexPaymentChannelByDelegate)
        #schema.payment_channels.attach_index('idx1',
        #                                     schema.idx_payment_channel_by_delegate,
        #                                     lambda payment_channel: (bytes(payment_channel.delegate), np.datetime64(time_ns(), 'ns')))

        schema.payment_balances = db.attach_table(PaymentChannelBalances)

        schema.paying_channel_requests = db.attach_table(PayingChannelRequests)

        schema.idx_paying_channel_requests_by_recipient = db.attach_table(IndexPayingChannelRequestByRecipient)
        schema.paying_channel_requests.attach_index('idx1',
                                             schema.idx_paying_channel_requests_by_recipient,
                                             lambda paying_channel_request: bytes(paying_channel_request.recipient))

        schema.paying_channels = db.attach_table(PayingChannels)

        schema.idx_paying_channel_by_delegate = db.attach_table(IndexPayingChannelByDelegate)
        #schema.paying_channels.attach_index('idx1',
        #                                     schema.idx_paying_channel_by_delegate,
        #                                     lambda paying_channel: (bytes(paying_channel.delegate), np.datetime64(time_ns(), 'ns')))

        #schema.idx_paying_channel_by_recipient = db.attach_table(IndexPayingChannelByRecipient)
        #schema.paying_channels.attach_index('idx2',
        #                                     schema.idx_paying_channel_by_recipient,
        #                                     lambda paying_channel: (bytes(paying_channel.recipient), np.datetime64(time_ns(), 'ns')))

        schema.paying_balances = db.attach_table(PayingChannelBalances)

        schema.offers = db.attach_table(Offers)
        schema.idx_offer_by_key = db.attach_table(IndexOfferByKey)
        schema.offers.attach_index('idx1',
                                   schema.idx_offer_by_key,
                                   lambda offer: offer.key)

        schema.transactions = db.attach_table(Transactions)

        return schema
