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, expressed in wei in contracts, needs conversion in decimals."             
    publishMarketFeeAmmount: 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")

    "pools, only available for datatokens"
    pools: [Pool!] @derivedFrom(field:"datatoken")

    "block time datatoken was created"
    createdTimestamp: Int!        

    "datatoken creation transaction id"                         
    tx: String!        

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

"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!     

    "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!           


    "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!                                              
}

type Pool @entity {
    "pool address"
    id: ID!    

    "owner address, pool controller"                                   
    controller: String!

    "only finalized pools are relevant to us"                             
    isFinalized: Boolean!                                   
    
    "pool token symbol"
    symbol: String      

    "pool token name"                                    
    name: String    

    "maximum supply if any, converted from wei"                                        
    cap: BigDecimal                                              

    baseToken: Token! 
    baseTokenLiquidity: BigDecimal!
    baseTokenWeight: BigDecimal!
    
    datatoken: Token!
    datatokenLiquidity: BigDecimal!
    datatokenWeight: BigDecimal!

    "publisher market fee   : SWAP, JOIN , EXIT"
    marketSwapFee: BigDecimal! 

    "liquidity provider fee"
    liquidityProviderFee: BigDecimal!

    "OPF Fee percent, fee that goes to Ocean Protocol Foundation : SWAP"                                    
    opcFee: BigDecimal!           

    "total pool token shares"                           
    totalShares: BigDecimal!   

    "total tokens that were swaped"                             
    totalSwapVolume: [TokenValuePair!]!                         

    spotPrice: BigDecimal!                                  

    "count for when liquidity has been added"
    joinCount: BigInt!             

    "count for when liquidity has been removed"                     
    exitCount: BigInt!              

    "count for when tokens were swapped"                             
    swapCount: BigInt!

    "number of transactions in this pool involving liquidity changes"
    transactionCount: BigInt!                               
   
    "block time when pool was created"
    createdTimestamp: Int!      
    "pool creation transaction id"                            
    tx: String!    
    "block number when it was created"                                          
    block: Int                                              

    shares: [PoolShare!] @derivedFrom(field: "pool")
    transactions: [PoolTransaction!] @derivedFrom(field: "pool")

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

    "fee amount. Fixed value, expressed in wei in contracts, needs conversion in decimals."             
    publishMarketSwapFee: BigDecimal   

    "LP fee amount. Fixed value, expressed in wei in contracts, needs conversion in decimals."             
    liquidityProviderSwapFee: BigDecimal   

}

# we will need to track pool share tx between users -  bpool transfer tx event
type PoolShare @entity {
  "poolAddress + userAddress"
  id: ID!                                                   
  user: User!
  pool: Pool!
  shares: BigDecimal!
}

 enum PoolTransactionType {
  JOIN,
  EXIT,
  SWAP,
  SETUP
}

type PoolTransaction @entity {
  "tx address + caller address" 
  id: ID!        
  "pool related to this tx"                                            
  pool: Pool!   
  "user that initiates the tx"                                             
  user: User!                                              
  type: PoolTransactionType!                                                  
  
  "number of shares transfered"
  sharesTransferAmount: BigDecimal!                           
 
  "block time when pool was created"
  timestamp: Int!      
  "pool creation transaction id"                            
  tx: String!    
  "block number when it was created"                                          
  block: Int       

  gasLimit: BigDecimal!  
  "price expressed in eth"                                    
  gasPrice: BigDecimal!                                      

  "base tokens transfered"
  baseToken: Token 

  "number of base tokens transfered, if value is negative it means it was removed"       
  baseTokenValue: BigDecimal

  "datatokens transfered"                        
  datatoken: Token

  "number of datatokens transfered, if value is negative it means it was removed"
  datatokenValue: 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

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

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

# to be removed, mabye for pool shares only 
type TokenTransaction @entity {
  id: ID! # Log ID
  event: String
  token: Token
  user: User

  block: Int!
  gasUsed: BigDecimal!
  gasPrice: BigDecimal!
  createdTimestamp: Int!
  tx: String!
}

type User @entity {
  id: ID!
  sharesOwned: [PoolShare!] @derivedFrom(field: "user")
  tokenBalancesOwned: [TokenValuePair!]
  poolTransactions: [PoolTransaction!] @derivedFrom(field: "user")
  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!                                                    
  owner: User!
  datatoken: Token!
  baseToken: Token!
  "amount of datatokens available to be sold, this is relevant if the exchange is not able to mint"
  datatokenBalance: BigDecimal!
  "amount of basetokens available to be collected by the owner"
  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             

  marketSwapFee: BigDecimal!

  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, expressed in wei in contracts, needs conversion in decimals."             
  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!                                                      
  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!
}

type PoolSnapshot @entity {
  id: ID!
  pool: Pool!
  "total pool shares at the end of the 24h interval"
  totalShares: BigDecimal!
  "swap value 24h"
  swapVolume: BigDecimal!   
  "swap fee value 24h"                                          
  swapFees: BigDecimal! 
  "date without time"                                              
  date: Int!         
  "last spot price in the 24h interval"                                 
  spotPrice: BigDecimal!                                         
  
  baseToken: Token!
  baseTokenLiquidity: BigDecimal!

  datatoken: Token!
  datatokenLiquidity: BigDecimal! 

}

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

"utility type"
type GlobalTotalPoolSwapPair @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!
}
type GlobalStatistic @entity {
    id: ID!

    "total liquidity for each base token in pools"                  
    totalLiquidity: [GlobalTotalLiquidityPair!]!   @derivedFrom(field: "globalStatistic")                      
    "total swap volume for each base token in pools"
    totalPoolSwapVolume: [GlobalTotalPoolSwapPair!]!  @derivedFrom(field: "globalStatistic")        

    "total swap volume for each base token in fixed rate exchanges"
    totalFixedSwapVolume: [GlobalTotalFixedSwapPair!]    @derivedFrom(field: "globalStatistic")                          
     
    "number of total orders. pool 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 pools"
    poolCount: Int!     
    
    "number of fixed rate exchanges"
    fixedCount: Int!

    "number of dispensers created"
    dispenserCount: Int!
}


 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!
}