diff --git a/README.md b/README.md index 1534927aa..f0a18c356 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # Astral -- [Astral Block Explorer](https://explorer.subspace.network/) Astral Block Explorer +- [Astral Block Explorer](https://explorer.autonomys.xyz/) Astral Block Explorer - [Astral Subsquid Playground](https://squid.gemini-3g.subspace.network/graphql) Astral Subspace SubSquid - [Health Check](https://uptime.subspace.network/status/network) Subspace Network Status Page diff --git a/explorer/next.config.js b/explorer/next.config.js index 21d355cc3..626c76920 100644 --- a/explorer/next.config.js +++ b/explorer/next.config.js @@ -6,7 +6,7 @@ const nextConfig = { remotePatterns: [ { protocol: 'https', - hostname: 'docs.subspace.network', + hostname: 'docs.autonomys.xyz', port: '', pathname: '**', }, diff --git a/explorer/src/components/Farming/index.tsx b/explorer/src/components/Farming/index.tsx index 013220a19..d28d0f5c2 100644 --- a/explorer/src/components/Farming/index.tsx +++ b/explorer/src/components/Farming/index.tsx @@ -187,7 +187,7 @@ export const DownloadPage: FC = () => { alt='Space Acres Screenshot Installation' width={800} height={400} - src='https://docs.subspace.network/assets/images/space-acres-setup-7-3490cba2e75635efdea0006d06da9936.png' + src='https://docs.autonomys.xyz/assets/images/space-acres-setup-7-3490cba2e75635efdea0006d06da9936.png' className='mx-auto' /> @@ -198,8 +198,6 @@ export const DownloadPage: FC = () => { By contributing storage and compute to the network, you play a crucial role in securing it, while also earning rewards. - -
diff --git a/explorer/src/components/WalletSideKick/PendingTransactions.tsx b/explorer/src/components/WalletSideKick/PendingTransactions.tsx index 774ede227..7ed7b0f00 100644 --- a/explorer/src/components/WalletSideKick/PendingTransactions.tsx +++ b/explorer/src/components/WalletSideKick/PendingTransactions.tsx @@ -160,7 +160,10 @@ export const PendingTransactions: FC = ({
- +
handleRemove(tx)} /> diff --git a/explorer/src/components/common/StatusIcon.tsx b/explorer/src/components/common/StatusIcon.tsx index 50c2e95f4..32dab0f34 100644 --- a/explorer/src/components/common/StatusIcon.tsx +++ b/explorer/src/components/common/StatusIcon.tsx @@ -1,14 +1,16 @@ -import { CheckCircleIcon, ClockIcon } from '@heroicons/react/24/outline' +import { CheckCircleIcon, ClockIcon, XCircleIcon } from '@heroicons/react/24/outline' import { FC } from 'react' type Props = { status: boolean + isPending?: boolean } -export const StatusIcon: FC = ({ status }) => { +export const StatusIcon: FC = ({ status, isPending }) => { + if (isPending) return return status ? ( ) : ( - + ) } diff --git a/explorer/src/constants/metadata.ts b/explorer/src/constants/metadata.ts index d60959877..9003bd9cf 100644 --- a/explorer/src/constants/metadata.ts +++ b/explorer/src/constants/metadata.ts @@ -3,7 +3,7 @@ const organization = 'Subspace Labs' const description = 'Subspace Labs Gemini Block Explorer' const keywords = 'Subspace, Subspace Network, Subspace Explorer, Subspace Labs, Subspace Labs Gemini, Subspace Labs Gemini Block Explorer' -export const url = process.env.NEXTAUTH_URL || 'https://explorer.subspace.network' +export const url = process.env.NEXTAUTH_URL || 'https://explorer.autonomys.xyz' const twitter = '@SubspaceLabs' const images = { url: url + '/images/share.png', diff --git a/explorer/src/constants/routes.ts b/explorer/src/constants/routes.ts index a64087e3e..403d7df63 100644 --- a/explorer/src/constants/routes.ts +++ b/explorer/src/constants/routes.ts @@ -55,9 +55,9 @@ export const EXTERNAL_ROUTES = { forum: 'https://forum.autonomys.xyz/', gemini2guide: 'https://forum.autonomys.xyz/t/how-to-check-your-balance-for-gemini-ii-incentivized-testnet/1081', - docs: 'https://docs.subspace.network/', + docs: 'https://docs.autonomys.xyz/', operatorDocs: - 'https://docs.subspace.network/docs/farming-&-staking/staking/operators/register-operator', + 'https://docs.autonomys.xyz/docs/farming-&-staking/staking/operators/register-operator', social: { twitter: 'https://x.com/AutonomysNet', discord: 'https://discord.gg/subspace-network', diff --git a/explorer/src/hooks/useConsensusData.ts b/explorer/src/hooks/useConsensusData.ts index 241d64cdf..231cbc103 100644 --- a/explorer/src/hooks/useConsensusData.ts +++ b/explorer/src/hooks/useConsensusData.ts @@ -2,7 +2,7 @@ import useWallet from 'hooks/useWallet' import { useCallback } from 'react' import { useConsensusStates } from 'states/consensus' import { - ConfirmedDomainBlock, + ConfirmedDomainExecutionReceipt, DomainRegistry, DomainStakingSummary, PendingStakingOperationCount, @@ -17,7 +17,7 @@ export const useConsensusData = () => { setSystem, setDomainRegistry, setDomainStakingSummary, - setLatestConfirmedDomainBlock, + setLatestConfirmedDomainExecutionReceipt, setNominatorCount, setOperatorIdOwner, setOperators, @@ -41,7 +41,7 @@ export const useConsensusData = () => { // domains domainRegistry, domainStakingSummary, - latestConfirmedDomainBlock, + latestConfirmedDomainExecutionReceipt, nominatorCount, operatorIdOwner, operators, @@ -53,9 +53,10 @@ export const useConsensusData = () => { // system api.rpc.system.chain(), api.rpc.system.name(), + // domains api.query.domains.domainRegistry.entries(), api.query.domains.domainStakingSummary.entries(), - api.query.domains.latestConfirmedDomainBlock.entries(), + api.query.domains.latestConfirmedDomainExecutionReceipt.entries(), api.query.domains.nominatorCount.entries(), api.query.domains.operatorIdOwner.entries(), api.query.domains.operators.entries(), @@ -106,10 +107,10 @@ export const useConsensusData = () => { setDomainStakingSummary( domainStakingSummary.map((domain) => domain[1].toJSON() as DomainStakingSummary), ) - setLatestConfirmedDomainBlock( - latestConfirmedDomainBlock.map((domainBlock) => ({ + setLatestConfirmedDomainExecutionReceipt( + latestConfirmedDomainExecutionReceipt.map((domainBlock) => ({ id: parseInt((domainBlock[0].toHuman() as string[])[0]), - ...(domainBlock[1].toJSON() as Omit), + ...(domainBlock[1].toJSON() as Omit), })), ) setNominatorCount( diff --git a/explorer/src/states/consensus.ts b/explorer/src/states/consensus.ts index 84dc83f86..3dbd37d48 100644 --- a/explorer/src/states/consensus.ts +++ b/explorer/src/states/consensus.ts @@ -1,6 +1,6 @@ import type { Deposit, Withdrawal } from '@autonomys/auto-consensus' import { - ConfirmedDomainBlock, + ConfirmedDomainExecutionReceipt, Domain, DomainRegistry, DomainStakingSummary, @@ -28,7 +28,7 @@ export interface ConsensusDefaultState { // domains domainRegistry: DomainRegistry[] domainStakingSummary: DomainStakingSummary[] - latestConfirmedDomainBlock: ConfirmedDomainBlock[] + latestConfirmedDomainExecutionReceipt: ConfirmedDomainExecutionReceipt[] // latestSubmittedER: LatestSubmittedER[] nominatorCount: NominatorCount[] operatorIdOwner: OperatorIdOwner[] @@ -51,7 +51,9 @@ interface ConsensusState extends ConsensusDefaultState { setSystem: (params: { chain: string; name: string }) => void setDomainRegistry: (domainRegistry: DomainRegistry[]) => void setDomainStakingSummary: (domainStakingSummary: DomainStakingSummary[]) => void - setLatestConfirmedDomainBlock: (latestConfirmedDomainBlock: ConfirmedDomainBlock[]) => void + setLatestConfirmedDomainExecutionReceipt: ( + latestConfirmedDomainExecutionReceipt: ConfirmedDomainExecutionReceipt[], + ) => void setNominatorCount: (nominatorCount: NominatorCount[]) => void setOperatorIdOwner: (operatorIdOwner: OperatorIdOwner[]) => void setOperators: (operators: Operators[]) => void @@ -77,7 +79,7 @@ const initialState: ConsensusDefaultState = { // domains domainRegistry: [], domainStakingSummary: [], - latestConfirmedDomainBlock: [], + latestConfirmedDomainExecutionReceipt: [], // latestSubmittedER: [], nominatorCount: [], operatorIdOwner: [], @@ -104,8 +106,8 @@ export const useConsensusStates = create()( setSystem: (params) => set(() => ({ chain: params.chain, name: params.name })), setDomainRegistry: (domainRegistry) => set(() => ({ domainRegistry })), setDomainStakingSummary: (domainStakingSummary) => set(() => ({ domainStakingSummary })), - setLatestConfirmedDomainBlock: (latestConfirmedDomainBlock) => - set(() => ({ latestConfirmedDomainBlock })), + setLatestConfirmedDomainExecutionReceipt: (latestConfirmedDomainExecutionReceipt) => + set(() => ({ latestConfirmedDomainExecutionReceipt })), setNominatorCount: (nominatorCount) => set(() => ({ nominatorCount })), setOperatorIdOwner: (operatorIdOwner) => set(() => ({ operatorIdOwner })), setOperators: (operators) => set(() => ({ operators })), diff --git a/explorer/src/types/consensus.ts b/explorer/src/types/consensus.ts index f0c8fe1c1..8355738f9 100644 --- a/explorer/src/types/consensus.ts +++ b/explorer/src/types/consensus.ts @@ -56,13 +56,9 @@ export type DomainStakingSummary = { } } -export type ConfirmedDomainBlock = { +export type ConfirmedDomainExecutionReceipt = { id: number - blockNumber: number - blockHash: string - parentBlockReceiptHash: string - stateRoot: string - extrinsicsRoot: string + domainBlockNumber: number } export type NominatorCount = { diff --git a/explorer/src/utils/auth/providers/nova.ts b/explorer/src/utils/auth/providers/nova.ts index c98789203..bfc3a1bc6 100644 --- a/explorer/src/utils/auth/providers/nova.ts +++ b/explorer/src/utils/auth/providers/nova.ts @@ -30,7 +30,7 @@ export const Nova = () => { const verifyParams: VerifyParams = { signature, - domain: 'subspace.network', + domain: 'autonomys.xyz', nonce: await getCsrfToken({ req }), } diff --git a/indexers/staking-squid/README.md b/indexers/staking-squid/README.md index 8b6a93548..d23790025 100644 --- a/indexers/staking-squid/README.md +++ b/indexers/staking-squid/README.md @@ -1,7 +1,7 @@ # Staking squid Our Staking Indexer using [Squid](https://subsquid.io). -It is in use at [Astral - Staking](https://explorer.subspace.network/gemini-3h/staking) Autonomus Explorer, Staking section. +It is in use at [Astral - Staking](https://explorer.autonomys.xyz/gemini-3h/staking) Autonomys Explorer, Staking section. ## Summary diff --git a/indexers/staking-squid/db/migrations/1721778314620-Data.js b/indexers/staking-squid/db/migrations/1722613051042-Data.js similarity index 55% rename from indexers/staking-squid/db/migrations/1721778314620-Data.js rename to indexers/staking-squid/db/migrations/1722613051042-Data.js index 68d44ce9d..3be75732c 100644 --- a/indexers/staking-squid/db/migrations/1721778314620-Data.js +++ b/indexers/staking-squid/db/migrations/1722613051042-Data.js @@ -1,132 +1,132 @@ -module.exports = class Data1721778314620 { - name = 'Data1721778314620' +module.exports = class Data1722613051042 { + name = 'Data1722613051042' async up(db) { - await db.query(`CREATE TABLE "withdrawal" ("id" character varying NOT NULL, "block_number" integer NOT NULL, "account" text NOT NULL, "shares" numeric NOT NULL, "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, "extrinsic_hash" text NOT NULL, "status" character varying(8) NOT NULL, "operator_id" character varying, "nominator_id" character varying, CONSTRAINT "PK_840e247aaad3fbd4e18129122a2" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_e8ac24b4a9b9657cd27289feea" ON "withdrawal" ("block_number") `) - await db.query(`CREATE INDEX "IDX_25c7ac5a7731ac3ce7982bef67" ON "withdrawal" ("account") `) - await db.query(`CREATE INDEX "IDX_d5f5ce8abff91d6485c4f84e57" ON "withdrawal" ("operator_id") `) - await db.query(`CREATE INDEX "IDX_09c9cf2ad9a4f3b674540dbfcf" ON "withdrawal" ("nominator_id") `) - await db.query(`CREATE INDEX "IDX_e2749aaf8ba367458c360a7c73" ON "withdrawal" ("timestamp") `) - await db.query(`CREATE INDEX "IDX_9c33f1820b02bef49172b9883f" ON "withdrawal" ("extrinsic_hash") `) - await db.query(`CREATE INDEX "IDX_4028ed4e39f5c919fc3317882b" ON "withdrawal" ("status") `) - await db.query(`CREATE TABLE "nominator" ("id" character varying NOT NULL, "account" text NOT NULL, "shares" numeric NOT NULL, "total_deposits" numeric NOT NULL, "deposits_count" integer NOT NULL, "withdrawals_count" integer NOT NULL, "status" character varying(12) NOT NULL, "created_at" integer, "updated_at" integer, "operator_id" character varying, CONSTRAINT "PK_7489b7a79b066f2660eab25f60b" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_ef8faa81be0a51d54fc727b9fb" ON "nominator" ("account") `) + await db.query(`CREATE TABLE "domain" ("id" character varying NOT NULL, "sort_id" integer NOT NULL, "completed_epoch" integer NOT NULL, "last_domain_block_number" integer NOT NULL, "total_deposits" numeric NOT NULL, "total_tax_collected" numeric NOT NULL, "total_rewards_collected" numeric NOT NULL, "current_total_stake" numeric NOT NULL, "current_storage_fee_deposit" numeric NOT NULL, "created_at" integer, "updated_at" integer, CONSTRAINT "PK_27e3ec3ea0ae02c8c5bceab3ba9" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_c1e90b3654ffe0a5544e502edb" ON "domain" ("sort_id") `) + await db.query(`CREATE INDEX "IDX_80867983eb3f6e204acfea4214" ON "domain" ("completed_epoch") `) + await db.query(`CREATE INDEX "IDX_e3a1b94f40001682587d9b0a3d" ON "domain" ("last_domain_block_number") `) + await db.query(`CREATE INDEX "IDX_35b49bec8ab1e3864de09a60d6" ON "domain" ("created_at") `) + await db.query(`CREATE INDEX "IDX_c3ac554ab7a2ed97d9a0af4083" ON "domain" ("updated_at") `) + await db.query(`CREATE TABLE "account" ("id" character varying NOT NULL, "total_deposits" numeric NOT NULL, "total_tax_collected" numeric NOT NULL, "created_at" integer, "updated_at" integer, CONSTRAINT "PK_54115ee388cdb6d86bb4bf5b2ea" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_2740156ea8742b8df1ad9d9774" ON "account" ("created_at") `) + await db.query(`CREATE INDEX "IDX_8bed31488e09ed64770378600b" ON "account" ("updated_at") `) + await db.query(`CREATE TABLE "operator" ("id" character varying NOT NULL, "sort_id" integer NOT NULL, "account_id" text NOT NULL, "domain_id" text NOT NULL, "signing_key" text NOT NULL, "minimum_nominator_stake" numeric NOT NULL, "nomination_tax" integer NOT NULL, "current_total_stake" numeric NOT NULL, "current_storage_fee_deposit" numeric NOT NULL, "current_epoch_rewards" numeric NOT NULL, "current_total_shares" numeric NOT NULL, "total_deposits" numeric NOT NULL, "total_tax_collected" numeric NOT NULL, "total_rewards_collected" numeric NOT NULL, "raw_status" text, "status" character varying(15) NOT NULL, "bundle_count" integer NOT NULL, "last_bundle_at" integer NOT NULL, "created_at" integer, "updated_at" integer, CONSTRAINT "PK_8b950e1572745d9f69be7748ae8" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_ed3a1bcef6df98998f07a571a7" ON "operator" ("sort_id") `) + await db.query(`CREATE INDEX "IDX_91b197ab29ad85b5e616289ea0" ON "operator" ("account_id") `) + await db.query(`CREATE INDEX "IDX_1c800426a1f738c1b202ff839f" ON "operator" ("domain_id") `) + await db.query(`CREATE INDEX "IDX_51b6c3609906ff3cd25e39e1b2" ON "operator" ("signing_key") `) + await db.query(`CREATE INDEX "IDX_c7fd0bf382a9832cf1db87827c" ON "operator" ("status") `) + await db.query(`CREATE INDEX "IDX_d6260ed02d20cf8231ebb742d6" ON "operator" ("created_at") `) + await db.query(`CREATE INDEX "IDX_d6d18ca05472785030a7a3963b" ON "operator" ("updated_at") `) + await db.query(`CREATE TABLE "nominator" ("id" character varying NOT NULL, "account_id" text NOT NULL, "domain_id" text NOT NULL, "operator_id" text NOT NULL, "shares" numeric NOT NULL, "total_deposits" numeric NOT NULL, "status" character varying(12) NOT NULL, "created_at" integer, "updated_at" integer, CONSTRAINT "PK_7489b7a79b066f2660eab25f60b" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_917636e6d1130ea9506eaeafef" ON "nominator" ("account_id") `) + await db.query(`CREATE INDEX "IDX_b017cafe03fa79059bd8164c4e" ON "nominator" ("domain_id") `) await db.query(`CREATE INDEX "IDX_14374f281ccb6e72c55dab3c20" ON "nominator" ("operator_id") `) await db.query(`CREATE INDEX "IDX_43aeeb4c46d83dd78aa564c1b1" ON "nominator" ("status") `) await db.query(`CREATE INDEX "IDX_7093d62ba7e5a6387a686e607e" ON "nominator" ("created_at") `) await db.query(`CREATE INDEX "IDX_9ebc942736e76bde99ee21452f" ON "nominator" ("updated_at") `) - await db.query(`CREATE TABLE "deposit" ("id" character varying NOT NULL, "block_number" integer NOT NULL, "account" text NOT NULL, "amount" numeric NOT NULL, "storage_fee_deposit" numeric NOT NULL, "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, "extrinsic_hash" text NOT NULL, "status" character varying(9) NOT NULL, "operator_id" character varying, "nominator_id" character varying, CONSTRAINT "PK_6654b4be449dadfd9d03a324b61" PRIMARY KEY ("id"))`) + await db.query(`CREATE TABLE "deposit" ("id" character varying NOT NULL, "block_number" integer NOT NULL, "account_id" text NOT NULL, "domain_id" text NOT NULL, "operator_id" text NOT NULL, "nominator_id" text NOT NULL, "amount" numeric NOT NULL, "storage_fee_deposit" numeric NOT NULL, "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, "extrinsic_hash" text NOT NULL, "status" character varying(9) NOT NULL, CONSTRAINT "PK_6654b4be449dadfd9d03a324b61" PRIMARY KEY ("id"))`) await db.query(`CREATE INDEX "IDX_230a90fc5a10c7ac5ac35397d2" ON "deposit" ("block_number") `) - await db.query(`CREATE INDEX "IDX_f3abde1e7f8d7ca5102e376219" ON "deposit" ("account") `) + await db.query(`CREATE INDEX "IDX_9ced91570695137ec1d60c1a61" ON "deposit" ("account_id") `) + await db.query(`CREATE INDEX "IDX_8dc544cfa89fb544beea034396" ON "deposit" ("domain_id") `) await db.query(`CREATE INDEX "IDX_c2f2cfaa2b294c75d38a57e380" ON "deposit" ("operator_id") `) await db.query(`CREATE INDEX "IDX_b673efd4ec207b203e4d06abe9" ON "deposit" ("nominator_id") `) await db.query(`CREATE INDEX "IDX_a37222607a86476fa124313c51" ON "deposit" ("timestamp") `) await db.query(`CREATE INDEX "IDX_b1d1dadac59ff00a27b4ef18cf" ON "deposit" ("extrinsic_hash") `) await db.query(`CREATE INDEX "IDX_6f250bd43f2f631fcb2f589200" ON "deposit" ("status") `) - await db.query(`CREATE TABLE "operator_reward_event" ("id" character varying NOT NULL, "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, "block_number" integer NOT NULL, "extrinsic_hash" text NOT NULL, "amount" numeric NOT NULL, "operator_id" character varying, CONSTRAINT "PK_721a9f907ad1f01a5abed1f2e8e" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_b9cf23c6256a9fc7e01a271376" ON "operator_reward_event" ("operator_id") `) - await db.query(`CREATE INDEX "IDX_2b8b8fd9152da4d7ba4b71080c" ON "operator_reward_event" ("timestamp") `) - await db.query(`CREATE INDEX "IDX_d878c755d920f1be253bad97dd" ON "operator_reward_event" ("block_number") `) - await db.query(`CREATE INDEX "IDX_83b9c467963de152d3e83dcf58" ON "operator_reward_event" ("extrinsic_hash") `) - await db.query(`CREATE TABLE "operator_fees_earned" ("id" character varying NOT NULL, "amount" numeric NOT NULL, "updated_at" integer NOT NULL, "operator_id" character varying, CONSTRAINT "PK_65191b997e44f43ec2c5d68c7e1" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_c9dda7e56175bc755c449c5e02" ON "operator_fees_earned" ("operator_id") `) - await db.query(`CREATE TABLE "operator" ("id" character varying NOT NULL, "domain_id" integer NOT NULL, "operator_id" integer NOT NULL, "signing_key" text NOT NULL, "owner" text NOT NULL, "minimum_nominator_stake" numeric NOT NULL, "nomination_tax" integer NOT NULL, "current_total_stake" numeric NOT NULL, "current_storage_fee_deposit" numeric NOT NULL, "current_epoch_rewards" numeric NOT NULL, "current_total_shares" numeric NOT NULL, "total_deposits" numeric NOT NULL, "total_tax_collected" numeric NOT NULL, "raw_status" text, "status" character varying(12) NOT NULL, "nominators_count" integer NOT NULL, "deposits_count" integer NOT NULL, "withdrawals_count" integer NOT NULL, "bundle_count" integer NOT NULL, "last_bundle_at" integer NOT NULL, "created_at" integer, "updated_at" integer, CONSTRAINT "PK_8b950e1572745d9f69be7748ae8" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_1c800426a1f738c1b202ff839f" ON "operator" ("domain_id") `) - await db.query(`CREATE INDEX "IDX_ca18369599805e0d60e4ac0652" ON "operator" ("operator_id") `) - await db.query(`CREATE INDEX "IDX_51b6c3609906ff3cd25e39e1b2" ON "operator" ("signing_key") `) - await db.query(`CREATE INDEX "IDX_3b141ec6a3d1225075d8c6bc21" ON "operator" ("owner") `) - await db.query(`CREATE INDEX "IDX_c7fd0bf382a9832cf1db87827c" ON "operator" ("status") `) - await db.query(`CREATE INDEX "IDX_d6260ed02d20cf8231ebb742d6" ON "operator" ("created_at") `) - await db.query(`CREATE INDEX "IDX_d6d18ca05472785030a7a3963b" ON "operator" ("updated_at") `) - await db.query(`CREATE TABLE "domain" ("id" character varying NOT NULL, "domain_id" integer NOT NULL, "completed_epoch" integer NOT NULL, "last_domain_block_number" integer NOT NULL, "created_at" integer, "updated_at" integer, "last_operator_bundle_produced_id" character varying, CONSTRAINT "PK_27e3ec3ea0ae02c8c5bceab3ba9" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_2bc5e1041a74e1492dfda20688" ON "domain" ("domain_id") `) - await db.query(`CREATE INDEX "IDX_80867983eb3f6e204acfea4214" ON "domain" ("completed_epoch") `) - await db.query(`CREATE INDEX "IDX_555eee0485a3e1937915a26e6b" ON "domain" ("last_operator_bundle_produced_id") `) - await db.query(`CREATE INDEX "IDX_e3a1b94f40001682587d9b0a3d" ON "domain" ("last_domain_block_number") `) - await db.query(`CREATE INDEX "IDX_35b49bec8ab1e3864de09a60d6" ON "domain" ("created_at") `) - await db.query(`CREATE INDEX "IDX_c3ac554ab7a2ed97d9a0af4083" ON "domain" ("updated_at") `) + await db.query(`CREATE TABLE "withdrawal" ("id" character varying NOT NULL, "block_number" integer NOT NULL, "account_id" text NOT NULL, "domain_id" text NOT NULL, "operator_id" text NOT NULL, "nominator_id" text NOT NULL, "shares" numeric NOT NULL, "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, "extrinsic_hash" text NOT NULL, "status" character varying(8) NOT NULL, CONSTRAINT "PK_840e247aaad3fbd4e18129122a2" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_e8ac24b4a9b9657cd27289feea" ON "withdrawal" ("block_number") `) + await db.query(`CREATE INDEX "IDX_66c152572f8743fcd9ddecf2d2" ON "withdrawal" ("account_id") `) + await db.query(`CREATE INDEX "IDX_12de4d5556aa377a203cb5b1b2" ON "withdrawal" ("domain_id") `) + await db.query(`CREATE INDEX "IDX_d5f5ce8abff91d6485c4f84e57" ON "withdrawal" ("operator_id") `) + await db.query(`CREATE INDEX "IDX_09c9cf2ad9a4f3b674540dbfcf" ON "withdrawal" ("nominator_id") `) + await db.query(`CREATE INDEX "IDX_e2749aaf8ba367458c360a7c73" ON "withdrawal" ("timestamp") `) + await db.query(`CREATE INDEX "IDX_9c33f1820b02bef49172b9883f" ON "withdrawal" ("extrinsic_hash") `) + await db.query(`CREATE INDEX "IDX_4028ed4e39f5c919fc3317882b" ON "withdrawal" ("status") `) await db.query(`CREATE TABLE "operator_unlocked_funds" ("id" character varying NOT NULL, "block_number" integer NOT NULL, "nominator_account" text NOT NULL, "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, "extrinsic_hash" text NOT NULL, "amount" numeric NOT NULL, "operator_id" character varying, "nominator_id" character varying, CONSTRAINT "PK_88e0c471830b6c83ae6df8e561a" PRIMARY KEY ("id"))`) await db.query(`CREATE INDEX "IDX_c5936076e548d50542cf776289" ON "operator_unlocked_funds" ("block_number") `) await db.query(`CREATE INDEX "IDX_8d1c61c4fa2cbdf5da095a3ffd" ON "operator_unlocked_funds" ("operator_id") `) await db.query(`CREATE INDEX "IDX_2fff22e92b7b71ed2f39466e57" ON "operator_unlocked_funds" ("nominator_id") `) await db.query(`CREATE INDEX "IDX_48c8e45b0ff8c212f11e4a68df" ON "operator_unlocked_funds" ("timestamp") `) await db.query(`CREATE INDEX "IDX_f01f1314fe38bc670d2a48fe1a" ON "operator_unlocked_funds" ("extrinsic_hash") `) - await db.query(`CREATE TABLE "stats" ("id" character varying NOT NULL, "block_number" integer NOT NULL, "total_domains" integer NOT NULL, "total_operators" integer NOT NULL, "total_nominators" integer NOT NULL, "total_active_operators" integer NOT NULL, "total_slashed_operators" integer NOT NULL, "total_staked" numeric NOT NULL, "total_fees" numeric NOT NULL, "total_deposits" numeric NOT NULL, "total_withdrawals" numeric NOT NULL, "all_time_high_staked" numeric NOT NULL, "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, CONSTRAINT "PK_c76e93dfef28ba9b6942f578ab1" PRIMARY KEY ("id"))`) + await db.query(`CREATE TABLE "operator_reward_event" ("id" character varying NOT NULL, "domain_id" text NOT NULL, "operator_id" text NOT NULL, "amount" numeric NOT NULL, "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, "block_number" integer NOT NULL, "extrinsic_hash" text NOT NULL, CONSTRAINT "PK_721a9f907ad1f01a5abed1f2e8e" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_bf9ca379132cf6ba98f9073986" ON "operator_reward_event" ("domain_id") `) + await db.query(`CREATE INDEX "IDX_b9cf23c6256a9fc7e01a271376" ON "operator_reward_event" ("operator_id") `) + await db.query(`CREATE INDEX "IDX_2b8b8fd9152da4d7ba4b71080c" ON "operator_reward_event" ("timestamp") `) + await db.query(`CREATE INDEX "IDX_d878c755d920f1be253bad97dd" ON "operator_reward_event" ("block_number") `) + await db.query(`CREATE INDEX "IDX_83b9c467963de152d3e83dcf58" ON "operator_reward_event" ("extrinsic_hash") `) + await db.query(`CREATE TABLE "stats" ("id" character varying NOT NULL, "block_number" integer NOT NULL, "total_staked" numeric NOT NULL, "total_fees" numeric NOT NULL, "total_deposits" numeric NOT NULL, "total_withdrawals" numeric NOT NULL, "all_time_high_staked" numeric NOT NULL, "domains_count" integer NOT NULL, "operators_count" integer NOT NULL, "active_operators_count" integer NOT NULL, "slashed_operators_count" integer NOT NULL, "nominators_count" integer NOT NULL, "deposits_count" integer NOT NULL, "withdrawals_count" integer NOT NULL, "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, CONSTRAINT "PK_c76e93dfef28ba9b6942f578ab1" PRIMARY KEY ("id"))`) await db.query(`CREATE INDEX "IDX_0b3890ae3ba62ee77fe94af26e" ON "stats" ("block_number") `) await db.query(`CREATE INDEX "IDX_ea4b2bcf5920a1b06f4454bb91" ON "stats" ("timestamp") `) - await db.query(`CREATE TABLE "stats_per_domain" ("id" character varying NOT NULL, "domain_id" integer NOT NULL, "block_number" integer NOT NULL, "total_operators" integer NOT NULL, "total_nominators" integer NOT NULL, "total_active_operators" integer NOT NULL, "total_slashed_operators" integer NOT NULL, "total_staked" numeric NOT NULL, "total_fees" numeric NOT NULL, "total_deposits" numeric NOT NULL, "total_withdrawals" numeric NOT NULL, "all_time_high_staked" numeric NOT NULL, "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, CONSTRAINT "PK_0edbe67267dbe09a2a691517eee" PRIMARY KEY ("id"))`) + await db.query(`CREATE TABLE "stats_per_domain" ("id" character varying NOT NULL, "domain_id" text NOT NULL, "block_number" integer NOT NULL, "total_staked" numeric NOT NULL, "total_fees" numeric NOT NULL, "total_deposits" numeric NOT NULL, "total_withdrawals" numeric NOT NULL, "all_time_high_staked" numeric NOT NULL, "operators_count" integer NOT NULL, "active_operators_count" integer NOT NULL, "slashed_operators_count" integer NOT NULL, "nominators_count" integer NOT NULL, "deposits_count" integer NOT NULL, "withdrawals_count" integer NOT NULL, "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, CONSTRAINT "PK_0edbe67267dbe09a2a691517eee" PRIMARY KEY ("id"))`) await db.query(`CREATE INDEX "IDX_3ac1b575a2dd3f64faedbde14b" ON "stats_per_domain" ("domain_id") `) await db.query(`CREATE INDEX "IDX_77118ccf015e661215115daaa5" ON "stats_per_domain" ("block_number") `) await db.query(`CREATE INDEX "IDX_8eb7279e3beeab2964a533cd52" ON "stats_per_domain" ("timestamp") `) - await db.query(`CREATE TABLE "stats_per_operator" ("id" character varying NOT NULL, "domain_id" integer NOT NULL, "operator_id" integer NOT NULL, "block_number" integer NOT NULL, "total_nominators" integer NOT NULL, "total_staked" numeric NOT NULL, "total_fees" numeric NOT NULL, "total_deposits" numeric NOT NULL, "total_withdrawals" numeric NOT NULL, "all_time_high_staked" numeric NOT NULL, "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, CONSTRAINT "PK_8cff6fe09e3e5510f0c90e42cf5" PRIMARY KEY ("id"))`) + await db.query(`CREATE TABLE "stats_per_operator" ("id" character varying NOT NULL, "domain_id" text NOT NULL, "operator_id" text NOT NULL, "block_number" integer NOT NULL, "total_staked" numeric NOT NULL, "total_fees" numeric NOT NULL, "total_deposits" numeric NOT NULL, "total_withdrawals" numeric NOT NULL, "all_time_high_staked" numeric NOT NULL, "nominators_count" integer NOT NULL, "deposits_count" integer NOT NULL, "withdrawals_count" integer NOT NULL, "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, CONSTRAINT "PK_8cff6fe09e3e5510f0c90e42cf5" PRIMARY KEY ("id"))`) await db.query(`CREATE INDEX "IDX_4a4bff6af8198a2f145ecf637f" ON "stats_per_operator" ("domain_id") `) await db.query(`CREATE INDEX "IDX_466db26acddfccae0a5d487d2c" ON "stats_per_operator" ("operator_id") `) await db.query(`CREATE INDEX "IDX_5ff9cc7e82a620057ef84c3826" ON "stats_per_operator" ("block_number") `) await db.query(`CREATE INDEX "IDX_3260a5fceb17a3d817e5678d7f" ON "stats_per_operator" ("timestamp") `) - await db.query(`ALTER TABLE "withdrawal" ADD CONSTRAINT "FK_d5f5ce8abff91d6485c4f84e574" FOREIGN KEY ("operator_id") REFERENCES "operator"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`) - await db.query(`ALTER TABLE "withdrawal" ADD CONSTRAINT "FK_09c9cf2ad9a4f3b674540dbfcf0" FOREIGN KEY ("nominator_id") REFERENCES "nominator"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`) - await db.query(`ALTER TABLE "nominator" ADD CONSTRAINT "FK_14374f281ccb6e72c55dab3c209" FOREIGN KEY ("operator_id") REFERENCES "operator"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`) - await db.query(`ALTER TABLE "deposit" ADD CONSTRAINT "FK_c2f2cfaa2b294c75d38a57e380a" FOREIGN KEY ("operator_id") REFERENCES "operator"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`) - await db.query(`ALTER TABLE "deposit" ADD CONSTRAINT "FK_b673efd4ec207b203e4d06abe9c" FOREIGN KEY ("nominator_id") REFERENCES "nominator"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`) - await db.query(`ALTER TABLE "operator_reward_event" ADD CONSTRAINT "FK_b9cf23c6256a9fc7e01a2713761" FOREIGN KEY ("operator_id") REFERENCES "operator"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`) - await db.query(`ALTER TABLE "operator_fees_earned" ADD CONSTRAINT "FK_c9dda7e56175bc755c449c5e02f" FOREIGN KEY ("operator_id") REFERENCES "operator"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`) - await db.query(`ALTER TABLE "domain" ADD CONSTRAINT "FK_555eee0485a3e1937915a26e6b2" FOREIGN KEY ("last_operator_bundle_produced_id") REFERENCES "operator"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`) await db.query(`ALTER TABLE "operator_unlocked_funds" ADD CONSTRAINT "FK_8d1c61c4fa2cbdf5da095a3ffd0" FOREIGN KEY ("operator_id") REFERENCES "operator"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`) await db.query(`ALTER TABLE "operator_unlocked_funds" ADD CONSTRAINT "FK_2fff22e92b7b71ed2f39466e57f" FOREIGN KEY ("nominator_id") REFERENCES "nominator"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`) } async down(db) { - await db.query(`DROP TABLE "withdrawal"`) - await db.query(`DROP INDEX "public"."IDX_e8ac24b4a9b9657cd27289feea"`) - await db.query(`DROP INDEX "public"."IDX_25c7ac5a7731ac3ce7982bef67"`) - await db.query(`DROP INDEX "public"."IDX_d5f5ce8abff91d6485c4f84e57"`) - await db.query(`DROP INDEX "public"."IDX_09c9cf2ad9a4f3b674540dbfcf"`) - await db.query(`DROP INDEX "public"."IDX_e2749aaf8ba367458c360a7c73"`) - await db.query(`DROP INDEX "public"."IDX_9c33f1820b02bef49172b9883f"`) - await db.query(`DROP INDEX "public"."IDX_4028ed4e39f5c919fc3317882b"`) + await db.query(`DROP TABLE "domain"`) + await db.query(`DROP INDEX "public"."IDX_c1e90b3654ffe0a5544e502edb"`) + await db.query(`DROP INDEX "public"."IDX_80867983eb3f6e204acfea4214"`) + await db.query(`DROP INDEX "public"."IDX_e3a1b94f40001682587d9b0a3d"`) + await db.query(`DROP INDEX "public"."IDX_35b49bec8ab1e3864de09a60d6"`) + await db.query(`DROP INDEX "public"."IDX_c3ac554ab7a2ed97d9a0af4083"`) + await db.query(`DROP TABLE "account"`) + await db.query(`DROP INDEX "public"."IDX_2740156ea8742b8df1ad9d9774"`) + await db.query(`DROP INDEX "public"."IDX_8bed31488e09ed64770378600b"`) + await db.query(`DROP TABLE "operator"`) + await db.query(`DROP INDEX "public"."IDX_ed3a1bcef6df98998f07a571a7"`) + await db.query(`DROP INDEX "public"."IDX_91b197ab29ad85b5e616289ea0"`) + await db.query(`DROP INDEX "public"."IDX_1c800426a1f738c1b202ff839f"`) + await db.query(`DROP INDEX "public"."IDX_51b6c3609906ff3cd25e39e1b2"`) + await db.query(`DROP INDEX "public"."IDX_c7fd0bf382a9832cf1db87827c"`) + await db.query(`DROP INDEX "public"."IDX_d6260ed02d20cf8231ebb742d6"`) + await db.query(`DROP INDEX "public"."IDX_d6d18ca05472785030a7a3963b"`) await db.query(`DROP TABLE "nominator"`) - await db.query(`DROP INDEX "public"."IDX_ef8faa81be0a51d54fc727b9fb"`) + await db.query(`DROP INDEX "public"."IDX_917636e6d1130ea9506eaeafef"`) + await db.query(`DROP INDEX "public"."IDX_b017cafe03fa79059bd8164c4e"`) await db.query(`DROP INDEX "public"."IDX_14374f281ccb6e72c55dab3c20"`) await db.query(`DROP INDEX "public"."IDX_43aeeb4c46d83dd78aa564c1b1"`) await db.query(`DROP INDEX "public"."IDX_7093d62ba7e5a6387a686e607e"`) await db.query(`DROP INDEX "public"."IDX_9ebc942736e76bde99ee21452f"`) await db.query(`DROP TABLE "deposit"`) await db.query(`DROP INDEX "public"."IDX_230a90fc5a10c7ac5ac35397d2"`) - await db.query(`DROP INDEX "public"."IDX_f3abde1e7f8d7ca5102e376219"`) + await db.query(`DROP INDEX "public"."IDX_9ced91570695137ec1d60c1a61"`) + await db.query(`DROP INDEX "public"."IDX_8dc544cfa89fb544beea034396"`) await db.query(`DROP INDEX "public"."IDX_c2f2cfaa2b294c75d38a57e380"`) await db.query(`DROP INDEX "public"."IDX_b673efd4ec207b203e4d06abe9"`) await db.query(`DROP INDEX "public"."IDX_a37222607a86476fa124313c51"`) await db.query(`DROP INDEX "public"."IDX_b1d1dadac59ff00a27b4ef18cf"`) await db.query(`DROP INDEX "public"."IDX_6f250bd43f2f631fcb2f589200"`) - await db.query(`DROP TABLE "operator_reward_event"`) - await db.query(`DROP INDEX "public"."IDX_b9cf23c6256a9fc7e01a271376"`) - await db.query(`DROP INDEX "public"."IDX_2b8b8fd9152da4d7ba4b71080c"`) - await db.query(`DROP INDEX "public"."IDX_d878c755d920f1be253bad97dd"`) - await db.query(`DROP INDEX "public"."IDX_83b9c467963de152d3e83dcf58"`) - await db.query(`DROP TABLE "operator_fees_earned"`) - await db.query(`DROP INDEX "public"."IDX_c9dda7e56175bc755c449c5e02"`) - await db.query(`DROP TABLE "operator"`) - await db.query(`DROP INDEX "public"."IDX_1c800426a1f738c1b202ff839f"`) - await db.query(`DROP INDEX "public"."IDX_ca18369599805e0d60e4ac0652"`) - await db.query(`DROP INDEX "public"."IDX_51b6c3609906ff3cd25e39e1b2"`) - await db.query(`DROP INDEX "public"."IDX_3b141ec6a3d1225075d8c6bc21"`) - await db.query(`DROP INDEX "public"."IDX_c7fd0bf382a9832cf1db87827c"`) - await db.query(`DROP INDEX "public"."IDX_d6260ed02d20cf8231ebb742d6"`) - await db.query(`DROP INDEX "public"."IDX_d6d18ca05472785030a7a3963b"`) - await db.query(`DROP TABLE "domain"`) - await db.query(`DROP INDEX "public"."IDX_2bc5e1041a74e1492dfda20688"`) - await db.query(`DROP INDEX "public"."IDX_80867983eb3f6e204acfea4214"`) - await db.query(`DROP INDEX "public"."IDX_555eee0485a3e1937915a26e6b"`) - await db.query(`DROP INDEX "public"."IDX_e3a1b94f40001682587d9b0a3d"`) - await db.query(`DROP INDEX "public"."IDX_35b49bec8ab1e3864de09a60d6"`) - await db.query(`DROP INDEX "public"."IDX_c3ac554ab7a2ed97d9a0af4083"`) + await db.query(`DROP TABLE "withdrawal"`) + await db.query(`DROP INDEX "public"."IDX_e8ac24b4a9b9657cd27289feea"`) + await db.query(`DROP INDEX "public"."IDX_66c152572f8743fcd9ddecf2d2"`) + await db.query(`DROP INDEX "public"."IDX_12de4d5556aa377a203cb5b1b2"`) + await db.query(`DROP INDEX "public"."IDX_d5f5ce8abff91d6485c4f84e57"`) + await db.query(`DROP INDEX "public"."IDX_09c9cf2ad9a4f3b674540dbfcf"`) + await db.query(`DROP INDEX "public"."IDX_e2749aaf8ba367458c360a7c73"`) + await db.query(`DROP INDEX "public"."IDX_9c33f1820b02bef49172b9883f"`) + await db.query(`DROP INDEX "public"."IDX_4028ed4e39f5c919fc3317882b"`) await db.query(`DROP TABLE "operator_unlocked_funds"`) await db.query(`DROP INDEX "public"."IDX_c5936076e548d50542cf776289"`) await db.query(`DROP INDEX "public"."IDX_8d1c61c4fa2cbdf5da095a3ffd"`) await db.query(`DROP INDEX "public"."IDX_2fff22e92b7b71ed2f39466e57"`) await db.query(`DROP INDEX "public"."IDX_48c8e45b0ff8c212f11e4a68df"`) await db.query(`DROP INDEX "public"."IDX_f01f1314fe38bc670d2a48fe1a"`) + await db.query(`DROP TABLE "operator_reward_event"`) + await db.query(`DROP INDEX "public"."IDX_bf9ca379132cf6ba98f9073986"`) + await db.query(`DROP INDEX "public"."IDX_b9cf23c6256a9fc7e01a271376"`) + await db.query(`DROP INDEX "public"."IDX_2b8b8fd9152da4d7ba4b71080c"`) + await db.query(`DROP INDEX "public"."IDX_d878c755d920f1be253bad97dd"`) + await db.query(`DROP INDEX "public"."IDX_83b9c467963de152d3e83dcf58"`) await db.query(`DROP TABLE "stats"`) await db.query(`DROP INDEX "public"."IDX_0b3890ae3ba62ee77fe94af26e"`) await db.query(`DROP INDEX "public"."IDX_ea4b2bcf5920a1b06f4454bb91"`) @@ -139,14 +139,6 @@ module.exports = class Data1721778314620 { await db.query(`DROP INDEX "public"."IDX_466db26acddfccae0a5d487d2c"`) await db.query(`DROP INDEX "public"."IDX_5ff9cc7e82a620057ef84c3826"`) await db.query(`DROP INDEX "public"."IDX_3260a5fceb17a3d817e5678d7f"`) - await db.query(`ALTER TABLE "withdrawal" DROP CONSTRAINT "FK_d5f5ce8abff91d6485c4f84e574"`) - await db.query(`ALTER TABLE "withdrawal" DROP CONSTRAINT "FK_09c9cf2ad9a4f3b674540dbfcf0"`) - await db.query(`ALTER TABLE "nominator" DROP CONSTRAINT "FK_14374f281ccb6e72c55dab3c209"`) - await db.query(`ALTER TABLE "deposit" DROP CONSTRAINT "FK_c2f2cfaa2b294c75d38a57e380a"`) - await db.query(`ALTER TABLE "deposit" DROP CONSTRAINT "FK_b673efd4ec207b203e4d06abe9c"`) - await db.query(`ALTER TABLE "operator_reward_event" DROP CONSTRAINT "FK_b9cf23c6256a9fc7e01a2713761"`) - await db.query(`ALTER TABLE "operator_fees_earned" DROP CONSTRAINT "FK_c9dda7e56175bc755c449c5e02f"`) - await db.query(`ALTER TABLE "domain" DROP CONSTRAINT "FK_555eee0485a3e1937915a26e6b2"`) await db.query(`ALTER TABLE "operator_unlocked_funds" DROP CONSTRAINT "FK_8d1c61c4fa2cbdf5da095a3ffd0"`) await db.query(`ALTER TABLE "operator_unlocked_funds" DROP CONSTRAINT "FK_2fff22e92b7b71ed2f39466e57f"`) } diff --git a/indexers/staking-squid/package-lock.json b/indexers/staking-squid/package-lock.json index 8bdc0cd87..cdddb7680 100644 --- a/indexers/staking-squid/package-lock.json +++ b/indexers/staking-squid/package-lock.json @@ -6,8 +6,8 @@ "": { "name": "staking-squid", "dependencies": { - "@autonomys/auto-consensus": "^0.1.6", - "@autonomys/auto-utils": "^0.1.6", + "@autonomys/auto-consensus": "^0.2.0", + "@autonomys/auto-utils": "^0.2.0", "@subsquid/graphql-server": "^4.5.1", "@subsquid/ss58": "^2.0.2", "@subsquid/substrate-processor": "^8.3.0", @@ -182,17 +182,17 @@ } }, "node_modules/@autonomys/auto-consensus": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/@autonomys/auto-consensus/-/auto-consensus-0.1.6.tgz", - "integrity": "sha512-V65b3Vl6QBPyuqIITINZH42ebMOO9Y+Gg74EPIJxDQcaGslMBmbA2IFuKOdKJRXwfO6WQkxAIioCdMmpa6z6PA==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@autonomys/auto-consensus/-/auto-consensus-0.2.0.tgz", + "integrity": "sha512-2kfHOVOXgdhoMAcRP46J4Tk3qeuT/CHetJNtjcVPY0H3ojGPpmfaFg2jBenQqGz59TacjSjLhSouA5UlY7iDJg==", "dependencies": { - "@autonomys/auto-utils": "^0.1.6" + "@autonomys/auto-utils": "^0.2.0" } }, "node_modules/@autonomys/auto-utils": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/@autonomys/auto-utils/-/auto-utils-0.1.6.tgz", - "integrity": "sha512-fCU6kjlzYsMuFx9l32GkwmzHRmUlQS2YIBbKDDohNQyixtCc7UEJSftgIhHlpXilTeZSetvVFingg/vbyChRJQ==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@autonomys/auto-utils/-/auto-utils-0.2.0.tgz", + "integrity": "sha512-uu4OxTWXGQk09HxmQsJQTmrcKAqwdTdGQy/zUloVm5/IAYPKmI1ttSPI/5BSUxeoKsBd69XFfb3wqtYfO5/ytw==", "dependencies": { "@polkadot/api": "^11.2.1", "@polkadot/extension-dapp": "^0.47.5", @@ -1586,9 +1586,9 @@ "optional": true }, "node_modules/@substrate/connect-known-chains": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/@substrate/connect-known-chains/-/connect-known-chains-1.1.11.tgz", - "integrity": "sha512-jl6RKTn9bDezKqlOj2X9B/BVftIqqnU9tgr/9WXMCBdLedzQaO/DRRb0c5VqF1+DH8dHV2q5MyKN9gR+KGt7ow==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@substrate/connect-known-chains/-/connect-known-chains-1.2.0.tgz", + "integrity": "sha512-BgcTHKteSAcEQs5ySNTYOO6ODQHVHwPgDrjYQhL0r8ZygY4cyXa5e2O//3tXNJiDopFHdqO8FBAy2Gbht0i0PA==", "optional": true }, "node_modules/@substrate/light-client-extension-helpers": { @@ -3785,9 +3785,9 @@ } }, "node_modules/nock/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "dependencies": { "ms": "2.1.2" }, diff --git a/indexers/staking-squid/package.json b/indexers/staking-squid/package.json index 6b4288298..d5f58b42c 100644 --- a/indexers/staking-squid/package.json +++ b/indexers/staking-squid/package.json @@ -5,7 +5,8 @@ "node": ">=16" }, "scripts": { - "build": "rm -rf lib && tsc" + "build": "rm -rf lib && tsc", + "deploy": "sqd deploy --org autonomys-labs ." }, "repository": { "type": "git", @@ -13,11 +14,11 @@ }, "author": { "name": "Autonomys", - "url": "https://www.autonomys.net" + "url": "https://www.autonomys.xyz" }, "dependencies": { - "@autonomys/auto-consensus": "^0.1.6", - "@autonomys/auto-utils": "^0.1.6", + "@autonomys/auto-consensus": "^0.2.0", + "@autonomys/auto-utils": "^0.2.0", "@subsquid/graphql-server": "^4.5.1", "@subsquid/ss58": "^2.0.2", "@subsquid/substrate-processor": "^8.3.0", diff --git a/indexers/staking-squid/schema.graphql b/indexers/staking-squid/schema.graphql index 62f248e30..3600d8cc8 100644 --- a/indexers/staking-squid/schema.graphql +++ b/indexers/staking-squid/schema.graphql @@ -1,9 +1,21 @@ type Domain @entity { id: ID! @index - domainId: Int! @index + sortId: Int! @index completedEpoch: Int! @index - lastOperatorBundleProduced: Operator! lastDomainBlockNumber: Int! @index + totalDeposits: BigInt! + totalTaxCollected: BigInt! + totalRewardsCollected: BigInt! + currentTotalStake: BigInt! + currentStorageFeeDeposit: BigInt! + createdAt: Int @index + updatedAt: Int @index +} + +type Account @entity { + id: ID! @index + totalDeposits: BigInt! + totalTaxCollected: BigInt! createdAt: Int @index updatedAt: Int @index } @@ -12,15 +24,16 @@ enum OperatorStatus { PENDING REGISTERED DEREGISTERED + READY_TO_UNLOCK SLASHED } type Operator @entity { id: ID! @index - domainId: Int! @index - operatorId: Int! @index + sortId: Int! @index + accountId: String! @index + domainId: String! @index signingKey: String! @index - owner: String! @index minimumNominatorStake: BigInt! nominationTax: Int! currentTotalStake: BigInt! @@ -29,26 +42,9 @@ type Operator @entity { currentTotalShares: BigInt! totalDeposits: BigInt! totalTaxCollected: BigInt! - deposits: [Deposit!]! - @derivedFrom(field: "operator") - @cardinality(value: 1000000000) - nominators: [Nominator!]! - @derivedFrom(field: "operator") - @cardinality(value: 1000000000) - withdrawals: [Withdrawal!]! - @derivedFrom(field: "operator") - @cardinality(value: 1000000000) - operatorRewards: [OperatorRewardEvent!]! - @derivedFrom(field: "operator") - @cardinality(value: 1000000000) - operatorFees: [OperatorFeesEarned!]! - @derivedFrom(field: "operator") - @cardinality(value: 1000000000) + totalRewardsCollected: BigInt! rawStatus: String status: OperatorStatus! @index - nominatorsCount: Int! - depositsCount: Int! - withdrawalsCount: Int! bundleCount: Int! lastBundleAt: Int! createdAt: Int @index @@ -64,18 +60,11 @@ enum NominatorStatus { type Nominator @entity { id: ID! @index - account: String! @index - operator: Operator! + accountId: String! @index + domainId: String! @index + operatorId: String! @index shares: BigInt! - deposits: [Deposit!]! - @derivedFrom(field: "nominator") - @cardinality(value: 1000000000) - withdrawals: [Withdrawal!]! - @derivedFrom(field: "nominator") - @cardinality(value: 1000000000) totalDeposits: BigInt! - depositsCount: Int! - withdrawalsCount: Int! status: NominatorStatus! @index createdAt: Int @index updatedAt: Int @index @@ -89,11 +78,12 @@ enum DepositStatus { type Deposit @entity { id: ID! @index blockNumber: Int! @index - account: String! @index + accountId: String! @index + domainId: String! @index + operatorId: String! @index + nominatorId: String! @index amount: BigInt! storageFeeDeposit: BigInt! - operator: Operator! - nominator: Nominator! timestamp: DateTime! @index extrinsicHash: String! @index status: DepositStatus! @index @@ -108,10 +98,11 @@ enum WithdrawalStatus { type Withdrawal @entity { id: ID! @index blockNumber: Int! @index - account: String! @index + accountId: String! @index + domainId: String! @index + operatorId: String! @index + nominatorId: String! @index shares: BigInt! - operator: Operator! - nominator: Nominator! timestamp: DateTime! @index extrinsicHash: String! @index status: WithdrawalStatus! @index @@ -130,62 +121,62 @@ type OperatorUnlockedFunds @entity { type OperatorRewardEvent @entity { id: ID! @index - operator: Operator! + domainId: String! @index + operatorId: String! @index + amount: BigInt! timestamp: DateTime! @index blockNumber: Int! @index extrinsicHash: String! @index - amount: BigInt! -} - -type OperatorFeesEarned @entity { - id: ID! @index - operator: Operator! - amount: BigInt! - updatedAt: Int! } type Stats @entity { id: ID! @index blockNumber: Int! @index - totalDomains: Int! - totalOperators: Int! - totalNominators: Int! - totalActiveOperators: Int! - totalSlashedOperators: Int! totalStaked: BigInt! totalFees: BigInt! totalDeposits: BigInt! totalWithdrawals: BigInt! allTimeHighStaked: BigInt! + domainsCount: Int! + operatorsCount: Int! + activeOperatorsCount: Int! + slashedOperatorsCount: Int! + nominatorsCount: Int! + depositsCount: Int! + withdrawalsCount: Int! timestamp: DateTime! @index } type StatsPerDomain @entity { id: ID! @index - domainId: Int! @index + domainId: String! @index blockNumber: Int! @index - totalOperators: Int! - totalNominators: Int! - totalActiveOperators: Int! - totalSlashedOperators: Int! totalStaked: BigInt! totalFees: BigInt! totalDeposits: BigInt! totalWithdrawals: BigInt! allTimeHighStaked: BigInt! + operatorsCount: Int! + activeOperatorsCount: Int! + slashedOperatorsCount: Int! + nominatorsCount: Int! + depositsCount: Int! + withdrawalsCount: Int! timestamp: DateTime! @index } type StatsPerOperator @entity { id: ID! @index - domainId: Int! @index - operatorId: Int! @index + domainId: String! @index + operatorId: String! @index blockNumber: Int! @index - totalNominators: Int! totalStaked: BigInt! totalFees: BigInt! totalDeposits: BigInt! totalWithdrawals: BigInt! allTimeHighStaked: BigInt! + nominatorsCount: Int! + depositsCount: Int! + withdrawalsCount: Int! timestamp: DateTime! @index } diff --git a/indexers/staking-squid/squid.yaml b/indexers/staking-squid/squid.yaml index 582060d4b..05d778221 100644 --- a/indexers/staking-squid/squid.yaml +++ b/indexers/staking-squid/squid.yaml @@ -1,11 +1,16 @@ manifestVersion: subsquid.io/v0.1 name: staking-squid -version: 1 +version: 2 description: Autonomys - Astral - Staking Indexer build: deploy: + env: + HASURA_GRAPHQL_ADMIN_SECRET: "${{ secrets.HASURA_SECRET }}" + HASURA_GRAPHQL_UNAUTHORIZED_ROLE: user + HASURA_GRAPHQL_STRINGIFY_NUMERIC_TYPES: "true" addons: postgres: + hasura: processor: cmd: - sqd @@ -17,3 +22,12 @@ deploy: cmd: - sqd - serve:prod + +scale: + dedicated: true + addons: + postgres: + storage: 100G + profile: medium + processor: + profile: medium diff --git a/indexers/staking-squid/src/blocks/index.ts b/indexers/staking-squid/src/blocks/index.ts index 0771b2e8c..905ae6c1b 100644 --- a/indexers/staking-squid/src/blocks/index.ts +++ b/indexers/staking-squid/src/blocks/index.ts @@ -1,22 +1,22 @@ import type { ApiPromise } from "@autonomys/auto-utils"; -import type { ApiDecoration } from "@polkadot/api/types"; -import type { Store } from "@subsquid/typeorm-store"; +import { Store } from "@subsquid/typeorm-store"; import { processExtrinsics } from "../extrinsics"; import type { Ctx, CtxBlock } from "../processor"; import { getBlockNumber } from "../utils"; +import { Cache, load, save } from "../utils/cache"; export async function processBlocks(ctx: Ctx, api: ApiPromise) { + let cache: Cache = await load(ctx); + console.log("Processing " + ctx.blocks.length + " blocks"); for (let block of ctx.blocks) { - const apiAt = await api.at(block.header.hash); - await processBlock(ctx, apiAt, block); + cache = await processBlock(cache, api, block); + + ctx.log.child("completed block").info(getBlockNumber(block).toString()); + + await save(ctx, cache); } } -async function processBlock( - ctx: Ctx, - apiAt: ApiDecoration<"promise">, - block: CtxBlock -) { - await processExtrinsics(ctx, apiAt, block, block.extrinsics); - ctx.log.child(`Last block`).info(getBlockNumber(block).toString()); +async function processBlock(cache: Cache, api: ApiPromise, block: CtxBlock) { + return await processExtrinsics(cache, api, block, block.extrinsics); } diff --git a/indexers/staking-squid/src/events/bundle.ts b/indexers/staking-squid/src/events/bundle.ts index 8d2731c97..1b9877c00 100644 --- a/indexers/staking-squid/src/events/bundle.ts +++ b/indexers/staking-squid/src/events/bundle.ts @@ -1,12 +1,10 @@ -import type { ApiDecoration } from "@polkadot/api/types"; -import type { Store } from "@subsquid/typeorm-store"; -import type { Ctx, CtxBlock, CtxEvent, CtxExtrinsic } from "../processor"; +import type { CtxBlock, CtxEvent, CtxExtrinsic } from "../processor"; import { getOrCreateDomain, getOrCreateOperator } from "../storage"; import { getBlockNumber } from "../utils"; +import { Cache } from "../utils/cache"; -export async function processBundleStoredEvent( - ctx: Ctx, - apiAt: ApiDecoration<"promise">, +export function processBundleStoredEvent( + cache: Cache, block: CtxBlock, extrinsic: CtxExtrinsic, event: CtxEvent @@ -14,21 +12,22 @@ export async function processBundleStoredEvent( const domainId = Number(event.args.domainId); const operatorId = Number(event.args.bundleAuthor); const lastDomainBlockNumber = Number( - extrinsic.call?.args[0].value.sealed_header.header.receipt - .domain_block_number + extrinsic.call?.args.opaqueBundle.sealedHeader.header.receipt + .domainBlockNumber ); - const domain = await getOrCreateDomain(ctx, block, domainId); - const operator = await getOrCreateOperator(ctx, block, operatorId); + const domain = getOrCreateDomain(cache, block, domainId); + const operator = getOrCreateOperator(cache, block, operatorId); - domain.lastOperatorBundleProduced = operator; domain.lastDomainBlockNumber = lastDomainBlockNumber; domain.updatedAt = getBlockNumber(block); - await ctx.store.save(domain); + cache.domains.set(domain.id, domain); operator.bundleCount++; operator.lastBundleAt = getBlockNumber(block); operator.updatedAt = getBlockNumber(block); - await ctx.store.save(operator); + cache.operators.set(operator.id, operator); + + return cache; } diff --git a/indexers/staking-squid/src/events/domain.ts b/indexers/staking-squid/src/events/domain.ts index 8e572ba02..f0dcfd4fc 100644 --- a/indexers/staking-squid/src/events/domain.ts +++ b/indexers/staking-squid/src/events/domain.ts @@ -1,17 +1,18 @@ -import type { ApiDecoration } from "@polkadot/api/types"; -import type { Store } from "@subsquid/typeorm-store"; -import type { Ctx, CtxBlock, CtxEvent, CtxExtrinsic } from "../processor"; -import { createDomain } from "../storage"; +import type { CtxBlock, CtxEvent } from "../processor"; +import { getOrCreateDomain } from "../storage"; +import { Cache } from "../utils/cache"; -export async function processDomainInstantiatedEvent( - ctx: Ctx, - apiAt: ApiDecoration<"promise">, +export function processDomainInstantiatedEvent( + cache: Cache, block: CtxBlock, - extrinsic: CtxExtrinsic, event: CtxEvent ) { - await createDomain(ctx, block, { - domainId: Number(event.args.domainId || 0), + const domainId = Number(event.args.domainId || 0); + const domain = getOrCreateDomain(cache, block, domainId, { completedEpoch: Number(event.args.completedEpochIndex || 0), }); + + cache.domains.set(domain.id, domain); + + return cache; } diff --git a/indexers/staking-squid/src/events/epoch.ts b/indexers/staking-squid/src/events/epoch.ts index d26d019a2..0e2866ec5 100644 --- a/indexers/staking-squid/src/events/epoch.ts +++ b/indexers/staking-squid/src/events/epoch.ts @@ -1,58 +1,130 @@ -import { parseOperator } from "@autonomys/auto-consensus"; -import type { ApiDecoration } from "@polkadot/api/types"; -import type { Store } from "@subsquid/typeorm-store"; -import type { Ctx, CtxBlock, CtxEvent, CtxExtrinsic } from "../processor"; +import { operators as getOperators } from "@autonomys/auto-consensus"; +import type { ApiPromise } from "@autonomys/auto-utils"; +import { DepositStatus, NominatorStatus, OperatorStatus } from "../model"; +import type { CtxBlock, CtxEvent, CtxExtrinsic } from "../processor"; import { - createDomain, + createStats, + createStatsPerDomain, + createStatsPerOperator, getOrCreateDomain, getOrCreateOperator, } from "../storage"; import { getBlockNumber } from "../utils"; +import { Cache } from "../utils/cache"; export async function processEpochTransitionEvent( - ctx: Ctx, - apiAt: ApiDecoration<"promise">, + cache: Cache, + api: ApiPromise, block: CtxBlock, extrinsic: CtxExtrinsic, event: CtxEvent ) { const domainId = Number(event.args.domainId); - const domain = await getOrCreateDomain(ctx, block, domainId); + const domain = getOrCreateDomain(cache, block, domainId); const completedEpoch = Number(event.args.completedEpochIndex); - if (!domain) - await createDomain(ctx, block, { - domainId, - completedEpoch: Number(event.args.completedEpochIndex), - }); - else { - domain.completedEpoch = Number(event.args.completedEpochIndex); - domain.updatedAt = getBlockNumber(block); - - await ctx.store.save(domain); - } + const apiAt = await api.at(block.header.hash); - const operatorsAll = await apiAt.query.domains.operators.entries(); - const allOperators = (operatorsAll as unknown as any[]).map((o) => - parseOperator(o) + const operatorsAll = await getOperators(apiAt); + const allOperators = operatorsAll.filter( + (o) => o.operatorDetails.currentDomainId === BigInt(domainId) ); + for (const operator of allOperators) { - const op = await getOrCreateOperator( - ctx, + const op = getOrCreateOperator( + cache, block, parseInt(operator.operatorId.toString()) ); + + const rawStatus = JSON.stringify(operator.operatorDetails.status); op.currentEpochRewards = operator.operatorDetails.currentEpochRewards; op.currentTotalShares = operator.operatorDetails.currentTotalShares; op.currentTotalStake = operator.operatorDetails.currentTotalStake; op.currentStorageFeeDeposit = operator.operatorDetails.totalStorageFeeDeposit; - op.rawStatus = JSON.stringify(operator.operatorDetails.status); + op.rawStatus = rawStatus; op.updatedAt = getBlockNumber(block); - await ctx.store.save(op); + cache.operators.set(op.id, op); + + try { + const rawStatusKey = Object.keys(rawStatus); + if (rawStatusKey[0] === "deregistered") { + const unlockBlock = ( + rawStatus as unknown as { + deregistered: { unlockAtConfirmedDomainBlockNumber: number }; + } + ).deregistered.unlockAtConfirmedDomainBlockNumber; + + if (unlockBlock <= domain.lastDomainBlockNumber) { + op.status = OperatorStatus.READY_TO_UNLOCK; + cache.operators.set(op.id, op); + } + } + } catch (e) { + console.error("Error in processEpochTransitionEvent", e); + } + } + + domain.currentTotalStake = allOperators.reduce( + (acc, o) => acc + o.operatorDetails.currentTotalStake, + BigInt(0) + ); + domain.currentStorageFeeDeposit = allOperators.reduce( + (acc, o) => acc + o.operatorDetails.totalStorageFeeDeposit, + BigInt(0) + ); + + domain.completedEpoch = completedEpoch; + domain.updatedAt = getBlockNumber(block); + + cache.domains.set(domain.id, domain); + + // Switch Pending to Active + Array.from(cache.operators.values()) + .filter((o) => o.status === OperatorStatus.PENDING) + .map((o) => { + o.status = OperatorStatus.REGISTERED; + o.updatedAt = getBlockNumber(block); + cache.operators.set(o.id, o); + }); + Array.from(cache.nominators.values()) + .filter((n) => n.status === NominatorStatus.PENDING) + .map((n) => { + n.status = NominatorStatus.STAKING; + n.updatedAt = getBlockNumber(block); + cache.nominators.set(n.id, n); + }); + Array.from(cache.deposits.values()) + .filter((d) => d.status === DepositStatus.PENDING) + .map((d) => { + d.status = DepositStatus.DEPOSITED; + cache.deposits.set(d.id, d); + }); + + // Stats on epoch transition + const stats = createStats(cache, block); + cache.stats.set(stats.id, stats); + + const domains = Array.from(cache.domains.values()); + for (const domain of domains) { + const statsPerDomain = createStatsPerDomain(cache, block, domain); + cache.statsPerDomain.set(statsPerDomain.id, statsPerDomain); + + const operators = Array.from(cache.operators.values()).filter( + (o) => o.domainId === domain.id + ); + for (const operator of operators) { + const statsPerOperator = createStatsPerOperator( + cache, + block, + domain, + operator + ); + cache.statsPerOperator.set(statsPerOperator.id, statsPerOperator); + } } - ctx.log - .child(`DomainId ${domainId} - Current epoch`) - .info(completedEpoch.toString()); + + return cache; } diff --git a/indexers/staking-squid/src/events/index.ts b/indexers/staking-squid/src/events/index.ts index ed498040b..3ab496c75 100644 --- a/indexers/staking-squid/src/events/index.ts +++ b/indexers/staking-squid/src/events/index.ts @@ -1,51 +1,49 @@ -import type { ApiDecoration } from "@polkadot/api/types"; -import type { Store } from "@subsquid/typeorm-store"; -import type { ProcessorContext } from "../processor"; +import type { ApiPromise } from "@autonomys/auto-utils"; +import type { CtxBlock, CtxEvent, CtxExtrinsic } from "../processor"; import { events } from "../types"; +import { Cache } from "../utils/cache"; import { processBundleStoredEvent } from "./bundle"; import { processDomainInstantiatedEvent } from "./domain"; import { processEpochTransitionEvent } from "./epoch"; import { processOperatorNominatedEvent, + processOperatorRewardedEvent, processOperatorSlashedEvent, processOperatorTaxCollectedEvent, } from "./operator"; +import { processWithdrewStakeEvent } from "./withdraw"; export async function processEvents( - ctx: ProcessorContext, - apiAt: ApiDecoration<"promise">, - block: ProcessorContext["blocks"][0], - extrinsic: ProcessorContext["blocks"][0]["extrinsics"][0] + cache: Cache, + api: ApiPromise, + block: CtxBlock, + extrinsic: CtxExtrinsic ) { for (let event of extrinsic.events) { - await processEvent(ctx, apiAt, block, extrinsic, event); + cache = await processEvent(cache, api, block, extrinsic, event); } + return cache; } async function processEvent( - ctx: ProcessorContext, - apiAt: ApiDecoration<"promise">, - block: ProcessorContext["blocks"][0], - extrinsic: ProcessorContext["blocks"][0]["extrinsics"][0], - event: ProcessorContext["blocks"][0]["extrinsics"][0]["events"][0] + cache: Cache, + api: ApiPromise, + block: CtxBlock, + extrinsic: CtxExtrinsic, + event: CtxEvent ) { + console.log("event", event.name); switch (event.name) { // new domain case events.domains.domainInstantiated.name: - return await processDomainInstantiatedEvent( - ctx, - apiAt, - block, - extrinsic, - event - ); + return processDomainInstantiatedEvent(cache, block, event); // epoch transition case events.domains.domainEpochCompleted.name: case events.domains.forceDomainEpochTransition.name: return await processEpochTransitionEvent( - ctx, - apiAt, + cache, + api, block, extrinsic, event @@ -53,48 +51,28 @@ async function processEvent( // operator and nomination case events.domains.operatorNominated.name: - return await processOperatorNominatedEvent( - ctx, - apiAt, - block, - extrinsic, - event - ); + return processOperatorNominatedEvent(cache, block, extrinsic, event); // bundle case events.domains.bundleStored.name: - return await processBundleStoredEvent( - ctx, - apiAt, - block, - extrinsic, - event - ); + return processBundleStoredEvent(cache, block, extrinsic, event); + + // deposit and stake + case events.domains.withdrewStake.name: + return processWithdrewStakeEvent(cache, block, extrinsic, event); // rewards and slashing case events.domains.operatorRewarded.name: - break; + return processOperatorRewardedEvent(cache, block, extrinsic, event); case events.domains.operatorSlashed.name: - return await processOperatorSlashedEvent( - ctx, - apiAt, - block, - extrinsic, - event - ); + return processOperatorSlashedEvent(cache, block, extrinsic, event); // tax on fees case events.domains.operatorTaxCollected.name: - return await processOperatorTaxCollectedEvent( - ctx, - apiAt, - block, - extrinsic, - event - ); + return processOperatorTaxCollectedEvent(cache, block, extrinsic, event); default: - break; + return cache; } } diff --git a/indexers/staking-squid/src/events/operator.ts b/indexers/staking-squid/src/events/operator.ts index f6f7dd389..3e7c02868 100644 --- a/indexers/staking-squid/src/events/operator.ts +++ b/indexers/staking-squid/src/events/operator.ts @@ -1,31 +1,31 @@ -import type { ApiDecoration } from "@polkadot/api/types"; -import type { Store } from "@subsquid/typeorm-store"; -import { Nominator, NominatorStatus, OperatorStatus } from "../model"; -import type { Ctx, CtxBlock, CtxEvent, CtxExtrinsic } from "../processor"; +import { DepositStatus, NominatorStatus, OperatorStatus } from "../model"; +import type { CtxBlock, CtxEvent, CtxExtrinsic } from "../processor"; import { - getOrCreateDeposit, + createDeposit, + createOperatorRewardEvent, + getOrCreateAccount, + getOrCreateDomain, getOrCreateNominator, getOrCreateOperator, } from "../storage"; import { events } from "../types"; -import { appendOrArray, getBlockNumber } from "../utils"; +import { getBlockNumber, getCallSigner } from "../utils"; +import { Cache } from "../utils/cache"; -export async function processOperatorNominatedEvent( - ctx: Ctx, - apiAt: ApiDecoration<"promise">, +export function processOperatorNominatedEvent( + cache: Cache, block: CtxBlock, extrinsic: CtxExtrinsic, event: CtxEvent ) { + const address = getCallSigner(extrinsic.call); + const blockNumber = getBlockNumber(block); const operatorId = Number(event.args.operatorId); const storageFeeDepositedEvent = extrinsic.events.find( (e) => e.name === events.domains.storageFeeDeposited.name ); - const shares = extrinsic.call - ? BigInt(extrinsic.call.args.shares) - : BigInt(0); const amount = extrinsic.call ? BigInt(extrinsic.call.args.amount) : BigInt(0); @@ -33,85 +33,147 @@ export async function processOperatorNominatedEvent( ? BigInt(storageFeeDepositedEvent.args.amount) : BigInt(0); - const operator = await getOrCreateOperator(ctx, block, operatorId); - const nominator = await getOrCreateNominator( - ctx, - block, - extrinsic, - operator, - { - shares, - } - ); - const deposit = await getOrCreateDeposit(ctx, block, extrinsic, operator, { + const account = getOrCreateAccount(cache, block, address); + cache.accounts.set(account.id, account); + + const operator = getOrCreateOperator(cache, block, operatorId, {}); + cache.operators.set(operator.id, operator); + + const domain = getOrCreateDomain(cache, block, operator.domainId); + cache.domains.set(domain.id, domain); + + const nominator = getOrCreateNominator(cache, block, extrinsic, operatorId, { + domainId: domain.id, + accountId: account.id, + operatorId: operator.id, + }); + cache.nominators.set(nominator.id, nominator); + + const deposit = createDeposit(block, extrinsic, { + domainId: domain.id, + accountId: account.id, + operatorId: operator.id, + nominatorId: nominator.id, amount, storageFeeDeposit, }); + cache.deposits.set(deposit.id, deposit); - operator.totalDeposits += deposit.amount; + operator.totalDeposits += amount; + operator.updatedAt = blockNumber; - const operatorNominators = appendOrArray(operator.nominators, nominator); - operator.nominators = operatorNominators; - operator.nominatorsCount = operatorNominators.length; + cache.operators.set(operator.id, operator); - const operatorDeposits = appendOrArray(operator.deposits, deposit); - operator.deposits = operatorDeposits; - operator.depositsCount = operatorDeposits.length; + nominator.totalDeposits += amount; + nominator.updatedAt = blockNumber; - operator.updatedAt = getBlockNumber(block); + cache.nominators.set(nominator.id, nominator); - await ctx.store.save(operator); + domain.totalDeposits += amount; + domain.updatedAt = blockNumber; - nominator.totalDeposits += deposit.amount; + cache.domains.set(domain.id, domain); - const nominatorDeposits = appendOrArray(nominator.deposits, deposit); - nominator.deposits = nominatorDeposits; - nominator.depositsCount = nominatorDeposits.length; + account.totalDeposits += amount; + account.updatedAt = blockNumber; - nominator.updatedAt = getBlockNumber(block); + cache.accounts.set(account.id, account); - await ctx.store.save(nominator); + return cache; } -export async function processOperatorSlashedEvent( - ctx: Ctx, - apiAt: ApiDecoration<"promise">, +export function processOperatorSlashedEvent( + cache: Cache, block: CtxBlock, extrinsic: CtxExtrinsic, event: CtxEvent ) { const operatorId = Number(event.args.operatorId); - const operator = await getOrCreateOperator(ctx, block, operatorId); + const operator = getOrCreateOperator(cache, block, operatorId); operator.currentTotalStake = BigInt(0); operator.currentStorageFeeDeposit = BigInt(0); operator.status = OperatorStatus.SLASHED; operator.updatedAt = getBlockNumber(block); - await ctx.store.save(operator); + cache.operators.set(operator.id, operator); - const nominators = await ctx.store.findBy(Nominator, { operator }); - for (const nominator of nominators) { - nominator.status = NominatorStatus.SLASHED; - nominator.updatedAt = getBlockNumber(block); + Array.from(cache.nominators.values()) + .filter((n) => n.operatorId === operator.id) + .map((n) => { + n.status = NominatorStatus.SLASHED; + n.updatedAt = getBlockNumber(block); + cache.nominators.set(n.id, n); + }); - await ctx.store.save(nominator); - } + return cache; } -export async function processOperatorTaxCollectedEvent( - ctx: Ctx, - apiAt: ApiDecoration<"promise">, +export function processOperatorTaxCollectedEvent( + cache: Cache, block: CtxBlock, extrinsic: CtxExtrinsic, event: CtxEvent ) { + const blockNumber = getBlockNumber(block); const operatorId = Number(event.args.operatorId); - const operator = await getOrCreateOperator(ctx, block, operatorId); + const tax = BigInt(event.args.tax); - operator.totalTaxCollected = - operator.totalTaxCollected + BigInt(event.args.tax); - operator.updatedAt = getBlockNumber(block); + const operator = getOrCreateOperator(cache, block, operatorId); + cache.operators.set(operator.id, operator); + + const account = getOrCreateAccount(cache, block, operator.accountId); + cache.accounts.set(account.id, account); + + const domain = getOrCreateDomain(cache, block, operator.domainId); + cache.domains.set(domain.id, domain); + + operator.totalTaxCollected += tax; + operator.updatedAt = blockNumber; + + cache.operators.set(operator.id, operator); + + account.totalTaxCollected += tax; + account.updatedAt = blockNumber; + + cache.accounts.set(account.id, account); + + domain.totalTaxCollected += tax; + + domain.updatedAt = blockNumber; + + cache.domains.set(domain.id, domain); + + return cache; +} + +export function processOperatorRewardedEvent( + cache: Cache, + block: CtxBlock, + extrinsic: CtxExtrinsic, + event: CtxEvent +) { + const operatorId = Number(event.args.operatorId); + const amount = BigInt(event.args.reward); + + const operator = getOrCreateOperator(cache, block, operatorId); + const domain = getOrCreateDomain(cache, block, operator.domainId); + + operator.totalRewardsCollected += amount; + cache.operators.set(operator.id, operator); + + domain.totalRewardsCollected += amount; + cache.domains.set(domain.id, domain); + + const operatorRewardedEvent = createOperatorRewardEvent(block, extrinsic, { + operatorId: operator.id, + domainId: operator.domainId, + amount, + }); + cache.operatorRewardedEvents.set( + operatorRewardedEvent.id, + operatorRewardedEvent + ); - await ctx.store.save(operator); + return cache; } diff --git a/indexers/staking-squid/src/events/withdraw.ts b/indexers/staking-squid/src/events/withdraw.ts new file mode 100644 index 000000000..523369708 --- /dev/null +++ b/indexers/staking-squid/src/events/withdraw.ts @@ -0,0 +1,52 @@ +import type { CtxBlock, CtxEvent, CtxExtrinsic } from "../processor"; +import { + createWithdrawal, + getOrCreateAccount, + getOrCreateDomain, + getOrCreateNominator, + getOrCreateOperator, +} from "../storage"; +import { getCallSigner } from "../utils"; +import { Cache } from "../utils/cache"; + +export function processWithdrewStakeEvent( + cache: Cache, + block: CtxBlock, + extrinsic: CtxExtrinsic, + event: CtxEvent +) { + const address = getCallSigner(extrinsic.call); + const operatorId = Number(event.args.operatorId); + + const shares = extrinsic.call + ? BigInt(extrinsic.call.args.shares) + : BigInt(0); + + const account = getOrCreateAccount(cache, block, address); + cache.accounts.set(account.id, account); + + const operator = getOrCreateOperator(cache, block, operatorId, {}); + cache.operators.set(operator.id, operator); + + const domain = getOrCreateDomain(cache, block, operator.domainId); + cache.domains.set(domain.id, domain); + + const nominator = getOrCreateNominator(cache, block, extrinsic, operatorId, { + domainId: domain.id, + accountId: account.id, + operatorId: operator.id, + shares, + }); + cache.nominators.set(nominator.id, nominator); + + const withdrawal = createWithdrawal(block, extrinsic, { + domainId: domain.id, + accountId: account.id, + operatorId: operator.id, + nominatorId: nominator.id, + shares, + }); + cache.withdrawals.set(withdrawal.id, withdrawal); + + return cache; +} diff --git a/indexers/staking-squid/src/extrinsics/index.ts b/indexers/staking-squid/src/extrinsics/index.ts index 1d49ffcd8..2d57c92f3 100644 --- a/indexers/staking-squid/src/extrinsics/index.ts +++ b/indexers/staking-squid/src/extrinsics/index.ts @@ -1,47 +1,42 @@ -import type { ApiDecoration } from "@polkadot/api/types"; -import type { Store } from "@subsquid/typeorm-store"; +import type { ApiPromise } from "@autonomys/auto-utils"; import { processEvents } from "../events"; -import type { ProcessorContext } from "../processor"; +import type { CtxBlock, CtxExtrinsic } from "../processor"; import { calls } from "../types"; +import { Cache } from "../utils/cache"; import { processDeregisterOperator, processRegisterOperator } from "./operator"; export async function processExtrinsics( - ctx: ProcessorContext, - apiAt: ApiDecoration<"promise">, - block: ProcessorContext["blocks"][0], - extrinsics: ProcessorContext["blocks"][0]["extrinsics"] + cache: Cache, + api: ApiPromise, + block: CtxBlock, + extrinsics: CtxExtrinsic[] ) { for (let extrinsic of extrinsics) { - await processExtrinsic(ctx, apiAt, block, extrinsic); + cache = await processExtrinsic(cache, api, block, extrinsic); } + return cache; } export async function processExtrinsic( - ctx: ProcessorContext, - apiAt: ApiDecoration<"promise">, - block: ProcessorContext["blocks"][0], - extrinsic: ProcessorContext["blocks"][0]["extrinsics"][0] + cache: Cache, + api: ApiPromise, + block: CtxBlock, + extrinsic: CtxExtrinsic ) { + console.log("extrinsic", extrinsic.call?.name); switch (extrinsic.call?.name) { case calls.domains.registerOperator.name: - return await processRegisterOperator(ctx, apiAt, block, extrinsic); - - case calls.domains.nominateOperator.name: - break; + return processRegisterOperator(cache, block, extrinsic); case calls.domains.deregisterOperator.name: - return await processDeregisterOperator(ctx, apiAt, block, extrinsic); + return processDeregisterOperator(cache, block, extrinsic); + case calls.domains.nominateOperator.name: case calls.domains.withdrawStake.name: - break; - case calls.domains.unlockOperator.name: - break; - case calls.domains.unlockFunds.name: case calls.domains.unlockNominator.name: - break; default: - return await processEvents(ctx, apiAt, block, extrinsic); + return await processEvents(cache, api, block, extrinsic); } } diff --git a/indexers/staking-squid/src/extrinsics/operator.ts b/indexers/staking-squid/src/extrinsics/operator.ts index 5ebf8a115..d7585cdb0 100644 --- a/indexers/staking-squid/src/extrinsics/operator.ts +++ b/indexers/staking-squid/src/extrinsics/operator.ts @@ -1,23 +1,30 @@ -import type { ApiDecoration } from "@polkadot/api/types"; -import type { Store } from "@subsquid/typeorm-store"; import { OperatorStatus } from "../model"; -import type { Ctx, CtxBlock, CtxExtrinsic } from "../processor"; -import { createOperator, getOrCreateOperator } from "../storage"; +import type { CtxBlock, CtxExtrinsic } from "../processor"; +import { + createDeposit, + createNominator, + createOperator, + getOrCreateAccount, + getOrCreateDomain, + getOrCreateOperator, +} from "../storage"; import { events } from "../types"; import { getCallSigner } from "../utils"; +import { Cache } from "../utils/cache"; -export async function processRegisterOperator( - ctx: Ctx, - api: ApiDecoration<"promise">, +export function processRegisterOperator( + cache: Cache, block: CtxBlock, extrinsic: CtxExtrinsic ) { - const owner = getCallSigner(extrinsic.call); - const domainId = extrinsic.call?.args.domainId; + const address = getCallSigner(extrinsic.call); + const domainId = Number(extrinsic.call?.args.domainId); const operatorRegisteredEvent = extrinsic.events.find( (e) => e.name === events.domains.operatorRegistered.name ); + if (!operatorRegisteredEvent) return cache; + const storageFeeDepositedEvent = extrinsic.events.find( (e) => e.name === events.domains.storageFeeDeposited.name ); @@ -25,44 +32,81 @@ export async function processRegisterOperator( const operatorId = operatorRegisteredEvent ? Number(operatorRegisteredEvent.args.operatorId) : 0; + const amount = extrinsic.call + ? BigInt(extrinsic.call.args.amount) + : BigInt(0); + const storageFeeDeposit = storageFeeDepositedEvent + ? BigInt(storageFeeDepositedEvent.args.amount) + : BigInt(0); + + const domain = getOrCreateDomain(cache, block, domainId); + cache.domains.set(domain.id, domain); + + const account = getOrCreateAccount(cache, block, address); + cache.accounts.set(account.id, account); if (operatorRegisteredEvent) { - const operator = await createOperator(ctx, block, { - domainId, - operatorId, + const operator = createOperator(block, operatorId, { + domainId: domain.id, + accountId: account.id, signingKey: extrinsic.call?.args.config.signingKey, - owner, minimumNominatorStake: BigInt( extrinsic.call?.args.config.minimumNominatorStake ), nominationTax: extrinsic.call?.args.config.nominationTax, - totalDeposits: extrinsic.call - ? BigInt(extrinsic.call.args.amount) - : BigInt(0), + totalDeposits: amount, + }); + cache.operators.set(operator.id, operator); + + const nominator = createNominator(block, extrinsic, operatorId, { + domainId: domain.id, + accountId: account.id, + operatorId: operator.id, + }); + cache.nominators.set(nominator.id, nominator); + + const deposit = createDeposit(block, extrinsic, { + domainId: domain.id, + accountId: account.id, + operatorId: operator.id, + nominatorId: nominator.id, + amount, + storageFeeDeposit, }); + cache.deposits.set(deposit.id, deposit); + + domain.totalDeposits += amount; + + cache.domains.set(domain.id, domain); - await ctx.store.save(operator); + account.totalDeposits += amount; + + cache.accounts.set(account.id, account); } + + return cache; } -export async function processDeregisterOperator( - ctx: Ctx, - api: ApiDecoration<"promise">, +export function processDeregisterOperator( + cache: Cache, block: CtxBlock, extrinsic: CtxExtrinsic ) { const operatorId = Number(extrinsic.call?.args.operatorId); - const operator = await getOrCreateOperator(ctx, block, operatorId); + const operator = getOrCreateOperator(cache, block, operatorId); const operatorDeregisteredEvent = extrinsic.events.find( (e) => e.name === events.domains.operatorDeregistered.name ); + if (!operatorDeregisteredEvent) return cache; if (operatorDeregisteredEvent) { operator.currentTotalStake = BigInt(0); operator.currentStorageFeeDeposit = BigInt(0); operator.status = OperatorStatus.DEREGISTERED; - await ctx.store.save(operator); + cache.operators.set(operator.id, operator); } + + return cache; } diff --git a/indexers/staking-squid/src/main.ts b/indexers/staking-squid/src/main.ts index 91d396224..5f86bd2d4 100644 --- a/indexers/staking-squid/src/main.ts +++ b/indexers/staking-squid/src/main.ts @@ -1,13 +1,17 @@ -import { activate, ApiPromise } from "@autonomys/auto-utils"; -import { Store, TypeormDatabase } from "@subsquid/typeorm-store"; +import { createConnection } from "@autonomys/auto-utils"; +import { TypeormDatabase } from "@subsquid/typeorm-store"; +import { assertNotNull } from "@subsquid/util-internal"; import { processBlocks } from "./blocks"; -import { Ctx, processor } from "./processor"; +import { processor } from "./processor"; processor.run(new TypeormDatabase({ supportHotBlocks: true }), async (ctx) => { - const api = await activate(); - await processChain(ctx, api); + console.log("Starting processor"); + + const api = await createConnection( + assertNotNull(process.env.RPC_CONSENSUS_HTTP, "No RPC endpoint supplied") + ); + + await processBlocks(ctx, api); + await api.disconnect(); }); -async function processChain(ctx: Ctx, api: ApiPromise) { - await processBlocks(ctx, api); -} diff --git a/indexers/staking-squid/src/model/generated/index.ts b/indexers/staking-squid/src/model/generated/index.ts index a952213ac..aa6a49f6f 100644 --- a/indexers/staking-squid/src/model/generated/index.ts +++ b/indexers/staking-squid/src/model/generated/index.ts @@ -1,4 +1,5 @@ export * from "./domain.model" +export * from "./account.model" export * from "./operator.model" export * from "./_operatorStatus" export * from "./nominator.model" @@ -9,7 +10,6 @@ export * from "./withdrawal.model" export * from "./_withdrawalStatus" export * from "./operatorUnlockedFunds.model" export * from "./operatorRewardEvent.model" -export * from "./operatorFeesEarned.model" export * from "./stats.model" export * from "./statsPerDomain.model" export * from "./statsPerOperator.model" diff --git a/indexers/staking-squid/src/processor.ts b/indexers/staking-squid/src/processor.ts index 3a15f5ba4..a04b9f4ee 100644 --- a/indexers/staking-squid/src/processor.ts +++ b/indexers/staking-squid/src/processor.ts @@ -52,6 +52,9 @@ export const processor = new SubstrateBatchProcessor() events.domains.operatorDeregistered.name, events.domains.operatorNominated.name, // deposit and stake + events.domains.withdrewStake.name, + events.domains.operatorUnlocked.name, + events.domains.fundsUnlocked.name, events.domains.storageFeeDeposited.name, // bundle events.domains.bundleStored.name, diff --git a/indexers/staking-squid/src/storage/account.ts b/indexers/staking-squid/src/storage/account.ts new file mode 100644 index 000000000..4d106b156 --- /dev/null +++ b/indexers/staking-squid/src/storage/account.ts @@ -0,0 +1,31 @@ +import { Account } from "../model"; +import type { CtxBlock } from "../processor"; +import { getBlockNumber } from "../utils"; +import { Cache } from "../utils/cache"; + +export const createAccount = ( + block: CtxBlock, + address: string, + props: Partial +): Account => + new Account({ + id: address, + totalDeposits: BigInt(0), + totalTaxCollected: BigInt(0), + ...props, + createdAt: getBlockNumber(block), + updatedAt: getBlockNumber(block), + }); + +export const getOrCreateAccount = ( + cache: Cache, + block: CtxBlock, + address: string, + props: Partial = {} +): Account => { + const account = cache.accounts.get(address); + + if (!account) return createAccount(block, address, props); + + return account; +}; diff --git a/indexers/staking-squid/src/storage/deposit.ts b/indexers/staking-squid/src/storage/deposit.ts index 82a5ef40e..ac3f3098c 100644 --- a/indexers/staking-squid/src/storage/deposit.ts +++ b/indexers/staking-squid/src/storage/deposit.ts @@ -1,31 +1,16 @@ -import type { Store } from "@subsquid/typeorm-store"; import { randomUUID } from "crypto"; -import { Deposit, DepositStatus, Operator } from "../model"; -import type { Ctx, CtxBlock, CtxExtrinsic } from "../processor"; -import { getBlockNumber, getCallSigner, getTimestamp } from "../utils"; -import { getOrCreateNominator } from "./nominator"; -import { getOrCreateOperator } from "./operator"; +import { Deposit, DepositStatus } from "../model"; +import type { CtxBlock, CtxExtrinsic } from "../processor"; +import { getBlockNumber, getTimestamp } from "../utils"; +import { Cache } from "../utils/cache"; -export const createDeposit = async ( - ctx: Ctx, +export const createDeposit = ( block: CtxBlock, extrinsic: CtxExtrinsic, props: Partial -): Promise => { - if (!props.account) props.account = getCallSigner(extrinsic.call); - if (!props.operator) - props.operator = await getOrCreateOperator(ctx, block, 0); - if (!props.nominator && props.operator) - props.nominator = await getOrCreateNominator( - ctx, - block, - extrinsic, - props.operator - ); - - const deposit = new Deposit({ +): Deposit => + new Deposit({ id: randomUUID(), - account: "st", amount: BigInt(0), storageFeeDeposit: BigInt(0), status: DepositStatus.PENDING, @@ -34,32 +19,3 @@ export const createDeposit = async ( timestamp: getTimestamp(block), extrinsicHash: extrinsic.hash, }); - - await ctx.store.insert(deposit); - - const count = await ctx.store.count(Deposit); - ctx.log.child("deposits").info(`count: ${count}`); - - return deposit; -}; - -export const getOrCreateDeposit = async ( - ctx: Ctx, - block: CtxBlock, - extrinsic: CtxExtrinsic, - operator: Operator, - props: Partial = {} -): Promise => { - const account = getCallSigner(extrinsic.call); - const blockNumber = getBlockNumber(block); - const deposit = await ctx.store.findOneBy(Deposit, { account, blockNumber }); - - if (!deposit) - return await createDeposit(ctx, block, extrinsic, { - account, - operator, - ...props, - }); - - return deposit; -}; diff --git a/indexers/staking-squid/src/storage/domain.ts b/indexers/staking-squid/src/storage/domain.ts index 3f29135fc..62a148d3d 100644 --- a/indexers/staking-squid/src/storage/domain.ts +++ b/indexers/staking-squid/src/storage/domain.ts @@ -1,41 +1,39 @@ -import type { Store } from "@subsquid/typeorm-store"; -import { randomUUID } from "crypto"; import { Domain } from "../model"; -import type { Ctx, CtxBlock } from "../processor"; -import { getBlockNumber } from "../utils"; +import type { CtxBlock } from "../processor"; +import { domainUID, getBlockNumber } from "../utils"; +import { Cache } from "../utils/cache"; -export const createDomain = async ( - ctx: Ctx, +export const createDomain = ( block: CtxBlock, + domainId: number | string, props: Partial -): Promise => { - const domain = new Domain({ - id: randomUUID(), - domainId: 0, +): Domain => + new Domain({ + id: typeof domainId === "string" ? domainId : domainUID(domainId), + sortId: typeof domainId === "string" ? parseInt(domainId) : domainId, completedEpoch: 0, lastDomainBlockNumber: 0, + totalDeposits: BigInt(0), + totalTaxCollected: BigInt(0), + totalRewardsCollected: BigInt(0), + currentTotalStake: BigInt(0), + currentStorageFeeDeposit: BigInt(0), ...props, createdAt: getBlockNumber(block), updatedAt: getBlockNumber(block), }); - await ctx.store.insert(domain); - - const count = await ctx.store.count(Domain); - ctx.log.child("domains").info(`count: ${count}`); - - return domain; -}; - -export const getOrCreateDomain = async ( - ctx: Ctx, +export const getOrCreateDomain = ( + cache: Cache, block: CtxBlock, - domainId: number, + domainId: number | string, props: Partial = {} -): Promise => { - const domain = await ctx.store.findOneBy(Domain, { domainId }); +): Domain => { + const domain = cache.domains.get( + typeof domainId === "string" ? domainId : domainUID(domainId) + ); - if (!domain) return await createDomain(ctx, block, { domainId, ...props }); + if (!domain) return createDomain(block, domainId, props); return domain; }; diff --git a/indexers/staking-squid/src/storage/index.ts b/indexers/staking-squid/src/storage/index.ts index d0257dfa9..a174753a8 100644 --- a/indexers/staking-squid/src/storage/index.ts +++ b/indexers/staking-squid/src/storage/index.ts @@ -1,5 +1,7 @@ +export * from "./account"; export * from "./deposit"; export * from "./domain"; export * from "./nominator"; export * from "./operator"; +export * from "./stats"; export * from "./withdrawal"; diff --git a/indexers/staking-squid/src/storage/nominator.ts b/indexers/staking-squid/src/storage/nominator.ts index 24857b485..64fa6ea8f 100644 --- a/indexers/staking-squid/src/storage/nominator.ts +++ b/indexers/staking-squid/src/storage/nominator.ts @@ -1,59 +1,50 @@ -import type { Store } from "@subsquid/typeorm-store"; -import { randomUUID } from "crypto"; -import { Nominator, NominatorStatus, Operator } from "../model"; -import type { Ctx, CtxBlock, CtxExtrinsic } from "../processor"; -import { getBlockNumber, getCallSigner } from "../utils"; -import { getOrCreateOperator } from "./operator"; +import { Nominator, NominatorStatus } from "../model"; +import type { CtxBlock, CtxExtrinsic } from "../processor"; +import { getBlockNumber, getCallSigner, nominatorUID } from "../utils"; +import { Cache } from "../utils/cache"; -export const createNominator = async ( - ctx: Ctx, +export const createNominator = ( block: CtxBlock, extrinsic: CtxExtrinsic, + operatorId: number, props: Partial -): Promise => { - if (!props.account) props.account = getCallSigner(extrinsic.call); - if (!props.operator) - props.operator = await getOrCreateOperator(ctx, block, 0); +): Nominator => { + const address = getCallSigner(extrinsic.call); - const nominator = new Nominator({ - id: randomUUID(), - account: "st", + return new Nominator({ + id: nominatorUID(operatorId, address), shares: BigInt(0), - deposits: [], - withdrawals: [], - depositsCount: 0, - withdrawalsCount: 0, totalDeposits: BigInt(0), status: NominatorStatus.PENDING, ...props, createdAt: getBlockNumber(block), updatedAt: getBlockNumber(block), }); - - await ctx.store.insert(nominator); - - const count = await ctx.store.count(Nominator); - ctx.log.child("nominators").info(`count: ${count}`); - - return nominator; }; -export const getOrCreateNominator = async ( - ctx: Ctx, +export const getOrCreateNominator = ( + cache: Cache, block: CtxBlock, extrinsic: CtxExtrinsic, - operator: Operator, + operatorId: number | string, props: Partial = {} -): Promise => { - const account = getCallSigner(extrinsic.call); - const nominator = await ctx.store.findOneBy(Nominator, { account, operator }); +): Nominator => { + const address = getCallSigner(extrinsic.call); + const nominator = cache.nominators.get( + typeof operatorId === "string" + ? operatorId + : nominatorUID(operatorId, address) + ); if (!nominator) - return await createNominator(ctx, block, extrinsic, { - account, - operator, - ...props, - }); + return createNominator( + block, + extrinsic, + typeof operatorId === "string" ? parseInt(operatorId) : operatorId, + { + ...props, + } + ); return nominator; }; diff --git a/indexers/staking-squid/src/storage/operator.ts b/indexers/staking-squid/src/storage/operator.ts index f5a3ea349..aaec301e2 100644 --- a/indexers/staking-squid/src/storage/operator.ts +++ b/indexers/staking-squid/src/storage/operator.ts @@ -1,22 +1,18 @@ -import type { Store } from "@subsquid/typeorm-store"; import { randomUUID } from "crypto"; -import { Operator, OperatorStatus } from "../model"; -import type { Ctx, CtxBlock } from "../processor"; -import { getBlockNumber } from "../utils"; -import { getOrCreateDomain } from "./domain"; +import { Operator, OperatorRewardEvent, OperatorStatus } from "../model"; +import type { CtxBlock, CtxExtrinsic } from "../processor"; +import { getBlockNumber, getTimestamp, operatorUID } from "../utils"; +import { Cache } from "../utils/cache"; -export const createOperator = async ( - ctx: Ctx, +export const createOperator = ( block: CtxBlock, + operatorId: number | string, props: Partial -): Promise => { - if (props.domainId) await getOrCreateDomain(ctx, block, props.domainId); - - const operator = new Operator({ - id: randomUUID(), - operatorId: 0, +): Operator => + new Operator({ + id: typeof operatorId === "string" ? operatorId : operatorUID(operatorId), + sortId: typeof operatorId === "string" ? parseInt(operatorId) : operatorId, signingKey: "0x", - owner: "st", minimumNominatorStake: BigInt(0), nominationTax: 0, currentTotalStake: BigInt(0), @@ -25,16 +21,9 @@ export const createOperator = async ( currentTotalShares: BigInt(0), totalDeposits: BigInt(0), totalTaxCollected: BigInt(0), - deposits: [], - nominators: [], - withdrawals: [], - operatorRewards: [], - operatorFees: [], + totalRewardsCollected: BigInt(0), rawStatus: JSON.stringify({}), status: OperatorStatus.PENDING, - nominatorsCount: 0, - depositsCount: 0, - withdrawalsCount: 0, bundleCount: 0, lastBundleAt: 0, ...props, @@ -42,28 +31,30 @@ export const createOperator = async ( updatedAt: getBlockNumber(block), }); - await ctx.store.insert(operator); - - const count = await ctx.store.count(Operator); - ctx.log.child("operators").info(`count: ${count}`); - - return operator; -}; - -export const getOrCreateOperator = async ( - ctx: Ctx, +export const getOrCreateOperator = ( + cache: Cache, block: CtxBlock, - operatorId: number, + operatorId: number | string, props: Partial = {} -): Promise => { - const operator = await ctx.store.findOneBy(Operator, { operatorId }); +): Operator => { + const operator = cache.operators.get( + typeof operatorId === "string" ? operatorId : operatorUID(operatorId) + ); - if (!operator) - return await createOperator(ctx, block, { - domainId: 0, - operatorId, - ...props, - }); + if (!operator) return createOperator(block, operatorId, props); return operator; }; + +export const createOperatorRewardEvent = ( + block: CtxBlock, + extrinsic: CtxExtrinsic, + props: Partial +): OperatorRewardEvent => + new OperatorRewardEvent({ + id: randomUUID(), + ...props, + blockNumber: getBlockNumber(block), + timestamp: getTimestamp(block), + extrinsicHash: extrinsic.hash.toString(), + }); diff --git a/indexers/staking-squid/src/storage/stats.ts b/indexers/staking-squid/src/storage/stats.ts new file mode 100644 index 000000000..af77f09b4 --- /dev/null +++ b/indexers/staking-squid/src/storage/stats.ts @@ -0,0 +1,125 @@ +import { randomUUID } from "crypto"; +import { + Domain, + Operator, + OperatorStatus, + Stats, + StatsPerDomain, + StatsPerOperator, +} from "../model"; +import type { CtxBlock } from "../processor"; +import { getBlockNumber, getTimestamp } from "../utils"; +import { Cache } from "../utils/cache"; + +export const createStatsPerOperator = ( + cache: Cache, + block: CtxBlock, + domain: Domain, + operator: Operator +): StatsPerOperator => { + const nominators = Array.from(cache.nominators.values()).filter( + (o) => o.domainId === domain.id + ); + const deposits = Array.from(cache.deposits.values()).filter( + (o) => o.domainId === domain.id + ); + const withdrawals = Array.from(cache.withdrawals.values()).filter( + (o) => o.domainId === domain.id + ); + return new StatsPerOperator({ + id: randomUUID(), + domainId: domain.id, + operatorId: operator.id, + totalStaked: operator.currentTotalStake, + totalFees: BigInt(0), + totalDeposits: operator.totalDeposits, + totalWithdrawals: BigInt(0), + allTimeHighStaked: BigInt(0), + nominatorsCount: nominators.length, + depositsCount: deposits.length, + withdrawalsCount: withdrawals.length, + blockNumber: getBlockNumber(block), + timestamp: getTimestamp(block), + }); +}; + +export const createStatsPerDomain = ( + cache: Cache, + block: CtxBlock, + domain: Domain +): StatsPerDomain => { + const operators = Array.from(cache.operators.values()).filter( + (o) => o.domainId === domain.id + ); + const nominators = Array.from(cache.nominators.values()).filter( + (o) => o.domainId === domain.id + ); + const deposits = Array.from(cache.deposits.values()).filter( + (o) => o.domainId === domain.id + ); + const withdrawals = Array.from(cache.withdrawals.values()).filter( + (o) => o.domainId === domain.id + ); + const activeOperatorsCount = operators.filter( + (operator) => operator.status === OperatorStatus.REGISTERED + ).length; + const slashedOperatorsCount = operators.filter( + (operator) => operator.status === OperatorStatus.SLASHED + ).length; + + return new StatsPerDomain({ + id: randomUUID(), + domainId: domain.id, + totalStaked: domain.currentTotalStake, + totalFees: BigInt(0), + totalDeposits: domain.totalDeposits, + totalWithdrawals: BigInt(0), + allTimeHighStaked: BigInt(0), + operatorsCount: operators.length, + activeOperatorsCount, + slashedOperatorsCount, + nominatorsCount: nominators.length, + depositsCount: deposits.length, + withdrawalsCount: withdrawals.length, + blockNumber: getBlockNumber(block), + timestamp: getTimestamp(block), + }); +}; + +export const createStats = (cache: Cache, block: CtxBlock): Stats => { + const operators = Array.from(cache.operators.values()); + + const activeOperatorsCount = operators.filter( + (operator) => operator.status === OperatorStatus.REGISTERED + ).length; + const slashedOperatorsCount = operators.filter( + (operator) => operator.status === OperatorStatus.SLASHED + ).length; + + const totalStaked = operators.reduce( + (total, operator) => total + operator.currentTotalStake, + BigInt(0) + ); + const totalDeposits = operators.reduce( + (total, operator) => total + operator.totalDeposits, + BigInt(0) + ); + + return new Stats({ + id: randomUUID(), + totalStaked, + totalFees: BigInt(0), + totalDeposits, + totalWithdrawals: BigInt(0), + allTimeHighStaked: BigInt(0), + domainsCount: cache.domains.size, + operatorsCount: operators.length, + activeOperatorsCount, + slashedOperatorsCount, + nominatorsCount: cache.nominators.size, + depositsCount: cache.deposits.size, + withdrawalsCount: cache.withdrawals.size, + blockNumber: getBlockNumber(block), + timestamp: getTimestamp(block), + }); +}; diff --git a/indexers/staking-squid/src/storage/withdrawal.ts b/indexers/staking-squid/src/storage/withdrawal.ts index 6d873abc6..c8f06d13b 100644 --- a/indexers/staking-squid/src/storage/withdrawal.ts +++ b/indexers/staking-squid/src/storage/withdrawal.ts @@ -1,31 +1,16 @@ -import type { Store } from "@subsquid/typeorm-store"; import { randomUUID } from "crypto"; -import { Operator, Withdrawal, WithdrawalStatus } from "../model"; -import type { Ctx, CtxBlock, CtxExtrinsic } from "../processor"; -import { getBlockNumber, getCallSigner, getTimestamp } from "../utils"; -import { getOrCreateNominator } from "./nominator"; -import { getOrCreateOperator } from "./operator"; +import { Withdrawal, WithdrawalStatus } from "../model"; +import type { CtxBlock, CtxExtrinsic } from "../processor"; +import { getBlockNumber, getTimestamp } from "../utils"; +import { Cache } from "../utils/cache"; -export const createWithdrawal = async ( - ctx: Ctx, +export const createWithdrawal = ( block: CtxBlock, extrinsic: CtxExtrinsic, props: Partial -): Promise => { - if (!props.account) props.account = getCallSigner(extrinsic.call); - if (!props.operator) - props.operator = await getOrCreateOperator(ctx, block, 0); - if (!props.nominator && props.operator) - props.nominator = await getOrCreateNominator( - ctx, - block, - extrinsic, - props.operator - ); - - const withdrawal = new Withdrawal({ +): Withdrawal => + new Withdrawal({ id: randomUUID(), - account: "st", shares: BigInt(0), status: WithdrawalStatus.PENDING, ...props, @@ -33,35 +18,3 @@ export const createWithdrawal = async ( timestamp: getTimestamp(block), extrinsicHash: extrinsic.hash, }); - - await ctx.store.insert(withdrawal); - - const count = await ctx.store.count(Withdrawal); - ctx.log.child("withdrawals").info(`count: ${count}`); - - return withdrawal; -}; - -export const getOrCreateWithdrawal = async ( - ctx: Ctx, - block: CtxBlock, - extrinsic: CtxExtrinsic, - operator: Operator, - props: Partial = {} -): Promise => { - const account = getCallSigner(extrinsic.call); - const blockNumber = getBlockNumber(block); - const withdrawal = await ctx.store.findOneBy(Withdrawal, { - account, - blockNumber, - }); - - if (!withdrawal) - return await createWithdrawal(ctx, block, extrinsic, { - account, - operator, - ...props, - }); - - return withdrawal; -}; diff --git a/indexers/staking-squid/src/utils/cache.ts b/indexers/staking-squid/src/utils/cache.ts new file mode 100644 index 000000000..8dcd7dbd3 --- /dev/null +++ b/indexers/staking-squid/src/utils/cache.ts @@ -0,0 +1,78 @@ +import type { Store } from "@subsquid/typeorm-store"; +import { + Account, + Deposit, + Domain, + Nominator, + Operator, + OperatorRewardEvent, + Stats, + StatsPerDomain, + StatsPerOperator, + Withdrawal, +} from "../model"; +import type { Ctx } from "../processor"; + +export type Cache = { + domains: Map; + accounts: Map; + operators: Map; + nominators: Map; + deposits: Map; + withdrawals: Map; + + operatorRewardedEvents: Map; + + stats: Map; + statsPerDomain: Map; + statsPerOperator: Map; +}; + +export const initCache: Cache = { + domains: new Map(), + accounts: new Map(), + operators: new Map(), + nominators: new Map(), + deposits: new Map(), + withdrawals: new Map(), + + operatorRewardedEvents: new Map(), + + stats: new Map(), + statsPerDomain: new Map(), + statsPerOperator: new Map(), +}; + +export const load = async (ctx: Ctx): Promise => { + const domains = await ctx.store.find(Domain); + const accounts = await ctx.store.find(Account); + const operators = await ctx.store.find(Operator); + const nominators = await ctx.store.find(Nominator); + const deposits = await ctx.store.find(Deposit); + const withdrawals = await ctx.store.find(Withdrawal); + + return { + ...initCache, + domains: new Map(domains.map((d) => [d.id, d])), + accounts: new Map(accounts.map((a) => [a.id, a])), + operators: new Map(operators.map((o) => [o.id, o])), + nominators: new Map(nominators.map((n) => [n.id, n])), + deposits: new Map(deposits.map((d) => [d.id, d])), + withdrawals: new Map(withdrawals.map((w) => [w.id, w])), + }; +}; + +export const save = async (ctx: Ctx, cache: Cache) => { + await ctx.store.save(Array.from(cache.domains.values())); + await ctx.store.save(Array.from(cache.accounts.values())); + await ctx.store.save(Array.from(cache.operators.values())); + await ctx.store.save(Array.from(cache.nominators.values())); + await ctx.store.save(Array.from(cache.deposits.values())); + await ctx.store.save(Array.from(cache.withdrawals.values())); + + await ctx.store.save(Array.from(cache.operatorRewardedEvents.values())); + + await ctx.store.save(Array.from(cache.stats.values())); + await ctx.store.save(Array.from(cache.statsPerDomain.values())); + await ctx.store.save(Array.from(cache.statsPerOperator.values())); +}; diff --git a/indexers/staking-squid/src/utils/index.ts b/indexers/staking-squid/src/utils/index.ts index 9727b5ff6..d4babbeca 100644 --- a/indexers/staking-squid/src/utils/index.ts +++ b/indexers/staking-squid/src/utils/index.ts @@ -17,3 +17,10 @@ export const getBlockNumber = (block: CtxBlock): number => block.header.height; export const getTimestamp = (block: CtxBlock): Date => new Date(block.header.timestamp || 0); + +export const domainUID = (domainId: number): string => `${domainId}`; + +export const operatorUID = (operatorId: number): string => `${operatorId}`; + +export const nominatorUID = (operatorId: number, account: string): string => + `${operatorId}-${account}`;