# === this part of the schema comes from giant squid === # https://github.com/subsquid-labs/giant-squid-explorer/blob/main/schema.graphql # Block / Extrinsic / Call / Event type Block @entity { "BlockHeight-blockHash - e.g. 0001812319-0001c" id: ID! height: Int! @index hash: Bytes! @index parentHash: Bytes! stateRoot: Bytes! extrinsicsicRoot: Bytes! specName: String! specVersion: Int! @index implName: String! implVersion: Int! timestamp: DateTime! @index validator: Bytes @index extrinsicsCount: Int! callsCount: Int! eventsCount: Int! extrinsics: [Extrinsic]! @derivedFrom(field: "block") @cardinality(value: 1000) calls: [Call]! @derivedFrom(field: "block") @cardinality(value: 1000) events: [Event]! @derivedFrom(field: "block") @cardinality(value: 1000) } type ExtrinsicSignature { address: JSON signature: JSON signedExtensions: JSON } type Extrinsic @entity { id: ID! block: Block! call: Call! index: Int! version: Int! signature: ExtrinsicSignature tip: BigInt fee: BigInt success: Boolean @index error: JSON hash: Bytes! @index calls: [Call]! @derivedFrom(field: "extrinsic") events: [Event]! @derivedFrom(field: "extrinsic") } type Call @entity @index(fields: ["id", "pallet", "name"]) { id: ID! block: Block! extrinsic: Extrinsic parent: Call address: [Int!]! success: Boolean! @index error: JSON pallet: String! @index name: String! @index args: JSON argsStr: [String] subcalls: [Call]! @derivedFrom(field: "parent") events: [Event]! @derivedFrom(field: "call") } type Event @entity @index(fields: ["id", "pallet", "name"]) { "Event id - e.g. 0000000001-000000-272d6" id: ID! block: Block! extrinsic: Extrinsic call: Call index: Int! phase: String! pallet: String! @index name: String! @index args: JSON argsStr: [String] } enum CounterLevel { Global Pallet Item } enum ItemType { Extrinsics Calls Events } type ItemsCounter @entity { id: ID! type: ItemType! @index level: CounterLevel! @index total: Int! @index } # === this part of the schema is for substrate pallets === # Balances / "Account table identified by its ss58 address" type Account @entity { "Account address is SS58 format" id: ID! "Block number of account creation" # if account is created multiple times, this is the first creation block createdOn: Int! "current account for the identity" identity: Identity @derivedFrom(field: "account") "removed identities on this account" # they are handled apart to avoid dropping the @unique constraint of account removedIdentities: [Identity] @derivedFrom(field: "accountRemoved") "was once account of the identity" wasIdentity: [ChangeOwnerKey!] @derivedFrom(field: "previous") # there should be at most one "linked to the identity" linkedIdentity: Identity "transfers issued by this account" transfersIssued: [Transfer!] @derivedFrom(field: "from") "transfers received by this account" transfersReceived: [Transfer!] @derivedFrom(field: "to") "comments issued" commentsIssued: [TxComment!] @derivedFrom(field: "author") "is currently active" isActive: Boolean! } "Since identities can change owner key, validator table helps track which smith is forging the block" # this could be removed if we fix the following issues # https://git.duniter.org/nodes/rust/duniter-v2s/-/issues/197 # https://git.duniter.org/nodes/rust/duniter-v2s/-/issues/245 type Validator @entity { "SS58 of pubkey used at least once to compute a block" id: ID! "Identity index of Smith who owned this pubkey" index: Int! @index } "Transfers" type Transfer @entity { "Block number of the transfer" blockNumber: Int! @index "Timestamp of the transfer (duplicate of block timestamp)" timestamp: DateTime! @index "Transfer issuer" from: Account! "Transfer receiver" to: Account! "Integer amount of the transfer" amount: BigInt! @index "Event the transfer was created in" # allows to find the call and block event: Event! "Optional comment linked to the transfer" comment: TxComment } type Smith @entity { "Identity index" index: Int! @index @unique identity: Identity! @unique "Smith certifications issued" smithCertIssued: [SmithCert!] @derivedFrom(field: "issuer") "Smith certifications received" smithCertReceived: [SmithCert!] @derivedFrom(field: "receiver") "Smith status of the identity" smithStatus: SmithStatus "history of the smith changes events" smithHistory: [SmithEvent] @derivedFrom(field: "smith") "Last status change" lastChanged: Int "Number of forged blocks" forged: Int! "Last forged block" lastForged: Int } # === this part of the schema is for Duniter pallets === # "Identity" type Identity @entity { "Identity index" index: Int! @index @unique "Current account" # should be null for a removed identity and only in this case account: Account @unique "Let track the account in case identity was removed" # should be non null for a removed identity and only in this case accountRemoved: Account "Name" name: String! @index "Status of the identity" # mixes identity pallet status (Unconfirmed, Unvalidated, Revoked) # and membership pallet status (Member, WasMember) # and a special status "Removed" specific to the indexer status: IdentityStatus! @index "Block number of identity creation event" createdOn: Int! "Event corresponding of identity creation event" createdIn: Event! "Block number of last identity, changeOwnerKey and membership active event" # - creation block # - confirmation block # - validation block # - membership renewal block # - manual revocation # but not # - membership expiry # - auto-revocation # - duniter deletion lastChangeOn: Int! "Certifications issued" certIssued: [Cert!] @derivedFrom(field: "issuer") "Certifications received" certReceived: [Cert!] @derivedFrom(field: "receiver") "True if the identity is a member" isMember: Boolean! "the current expireOn value" # Unconfirmed → block of expected confirmation (future) # Unvalidated → block of expected validation (future) # Member → block of membership expiry (future) # NotMember → block of auto-revocation (future) # Revoked → block of revocation (past) # Removed → still block of revocation (past) because only Duniter "garbage collection" expireOn: Int! "history of the membership changes events" membershipHistory: [MembershipEvent] @derivedFrom(field: "identity") "Owner key changes" ownerKeyChange: [ChangeOwnerKey!] @derivedFrom(field: "identity") "linked accounts" linkedAccount: [Account!] @derivedFrom(field: "linkedIdentity") "Smith information" smith: Smith @derivedFrom(field: "identity") "Universal Dividend history" udHistory: [UdHistory!] @derivedFrom(field: "identity") } "identity status directly linked to Duniter IdtyStatus" enum IdentityStatus { Unconfirmed Unvalidated Member NotMember Revoked # this status is added because the indexer keeps track of the history # and does not remove an identity event when it is remove from Duniter Removed } "smith status directly linked to Duniter SmithStatus" # used as a nullable field because most identities are not smith as well enum SmithStatus { Invited Pending Smith Excluded } "owner key change" type ChangeOwnerKey @entity { identity: Identity! previous: Account! next: Account! blockNumber: Int! } "Certification" type Cert @entity { "certification source" issuer: Identity! @index "certification target" receiver: Identity! @index "whether the certification is currently active or not" isActive: Boolean! "the first block number of the certification creation" # (helper field to avoid looking for all CertCreation and choose the first) createdOn: Int! "the event corresponding to the first certification creation" createdIn: Event! "the last block number of the certification renewal" updatedOn: Int! "the event corresponding to the last certification renewal" updatedIn: Event! "the current expireOn value" # usually this is updatedOn + certDuration *but*: # - certs can be removed prematurely for unconfirmed or unvalidated identity # - update can be before genesis, in this case we still need expire block after genesis expireOn: Int! "list all events of this cert" certHistory: [CertEvent!] @derivedFrom(field: "cert") } "Certification event" type CertEvent @entity { cert: Cert! @index event: Event! blockNumber: Int! @index eventType: EventType! } "Smith certification" type SmithCert @entity { issuer: Smith! receiver: Smith! createdOn: Int! } type SmithEvent @entity { smith: Smith! @index eventType: SmithEventType! event: Event! blockNumber: Int! @index } enum SmithEventType { Invited Accepted Promoted Excluded } type MembershipEvent @entity { identity: Identity! @index eventType: EventType! event: Event! blockNumber: Int! @index } "event type used for certification and membership" enum EventType { "creation event" Creation "renewal event" Renewal "removal event" Removal } "Each Universal Dividend created since the beginning of the blockchain" type UniversalDividend @entity { blockNumber: Int! event: Event! timestamp: DateTime! amount: BigInt! monetaryMass: BigInt! membersCount: Int! } "List of reevaluation of Universal Dividend based on changes in monetary mass and number of members. Every 6 months in Ğ1" type UdReeval @entity { blockNumber: Int! event: Event! timestamp: DateTime! newUdAmount: BigInt! monetaryMass: BigInt! membersCount: Int! } "History of Universal Dividend received by an member identity." type UdHistory @entity { identity: Identity! @index amount: BigInt! blockNumber: Int! timestamp: DateTime! } "transaction comment" type TxComment @entity { "Block number of the comment" # allows easy sorting blockNumber: Int! "Author of the comment" author: Account! "Event where the comment comes from" event: Event! "Raw remark as present on the blockchain" remarkBytes: Bytes! "Remark decoded as string" remark: String! "Blake two 256 hash published by the blockchain in the remark event" # not used at the moment, will be changed in Duniter hash: String! "Type of the comment" # now classified by the indexer, can later appear in Duniter type: CommentType! } "type of the tx comment" # by order of preference enum CommentType { "bytes look like a CID" Cid "bytes can be decoded to printable ascii" Ascii "bytes can be decoded to printable utf8" Unicode "no known type, raw bytes" Raw } "History of the blockchain population." type PopulationHistory @entity { "The count of smiths at this point in the history." smithCount: Int! "The count of members at this point in the history." memberCount: Int! "The count of active accounts at this point in the history." activeAccountCount: Int! "The block number at which this history record was created." blockNumber: Int! @index @unique }