type Token @entity {
    id: ID!                                               
    symbol: String                                      
    name: String                                          
    decimals: Int!                                        
    address: String!                                      
    cap: BigDecimal                                       
    supply: BigDecimal                                    
    isDatatoken: Boolean!                                 
    
    "address of ERC721 that owns the token, valid only for datatokens"
    nft: Nft    

    "array of addresses with minter role"                                 
    minter: [String!] 

    "array of addresses with payment manager minter role"                                 
    paymentManager: [String!] 

    "address that collects the payments (NOT fees)"                                      
    paymentCollector: String   

    "address of the market where the datatoken was created. This address collects market fees."                       
    publishMarketFeeAddress: String 

    "adreess of fee token (can be Ocean, ETH, etc.)"                     
    publishMarketFeeToken: String   

    "fee amount. Fixed value."             
    publishMarketFeeAmount: BigDecimal   

    "template ID of the datatoken"                               
    templateId: Int                                       

    "number of addresses holding a balance of datatoken , TODO: can we actually calculate this? what happens when users trade the dts"
    holderCount: BigInt!   

    "number of orders executed for this datatoken"                                
    orderCount: BigInt!                                    

    "orders created with the datatoken, only available for datatokens"
    orders: [Order!] @derivedFrom(field:"datatoken")

    "fixed rate exchanges, only available for datatokens"
    fixedRateExchanges: [FixedRateExchange!] @derivedFrom(field:"datatoken")

    "dispensers using this token"
    dispensers: [Dispenser!] @derivedFrom(field:"token")

    "block time datatoken was created"
    createdTimestamp: Int!        

    "datatoken creation transaction id"                         
    tx: String!        

    "block number when it was created"                                   
    block: Int!           

    lastPriceToken: Token
    lastPriceValue: BigDecimal!
}

"utility type"
type TokenValuePair @entity {
   "address of the token"
   id : ID!
   token : Token!
   value : BigDecimal!
}

type Nft @entity{
    "nft address"
    id: ID!                                                
    symbol: String!                                       
    name: String!                                          
    tokenUri: String
  
    "address of the owner of the nft"                                     
    owner: String!     
    "address of the creator of the nft"                                     
    creator: String!     

    "same as id, it's just for easy discoverability"                                    
    address: String!     

    "provider url that can decrypt the ddo"                                  
    providerUrl: String  

    "state of the asset (described in docs)"                                  
    assetState: Int!                                       

    managerRole: [String!]
    erc20DeployerRole: [String!]
    storeUpdateRole: [String!] 
    "addresses that can update the metadata"
    metadataRole: [String!]                                 

    "template address"
    template: String!           

    "set if NFT is transferable"
    transferable: Boolean!

    "block time nft was created"
    createdTimestamp: Int!                                  
    "nft creation transaction id"
    tx: String!   
    "block number when it was created"                                            
    block: Int  

    "number of orders executed for all underlying datatokens"                                
    orderCount: BigInt!  

    "has metadata"
    hasMetadata: Boolean!                                            

    nftData: [NftData!] @derivedFrom(field: "nft")
}

type NftData @entity{
    "nft address+key"
    id: ID!
    nft: Nft!
    key: Bytes
    value: Bytes
  }

type OrderReuse @entity {
  id: ID!
  order: Order!
  caller: String!
  createdTimestamp: Int!
  tx: String!
  block: Int!
  providerFee: String
  providerFeeValidUntil: BigInt
  "gas price in Wei"
  gasPrice: BigInt
  gasUsed: BigDecimal
  }

type Order @entity {  
  "transaction hash - token address - from address"                                       
  id: ID!                                                    
  datatoken: Token!

  consumer: User!
  payer: User!
  amount: BigDecimal!
  serviceIndex: Int!


  # the fees will be updated from an event that will be created after (todo)
  publishingMarket: User
  publishingMarketToken: Token                                #
  publishingMarketAmmount: BigDecimal                         #call contract to get fee amount
  providerFee: String
  providerFeeValidUntil: BigInt

  consumerMarket: User
  consumerMarketToken: Token                                  #
  consumerMarketAmmount: BigDecimal                           #call contract to get fee amount

  reuses: [OrderReuse!] @derivedFrom(field: "order")

  createdTimestamp: Int!
  tx: String!
  block: Int!

  lastPriceToken: Token
  lastPriceValue: BigDecimal!
  estimatedUSDValue: BigDecimal!
  gasUsed: BigDecimal
  "gas price in Wei"
  gasPrice: BigInt
}

type User @entity {
  id: ID!
  tokenBalancesOwned: [TokenValuePair!]
  orders: [Order!] @derivedFrom(field: "payer")
  freSwaps: [FixedRateExchangeSwap!] @derivedFrom(field: "by")
  
  "total number of orders made by this user"       
  totalOrders: BigInt!

  "total number of orders made on assets owned by this user"       
  totalSales: BigInt!
}

type FixedRateExchange @entity {
  "fixed rate exchange id"
  id: ID!             
  contract: String!
  exchangeId: String!                                       
  owner: User!
  datatoken: Token!
  baseToken: Token!
  "amount of datatokens available to be sold, this is relevant if the exchange is not able to mint"
  datatokenSupply: BigDecimal!
  "amount of basetokens available to be collected by the owner"
  baseTokenSupply: BigDecimal!
  datatokenBalance: BigDecimal!
  baseTokenBalance: BigDecimal!
  price: BigDecimal!
  active: Boolean!
  "amount of total basetokens spent"
  totalSwapValue: BigDecimal!  
  "address that is allowed to  swap tokens"                              
  allowedSwapper: String                                     
  "if the owner allowes the fre to mint"
  withMint: Boolean  
  "if the fre has the minter role on the datatoken"                                        
  isMinter: Boolean             

  updates: [FixedRateExchangeUpdate!] @derivedFrom(field: "exchangeId")
  swaps: [FixedRateExchangeSwap!] @derivedFrom(field: "exchangeId")

  createdTimestamp: Int!
  tx: String!
  block: Int!

  "address of the market where the datatoken was created. This address collects market fees."                       
  publishMarketFeeAddress: String 

  "fee amount. Fixed value"             
  publishMarketSwapFee: BigDecimal   

}

type FixedRateExchangeUpdate @entity {
  id: ID!
  exchangeId: FixedRateExchange!

  oldPrice: BigDecimal
  newPrice: BigDecimal

  oldActive: Boolean
  newActive: Boolean

  oldAllowedSwapper: String
  newAllowedSwapper: String

  block: Int!
  createdTimestamp: Int!
  tx: String!
}

type FixedRateExchangeSwap @entity {
  id: ID!
  exchangeId: FixedRateExchange!
  by: User!
  baseTokenAmount: BigDecimal!
  dataTokenAmount: BigDecimal!
  block: Int!
  createdTimestamp: Int!
  tx: String!
}


type Dispenser @entity {
  "token address"
  id: ID!        
  contract: String!                                              
  active: Boolean!   
  "if using the enterprise template the owner will always be the erc721 factory, for normal template it will a user"                         
  owner: String
  token: Token!

  allowedSwapper: String
  isMinter: Boolean   
  "max tokens that can be dispensed"                                         
  maxTokens: BigDecimal! 
  "max balance of requester. If the balance is higher, the dispense is rejected"                              
  maxBalance: BigDecimal!    
  "how many tokens are left"                                   
  balance: BigDecimal!                        


  block: Int!
  createdTimestamp: Int!
  tx: String!                 
  
  dispenses: [DispenserTransaction!] @derivedFrom(field: "dispenser")
}

type DispenserTransaction @entity {
  id: ID!                                                      
  dispenser: Dispenser!
  user: User!
  amount: BigDecimal!

  block: Int!
  createdTimestamp: Int!
  tx: String!
}

"utility type"
type GlobalTotalLiquidityPair @entity {
   "address of the token"
   id : ID!
   globalStatistic: GlobalStatistic!
   token : Token!
   value : BigDecimal!
}

"utility type"
type GlobalTotalFixedSwapPair @entity {
   "address of the token"
   id : ID!
    globalStatistic: GlobalStatistic!
   token : Token!
   value : BigDecimal!
   count: BigInt!
}
type GlobalStatistic @entity {
    id: ID!     

    "total swap volume for each base token in fixed rate exchanges"
    totalFixedSwapVolume: [GlobalTotalFixedSwapPair!]    @derivedFrom(field: "globalStatistic")                          
     
    "number of total orders. fixed rate exchange orders + dispenser orders"
    orderCount: Int!                                    

    "total nfts(erc721) created"
    nftCount: Int!
    "total datatokens (tokens with isDatatoken = true) created"
    datatokenCount:Int!  
    
    "number of fixed rate exchanges"
    fixedCount: Int!

    "number of dispensers created"
    dispenserCount: Int!

   "current version"
    version: String
}

type OPC @entity {
    id: ID!
    "fee in percent for swaps involving OPC approved tokens"
    swapOceanFee: BigDecimal
    "fee in percent for swaps involving non OPC approved tokens"
    swapNonOceanFee: BigDecimal
    "fee in percent taken by OPC from orderFees"
    orderFee: BigDecimal
    "fee in percent taken by OPC from providerFees"
    providerFee: BigDecimal
    approvedTokens: [Token!]
}

 enum NftUpdateType {
  METADATA_CREATED,
  METADATA_UPDATED,
  STATE_UPDATED,
  TOKENURI_UPDATED
}

type NftUpdate @entity {
  id: ID! # update tx +  nft address
  tokenUri: String
  nft: Nft!

  "provider url that can decrypt the ddo"                                  
  providerUrl: String  

 "user that made the update"
  userAddress: String!

  "state of the asset in this update"
  assetState: Int!

  "type of the update: metadata created, metadata update, state update, token uri update"
  type: NftUpdateType!

  block: Int!
  timestamp: Int!
  tx: String!
}

type Template @entity{
  id: ID!
  fixedRateTemplates: [String!]
  dispenserTemplates: [String!]
  ssTemplates: [String!]
}

# Not tracking allocationToId or idToAllocation
type VeAllocateUser @entity{
  "id = {user}"
  id: ID!
  
  veAllocation: [VeAllocation!] @derivedFrom(field: "allocationUser")  
  allocatedTotal: BigDecimal!

  block: Int!
  firstContact: Int!
  lastContact: Int!
  tx: String!
  veOcean: VeOCEAN!
}

type VeAllocateId @entity{
  "id = {DataNFT Address}-{chain id}"
  id: ID!
  nftAddress: String!
  chainId: BigInt!

  veAllocation: [VeAllocation!] @derivedFrom(field: "allocationId")
  allocatedTotal: BigDecimal!

  block: Int!
  firstContact: Int!
  lastContact: Int!
  tx: String!
}

# we need to track allocation of user to id
type VeAllocation @entity {
  "id = {user}-{DataNFT Address}-{chain id}"
  id: ID!

  allocationUser: VeAllocateUser!
  allocationId: VeAllocateId!
  
  updates: [VeAllocationUpdate!] @derivedFrom(field: "veAllocation")
  allocated: BigDecimal!
  chainId: BigInt!
  nftAddress: String!

  block: Int!
  firstContact: Int!
  lastContact: Int!
  tx: String!
}

enum veAllocationUpdateType {
  SET,
  REMOVED
}

type VeAllocationUpdate @entity {
  "{tx}-{VeAllocation id}"
  id: ID!
 
  veAllocation: VeAllocation!
  type: veAllocationUpdateType!
  allocatedTotal: BigDecimal!

  block: Int!
  timestamp: Int!
  tx: String!
}

type VeDelegation @entity {
  "id = tokenId"
  id: ID!
  delegator: VeOCEAN!
  receiver: VeOCEAN!
  tokenId: BigInt!
  amount: BigInt!
  cancelTime: BigInt!
  expireTime: BigInt!
  block: Int!
}

type VeOCEAN @entity {
  "id = {user address}"
  id: ID!
  "total amount of locked tokens"
  lockedAmount: BigDecimal!
  "unlock timestamp"
  unlockTime: BigInt!
  delegation: [VeDelegation!] @derivedFrom(field: "delegator")
  delegates: [VeDelegation!] @derivedFrom(field: "receiver")
  deposits: [VeDeposit!] @derivedFrom(field: "veOcean")
  claims: [VeClaim!] @derivedFrom(field: "veOcean")
  allocation: VeAllocateUser @derivedFrom(field: "veOcean")
  block: Int!
}

type VeDeposit @entity {
  "id = {user address}-{timestamp}"
  id: ID!
  "veOcean holder"
  provider:String!
  "who initiated the tx"
  sender: String!
  "amount of tokens locked"
  value: BigDecimal!
  "unlock timestamp"
  unlockTime: BigInt!
  "deposit type: DEPOSIT_FOR = 0, CREATE_LOCK_TYPE = 1,INCREASE_LOCK_AMOUNT = 2,INCREASE_UNLOCK_TIME = 3, WITHDRAW = 4"
  type:BigInt!
  timestamp: BigInt!
  block: Int!
  tx: String!
  veOcean: VeOCEAN!
}


type VeFeeDistributor @entity {
  "id = contract address"
  id: ID!
  "token used by FeeDistributor"
  token: Token!
  claims: [VeClaim!] @derivedFrom(field: "VeFeeDistributor")
  checkpoints: [VeFeeDistributorCheckPoint!] @derivedFrom(field: "VeFeeDistributor")
}

type VeFeeDistributorCheckPoint @entity {
  "id = {tx}-{eventno}"
  id: ID!
  "amount of tokens for rewards"
  tokens: BigDecimal!
  "who initiated the tx"
  sender: String!
  VeFeeDistributor: VeFeeDistributor!
  timestamp: BigInt!
  block: Int!
  tx: String!
}

type VeClaim @entity {
  "id = {tx}-{eventno}"
  id: ID!
  "amount of tokens claimed"
  amount: BigDecimal!
  "claim epoch"
  claim_epoch: BigInt
  "max_epoch"
  max_epoch: BigInt
  timestamp: BigInt!
  block: Int!
  tx: String!
  veOcean: VeOCEAN!
  VeFeeDistributor: VeFeeDistributor!
}

enum DFHistoryType {
  Allocated,
  Claimed
}

type DFAvailableClaim @entity {
  "id = {userId}-{tokenId}"
  id: ID!
  receiver: DFReward!
  amount: BigDecimal!
  token: Token!
}


type DFHistory @entity {
  "id = {user-id}-{txId}-{eventId}"
  id: ID!
  receiver: DFReward!
  amount: BigDecimal!
  token: Token!
  type: DFHistoryType!
  timestamp: BigInt!
  block: Int!
  tx: String!
}


type DFReward @entity {
  "id = {user address}"
  id: ID!
  receiver: User!
  availableClaims: [DFAvailableClaim!] @derivedFrom(field: "receiver")
  history: [DFHistory!] @derivedFrom(field: "receiver")
}