From 5bae28cb20b8b8b20744b03fc7d02c4b6073b267 Mon Sep 17 00:00:00 2001 From: kingsleydon <10992364+kingsleydon@users.noreply.github.com> Date: Wed, 21 Feb 2024 23:22:39 +0800 Subject: [PATCH] refactor --- .github/ISSUE_TEMPLATE/bug_report.md | 45 --- .vscode/settings.json | 1 + Dockerfile | 2 +- ...73517919-Data.js => 1708547433185-Data.js} | 60 ++-- .../3000000.json | 0 package.json | 2 +- patches/@subsquid+big-decimal+1.0.0.patch | 14 + schema.graphql | 37 ++- src/constants.ts | 2 +- src/decodeEvents.ts | 4 +- src/helper/account.ts | 21 ++ src/{utils => helper}/basePool.ts | 68 +++-- src/{utils => helper}/delegation.ts | 10 +- src/{utils => helper}/globalState.ts | 17 +- src/{utils => helper}/identity.ts | 4 +- src/{utils => helper}/postUpdate.ts | 131 ++------ src/helper/snapshot.ts | 213 +++++++++++++ src/{utils => helper}/worker.ts | 10 +- src/{importDump.ts => loadInitialState.ts} | 116 ++++---- src/main.ts | 281 +++++++++--------- src/model/generated/accountSnapshot.model.ts | 7 +- src/model/generated/basePoolSnapshot.model.ts | 10 +- src/model/generated/delegation.model.ts | 6 +- .../generated/delegationSnapshot.model.ts | 7 +- src/model/generated/session.model.ts | 18 +- src/model/generated/worker.model.ts | 8 - src/model/generated/workerSnapshot.model.ts | 43 ++- src/processor.ts | 4 +- src/{utils/converter.ts => utils.ts} | 28 +- src/utils/common.ts | 45 --- src/utils/snapshot.ts | 129 -------- 31 files changed, 642 insertions(+), 701 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/bug_report.md rename db/migrations/{1708273517919-Data.js => 1708547433185-Data.js} (73%) rename dump_3000000.json => initial_state/3000000.json (100%) create mode 100644 patches/@subsquid+big-decimal+1.0.0.patch create mode 100644 src/helper/account.ts rename src/{utils => helper}/basePool.ts (74%) rename src/{utils => helper}/delegation.ts (80%) rename src/{utils => helper}/globalState.ts (70%) rename src/{utils => helper}/identity.ts (94%) rename src/{utils => helper}/postUpdate.ts (58%) create mode 100644 src/helper/snapshot.ts rename src/{utils => helper}/worker.ts (84%) rename src/{importDump.ts => loadInitialState.ts} (85%) rename src/{utils/converter.ts => utils.ts} (52%) delete mode 100644 src/utils/common.ts delete mode 100644 src/utils/snapshot.ts diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index bf3db9c..0000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: '' -labels: '' -assignees: '' - ---- - -**Describe the bug** -A clear and concise description of what the bug is. - -**To Reproduce** -Steps to reproduce the behavior: -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Screenshots** -If applicable, add screenshots to help explain your problem. - -**Environment (please complete the following information):** - - specify the version of the core packages (@subsquid/cli, @subsquid/substrate-processor, ...) - - node.js version - - npm version - - OS version - - Reproducible example or a repo link - -**Applicable to decoding issues:** - - chain name - - typesBundle (if it's not built-in) -optional: - - block - - extrinsic - - call - - event - - spec version - - endpoint - -**Additional context** -Add any other context about the problem here. diff --git a/.vscode/settings.json b/.vscode/settings.json index f048c52..c26959d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -14,6 +14,7 @@ "cSpell.words": [ "biomejs", "codegen", + "judgements", "khala", "phala", "poolv2", diff --git a/Dockerfile b/Dockerfile index bb23b50..78f53bd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -33,8 +33,8 @@ FROM base AS release COPY --from=install /temp/prod/node_modules node_modules COPY --from=prerelease /usr/src/app/db db COPY --from=prerelease /usr/src/app/lib lib +COPY --from=prerelease /usr/src/app/initial_state initial_state COPY --from=prerelease /usr/src/app/schema.graphql . -COPY --from=prerelease /usr/src/app/dump_*.json . COPY --from=prerelease /usr/src/app/package.json . # run the app diff --git a/db/migrations/1708273517919-Data.js b/db/migrations/1708547433185-Data.js similarity index 73% rename from db/migrations/1708273517919-Data.js rename to db/migrations/1708547433185-Data.js index 8bb5520..45802a9 100644 --- a/db/migrations/1708273517919-Data.js +++ b/db/migrations/1708547433185-Data.js @@ -1,5 +1,5 @@ -module.exports = class Data1708273517919 { - name = 'Data1708273517919' +module.exports = class Data1708547433185 { + name = 'Data1708547433185' async up(db) { await db.query(`CREATE TABLE "global_state" ("id" character varying NOT NULL, "total_value" numeric NOT NULL, "average_block_time_updated_height" integer NOT NULL, "average_block_time_updated_time" TIMESTAMP WITH TIME ZONE NOT NULL, "snapshot_updated_time" TIMESTAMP WITH TIME ZONE NOT NULL, "average_block_time" integer NOT NULL, "average_apr_multiplier" numeric NOT NULL, "average_apr" numeric NOT NULL, "idle_worker_shares" numeric NOT NULL, "cumulative_rewards" numeric NOT NULL, "pha_rate" numeric NOT NULL, "budget_per_block" numeric NOT NULL, "v_max" numeric NOT NULL, "treasury_ratio" numeric NOT NULL, "re" numeric NOT NULL, "k" numeric NOT NULL, "worker_count" integer NOT NULL, "idle_worker_count" integer NOT NULL, "budget_per_share" numeric NOT NULL, "delegator_count" integer NOT NULL, "withdrawal_dust_cleared" boolean, CONSTRAINT "PK_8b4db1150cf49bfd067e2572c74" PRIMARY KEY ("id"))`) @@ -8,8 +8,6 @@ module.exports = class Data1708273517919 { await db.query(`CREATE INDEX "IDX_c9fe1c8727e265ebcdb30019b6" ON "base_pool_whitelist" ("base_pool_id", "create_time") `) await db.query(`CREATE TABLE "nft" ("id" character varying NOT NULL, "cid" integer NOT NULL, "nft_id" integer NOT NULL, "burned" boolean NOT NULL, "mint_time" TIMESTAMP WITH TIME ZONE, "owner_id" character varying, CONSTRAINT "PK_8f46897c58e23b0e7bf6c8e56b0" PRIMARY KEY ("id"))`) await db.query(`CREATE INDEX "IDX_83cfd3a290ed70c660f8c9dfe2" ON "nft" ("owner_id") `) - await db.query(`CREATE TABLE "delegation_snapshot" ("id" character varying NOT NULL, "updated_time" TIMESTAMP WITH TIME ZONE NOT NULL, "cost" numeric NOT NULL, "value" numeric NOT NULL, "delegation_id" character varying, CONSTRAINT "PK_335066227038f09d171baca0bb9" PRIMARY KEY ("id"))`) - await db.query(`CREATE UNIQUE INDEX "IDX_22443055645351a609de9484f5" ON "delegation_snapshot" ("delegation_id", "updated_time") `) await db.query(`CREATE TABLE "delegation" ("id" character varying NOT NULL, "value" numeric NOT NULL, "cost" numeric NOT NULL, "shares" numeric NOT NULL, "withdrawing_value" numeric NOT NULL, "withdrawing_shares" numeric NOT NULL, "withdrawal_start_time" TIMESTAMP WITH TIME ZONE, "account_id" character varying, "base_pool_id" character varying, "delegation_nft_id" character varying, "withdrawal_nft_id" character varying, CONSTRAINT "REL_2d6f29d59b2d5cd7e3034ab857" UNIQUE ("delegation_nft_id"), CONSTRAINT "PK_a2cb6c9b942d68b109131beab44" PRIMARY KEY ("id"))`) await db.query(`CREATE INDEX "IDX_be5a5e334e4fb53a0cab3b0125" ON "delegation" ("account_id") `) await db.query(`CREATE UNIQUE INDEX "IDX_2d6f29d59b2d5cd7e3034ab857" ON "delegation" ("delegation_nft_id") `) @@ -27,26 +25,25 @@ module.exports = class Data1708273517919 { await db.query(`CREATE INDEX "IDX_5db95abd660552bdaa77e1b552" ON "account" ("identity_display") `) await db.query(`CREATE TABLE "vault" ("id" character varying NOT NULL, "last_share_price_checkpoint" numeric NOT NULL, "claimable_owner_shares" numeric NOT NULL, "base_pool_id" character varying, CONSTRAINT "REL_79f07f6ce7cca2f1ebfc2c0b11" UNIQUE ("base_pool_id"), CONSTRAINT "PK_dd0898234c77f9d97585171ac59" PRIMARY KEY ("id"))`) await db.query(`CREATE UNIQUE INDEX "IDX_79f07f6ce7cca2f1ebfc2c0b11" ON "vault" ("base_pool_id") `) - await db.query(`CREATE TABLE "session" ("id" character varying NOT NULL, "is_bound" boolean NOT NULL, "stake" numeric NOT NULL, "state" character varying(18) NOT NULL, "v" numeric NOT NULL, "ve" numeric NOT NULL, "p_init" integer NOT NULL, "p_instant" integer NOT NULL, "total_reward" numeric NOT NULL, "cooling_down_start_time" TIMESTAMP WITH TIME ZONE, "stake_pool_id" character varying, "worker_id" character varying, CONSTRAINT "PK_f55da76ac1c3ac420f444d2ff11" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_84c1c253406ae3adb5ba41ff7d" ON "session" ("stake_pool_id") `) - await db.query(`CREATE INDEX "IDX_30db46e58a0ae3fbc408179de8" ON "session" ("worker_id") `) - await db.query(`CREATE TABLE "worker" ("id" character varying NOT NULL, "confidence_level" integer NOT NULL, "initial_score" integer, "shares" numeric, "stake_pool_id" character varying, "session_id" character varying, CONSTRAINT "PK_dc8175fa0e34ce7a39e4ec73b94" PRIMARY KEY ("id"))`) + await db.query(`CREATE TABLE "worker" ("id" character varying NOT NULL, "confidence_level" integer NOT NULL, "initial_score" integer, "stake_pool_id" character varying, CONSTRAINT "PK_dc8175fa0e34ce7a39e4ec73b94" PRIMARY KEY ("id"))`) await db.query(`CREATE INDEX "IDX_81caea9d964ee3c0338fd44db4" ON "worker" ("stake_pool_id") `) - await db.query(`CREATE INDEX "IDX_9d35228a135aa08da0b546b58a" ON "worker" ("session_id") `) await db.query(`CREATE TABLE "stake_pool" ("id" character varying NOT NULL, "capacity" numeric, "delegable" numeric, "owner_reward" numeric NOT NULL, "worker_count" integer NOT NULL, "idle_worker_count" integer NOT NULL, "idle_worker_shares" numeric NOT NULL, "base_pool_id" character varying, CONSTRAINT "REL_663952452d6814016e857b710b" UNIQUE ("base_pool_id"), CONSTRAINT "PK_646d137a2979aa231fa880711f3" PRIMARY KEY ("id"))`) await db.query(`CREATE UNIQUE INDEX "IDX_663952452d6814016e857b710b" ON "stake_pool" ("base_pool_id") `) - await db.query(`CREATE TABLE "account_snapshot" ("id" character varying NOT NULL, "updated_time" TIMESTAMP WITH TIME ZONE NOT NULL, "delegation_value" numeric NOT NULL, "cumulative_stake_pool_owner_rewards" numeric NOT NULL, "cumulative_vault_owner_rewards" numeric NOT NULL, "account_id" character varying, CONSTRAINT "PK_3296654a614882b571b225c84e3" PRIMARY KEY ("id"))`) - await db.query(`CREATE UNIQUE INDEX "IDX_3801c73b4f257fa3d70cb94772" ON "account_snapshot" ("account_id", "updated_time") `) - await db.query(`CREATE TABLE "base_pool_snapshot" ("id" character varying NOT NULL, "updated_time" TIMESTAMP WITH TIME ZONE NOT NULL, "commission" numeric NOT NULL, "apr" numeric NOT NULL, "total_value" numeric NOT NULL, "delegator_count" integer NOT NULL, "share_price" numeric NOT NULL, "worker_count" integer, "idle_worker_count" integer, "stake_pool_count" integer, "cumulative_owner_rewards" numeric NOT NULL, "base_pool_id" character varying, CONSTRAINT "PK_7adc035ceca68381a1613757d2a" PRIMARY KEY ("id"))`) - await db.query(`CREATE UNIQUE INDEX "IDX_7c738c2364b8548a117089f684" ON "base_pool_snapshot" ("base_pool_id", "updated_time") `) + await db.query(`CREATE TABLE "session" ("id" character varying NOT NULL, "stake" numeric NOT NULL, "state" character varying(18) NOT NULL, "v" numeric NOT NULL, "ve" numeric NOT NULL, "p_init" integer NOT NULL, "p_instant" integer NOT NULL, "total_reward" numeric NOT NULL, "cooling_down_start_time" TIMESTAMP WITH TIME ZONE, "shares" numeric NOT NULL, "worker_id" character varying, CONSTRAINT "REL_30db46e58a0ae3fbc408179de8" UNIQUE ("worker_id"), CONSTRAINT "PK_f55da76ac1c3ac420f444d2ff11" PRIMARY KEY ("id"))`) + await db.query(`CREATE UNIQUE INDEX "IDX_30db46e58a0ae3fbc408179de8" ON "session" ("worker_id") `) + await db.query(`CREATE TABLE "account_snapshot" ("id" character varying NOT NULL, "updated_time" TIMESTAMP WITH TIME ZONE NOT NULL, "account" text NOT NULL, "delegation_value" numeric NOT NULL, "cumulative_stake_pool_owner_rewards" numeric NOT NULL, "cumulative_vault_owner_rewards" numeric NOT NULL, CONSTRAINT "PK_3296654a614882b571b225c84e3" PRIMARY KEY ("id"))`) + await db.query(`CREATE UNIQUE INDEX "IDX_114923489e01e385119439b38a" ON "account_snapshot" ("account", "updated_time") `) + await db.query(`CREATE TABLE "base_pool_snapshot" ("id" character varying NOT NULL, "updated_time" TIMESTAMP WITH TIME ZONE NOT NULL, "base_pool" text NOT NULL, "commission" numeric NOT NULL, "apr" numeric NOT NULL, "total_shares" numeric NOT NULL, "total_value" numeric NOT NULL, "delegator_count" integer NOT NULL, "share_price" numeric NOT NULL, "worker_count" integer, "idle_worker_count" integer, "stake_pool_count" integer, "cumulative_owner_rewards" numeric NOT NULL, CONSTRAINT "PK_7adc035ceca68381a1613757d2a" PRIMARY KEY ("id"))`) + await db.query(`CREATE UNIQUE INDEX "IDX_de91ab969c75330a623600b6de" ON "base_pool_snapshot" ("base_pool", "updated_time") `) await db.query(`CREATE TABLE "global_state_snapshot" ("id" character varying NOT NULL, "updated_time" TIMESTAMP WITH TIME ZONE NOT NULL, "total_value" numeric NOT NULL, "average_block_time" integer NOT NULL, "average_apr" numeric NOT NULL, "idle_worker_shares" numeric NOT NULL, "cumulative_rewards" numeric NOT NULL, "budget_per_block" numeric NOT NULL, "worker_count" integer NOT NULL, "idle_worker_count" integer NOT NULL, "budget_per_share" numeric NOT NULL, "delegator_count" integer NOT NULL, CONSTRAINT "PK_f168dfb48948e182df276f30021" PRIMARY KEY ("id"))`) await db.query(`CREATE INDEX "IDX_51f536d736eee486c1a2acca1a" ON "global_state_snapshot" ("updated_time") `) - await db.query(`CREATE TABLE "worker_snapshot" ("id" character varying NOT NULL, "updated_time" TIMESTAMP WITH TIME ZONE NOT NULL, "stake_pool_id" text, "session_id" text, "confidence_level" integer NOT NULL, "initial_score" integer, "stake" numeric, "state" character varying(18), "v" numeric, "ve" numeric, "p_init" integer, "p_instant" integer, "total_reward" numeric, "worker_id" character varying, CONSTRAINT "PK_5140a438c3891406b7420770cb9" PRIMARY KEY ("id"))`) - await db.query(`CREATE UNIQUE INDEX "IDX_41e43066b56549dd372b3e6860" ON "worker_snapshot" ("worker_id", "updated_time") `) + await db.query(`CREATE TABLE "delegation_snapshot" ("id" character varying NOT NULL, "updated_time" TIMESTAMP WITH TIME ZONE NOT NULL, "delegation" text NOT NULL, "cost" numeric NOT NULL, "value" numeric NOT NULL, CONSTRAINT "PK_335066227038f09d171baca0bb9" PRIMARY KEY ("id"))`) + await db.query(`CREATE UNIQUE INDEX "IDX_6bd56f9ee58c8be8ce385a4c08" ON "delegation_snapshot" ("delegation", "updated_time") `) + await db.query(`CREATE TABLE "worker_snapshot" ("id" character varying NOT NULL, "updated_time" TIMESTAMP WITH TIME ZONE NOT NULL, "worker" text NOT NULL, "stake_pool" text NOT NULL, "session" text NOT NULL, "confidence_level" integer NOT NULL, "initial_score" integer, "stake" numeric NOT NULL, "state" character varying(18) NOT NULL, "v" numeric NOT NULL, "ve" numeric NOT NULL, "p_init" integer NOT NULL, "p_instant" integer NOT NULL, "total_reward" numeric NOT NULL, CONSTRAINT "PK_5140a438c3891406b7420770cb9" PRIMARY KEY ("id"))`) + await db.query(`CREATE UNIQUE INDEX "IDX_99df4d67cde03dadbfa7bc5c97" ON "worker_snapshot" ("worker", "updated_time") `) await db.query(`ALTER TABLE "base_pool_whitelist" ADD CONSTRAINT "FK_57aaf3859a02333f595bd5bd224" FOREIGN KEY ("account_id") REFERENCES "account"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`) await db.query(`ALTER TABLE "base_pool_whitelist" ADD CONSTRAINT "FK_993eea06189ccb1817da97adaba" FOREIGN KEY ("base_pool_id") REFERENCES "base_pool"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`) await db.query(`ALTER TABLE "nft" ADD CONSTRAINT "FK_83cfd3a290ed70c660f8c9dfe2c" FOREIGN KEY ("owner_id") REFERENCES "account"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`) - await db.query(`ALTER TABLE "delegation_snapshot" ADD CONSTRAINT "FK_de5f9d9f586feada9d0c362a12c" FOREIGN KEY ("delegation_id") REFERENCES "delegation"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`) await db.query(`ALTER TABLE "delegation" ADD CONSTRAINT "FK_be5a5e334e4fb53a0cab3b01254" FOREIGN KEY ("account_id") REFERENCES "account"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`) await db.query(`ALTER TABLE "delegation" ADD CONSTRAINT "FK_4b95628b3ff2b93f23b1f59ae44" FOREIGN KEY ("base_pool_id") REFERENCES "base_pool"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`) await db.query(`ALTER TABLE "delegation" ADD CONSTRAINT "FK_2d6f29d59b2d5cd7e3034ab8574" FOREIGN KEY ("delegation_nft_id") REFERENCES "nft"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`) @@ -54,14 +51,9 @@ module.exports = class Data1708273517919 { await db.query(`ALTER TABLE "base_pool" ADD CONSTRAINT "FK_e20be4204009ad2ad1d17a125de" FOREIGN KEY ("owner_id") REFERENCES "account"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`) await db.query(`ALTER TABLE "base_pool" ADD CONSTRAINT "FK_b17f3b9349da680afa1e2e98055" FOREIGN KEY ("account_id") REFERENCES "account"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`) await db.query(`ALTER TABLE "vault" ADD CONSTRAINT "FK_79f07f6ce7cca2f1ebfc2c0b117" FOREIGN KEY ("base_pool_id") REFERENCES "base_pool"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`) - await db.query(`ALTER TABLE "session" ADD CONSTRAINT "FK_84c1c253406ae3adb5ba41ff7db" FOREIGN KEY ("stake_pool_id") REFERENCES "stake_pool"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`) - await db.query(`ALTER TABLE "session" ADD CONSTRAINT "FK_30db46e58a0ae3fbc408179de88" FOREIGN KEY ("worker_id") REFERENCES "worker"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`) await db.query(`ALTER TABLE "worker" ADD CONSTRAINT "FK_81caea9d964ee3c0338fd44db4a" FOREIGN KEY ("stake_pool_id") REFERENCES "stake_pool"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`) - await db.query(`ALTER TABLE "worker" ADD CONSTRAINT "FK_9d35228a135aa08da0b546b58ab" FOREIGN KEY ("session_id") REFERENCES "session"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`) await db.query(`ALTER TABLE "stake_pool" ADD CONSTRAINT "FK_663952452d6814016e857b710b4" FOREIGN KEY ("base_pool_id") REFERENCES "base_pool"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`) - await db.query(`ALTER TABLE "account_snapshot" ADD CONSTRAINT "FK_73a316a59d3e01d53ff90427a68" FOREIGN KEY ("account_id") REFERENCES "account"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`) - await db.query(`ALTER TABLE "base_pool_snapshot" ADD CONSTRAINT "FK_16d8a7162b480ecb5848203d30d" FOREIGN KEY ("base_pool_id") REFERENCES "base_pool"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`) - await db.query(`ALTER TABLE "worker_snapshot" ADD CONSTRAINT "FK_01768e88a94de867b21107e7a7a" FOREIGN KEY ("worker_id") REFERENCES "worker"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`) + await db.query(`ALTER TABLE "session" ADD CONSTRAINT "FK_30db46e58a0ae3fbc408179de88" FOREIGN KEY ("worker_id") REFERENCES "worker"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`) } async down(db) { @@ -71,8 +63,6 @@ module.exports = class Data1708273517919 { await db.query(`DROP INDEX "public"."IDX_c9fe1c8727e265ebcdb30019b6"`) await db.query(`DROP TABLE "nft"`) await db.query(`DROP INDEX "public"."IDX_83cfd3a290ed70c660f8c9dfe2"`) - await db.query(`DROP TABLE "delegation_snapshot"`) - await db.query(`DROP INDEX "public"."IDX_22443055645351a609de9484f5"`) await db.query(`DROP TABLE "delegation"`) await db.query(`DROP INDEX "public"."IDX_be5a5e334e4fb53a0cab3b0125"`) await db.query(`DROP INDEX "public"."IDX_2d6f29d59b2d5cd7e3034ab857"`) @@ -90,26 +80,25 @@ module.exports = class Data1708273517919 { await db.query(`DROP INDEX "public"."IDX_5db95abd660552bdaa77e1b552"`) await db.query(`DROP TABLE "vault"`) await db.query(`DROP INDEX "public"."IDX_79f07f6ce7cca2f1ebfc2c0b11"`) - await db.query(`DROP TABLE "session"`) - await db.query(`DROP INDEX "public"."IDX_84c1c253406ae3adb5ba41ff7d"`) - await db.query(`DROP INDEX "public"."IDX_30db46e58a0ae3fbc408179de8"`) await db.query(`DROP TABLE "worker"`) await db.query(`DROP INDEX "public"."IDX_81caea9d964ee3c0338fd44db4"`) - await db.query(`DROP INDEX "public"."IDX_9d35228a135aa08da0b546b58a"`) await db.query(`DROP TABLE "stake_pool"`) await db.query(`DROP INDEX "public"."IDX_663952452d6814016e857b710b"`) + await db.query(`DROP TABLE "session"`) + await db.query(`DROP INDEX "public"."IDX_30db46e58a0ae3fbc408179de8"`) await db.query(`DROP TABLE "account_snapshot"`) - await db.query(`DROP INDEX "public"."IDX_3801c73b4f257fa3d70cb94772"`) + await db.query(`DROP INDEX "public"."IDX_114923489e01e385119439b38a"`) await db.query(`DROP TABLE "base_pool_snapshot"`) - await db.query(`DROP INDEX "public"."IDX_7c738c2364b8548a117089f684"`) + await db.query(`DROP INDEX "public"."IDX_de91ab969c75330a623600b6de"`) await db.query(`DROP TABLE "global_state_snapshot"`) await db.query(`DROP INDEX "public"."IDX_51f536d736eee486c1a2acca1a"`) + await db.query(`DROP TABLE "delegation_snapshot"`) + await db.query(`DROP INDEX "public"."IDX_6bd56f9ee58c8be8ce385a4c08"`) await db.query(`DROP TABLE "worker_snapshot"`) - await db.query(`DROP INDEX "public"."IDX_41e43066b56549dd372b3e6860"`) + await db.query(`DROP INDEX "public"."IDX_99df4d67cde03dadbfa7bc5c97"`) await db.query(`ALTER TABLE "base_pool_whitelist" DROP CONSTRAINT "FK_57aaf3859a02333f595bd5bd224"`) await db.query(`ALTER TABLE "base_pool_whitelist" DROP CONSTRAINT "FK_993eea06189ccb1817da97adaba"`) await db.query(`ALTER TABLE "nft" DROP CONSTRAINT "FK_83cfd3a290ed70c660f8c9dfe2c"`) - await db.query(`ALTER TABLE "delegation_snapshot" DROP CONSTRAINT "FK_de5f9d9f586feada9d0c362a12c"`) await db.query(`ALTER TABLE "delegation" DROP CONSTRAINT "FK_be5a5e334e4fb53a0cab3b01254"`) await db.query(`ALTER TABLE "delegation" DROP CONSTRAINT "FK_4b95628b3ff2b93f23b1f59ae44"`) await db.query(`ALTER TABLE "delegation" DROP CONSTRAINT "FK_2d6f29d59b2d5cd7e3034ab8574"`) @@ -117,13 +106,8 @@ module.exports = class Data1708273517919 { await db.query(`ALTER TABLE "base_pool" DROP CONSTRAINT "FK_e20be4204009ad2ad1d17a125de"`) await db.query(`ALTER TABLE "base_pool" DROP CONSTRAINT "FK_b17f3b9349da680afa1e2e98055"`) await db.query(`ALTER TABLE "vault" DROP CONSTRAINT "FK_79f07f6ce7cca2f1ebfc2c0b117"`) - await db.query(`ALTER TABLE "session" DROP CONSTRAINT "FK_84c1c253406ae3adb5ba41ff7db"`) - await db.query(`ALTER TABLE "session" DROP CONSTRAINT "FK_30db46e58a0ae3fbc408179de88"`) await db.query(`ALTER TABLE "worker" DROP CONSTRAINT "FK_81caea9d964ee3c0338fd44db4a"`) - await db.query(`ALTER TABLE "worker" DROP CONSTRAINT "FK_9d35228a135aa08da0b546b58ab"`) await db.query(`ALTER TABLE "stake_pool" DROP CONSTRAINT "FK_663952452d6814016e857b710b4"`) - await db.query(`ALTER TABLE "account_snapshot" DROP CONSTRAINT "FK_73a316a59d3e01d53ff90427a68"`) - await db.query(`ALTER TABLE "base_pool_snapshot" DROP CONSTRAINT "FK_16d8a7162b480ecb5848203d30d"`) - await db.query(`ALTER TABLE "worker_snapshot" DROP CONSTRAINT "FK_01768e88a94de867b21107e7a7a"`) + await db.query(`ALTER TABLE "session" DROP CONSTRAINT "FK_30db46e58a0ae3fbc408179de88"`) } } diff --git a/dump_3000000.json b/initial_state/3000000.json similarity index 100% rename from dump_3000000.json rename to initial_state/3000000.json diff --git a/package.json b/package.json index 24f0c03..c18df59 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "private": true, "main": "src/main.ts", "scripts": { - "build": "rm -rf lib && tsc --project tsconfig.build.json", + "build": "rm -rf lib && tsc -p tsconfig.build.json", "postinstall": "patch-package" }, "dependencies": { diff --git a/patches/@subsquid+big-decimal+1.0.0.patch b/patches/@subsquid+big-decimal+1.0.0.patch new file mode 100644 index 0000000..0c882ed --- /dev/null +++ b/patches/@subsquid+big-decimal+1.0.0.patch @@ -0,0 +1,14 @@ +diff --git a/node_modules/@subsquid/big-decimal/bigdecimal.js b/node_modules/@subsquid/big-decimal/bigdecimal.js +index a9d3887..a641179 100644 +--- a/node_modules/@subsquid/big-decimal/bigdecimal.js ++++ b/node_modules/@subsquid/big-decimal/bigdecimal.js +@@ -7,7 +7,8 @@ const Base = Big() + + + // adjust settings +-Base.DP = 80 ++Base.DP = 12 ++Base.RM = 0 + Base.NE = -19 + + diff --git a/schema.graphql b/schema.graphql index 116b5fb..96503c0 100644 --- a/schema.graphql +++ b/schema.graphql @@ -126,7 +126,6 @@ type Delegation @entity @index(fields: ["basePool", "account"], unique: true) { withdrawalStartTime: DateTime delegationNft: Nft! @unique withdrawalNft: Nft - snapshots: [DelegationSnapshot!] @derivedFrom(field: "delegation") } type Nft @entity { @@ -152,10 +151,9 @@ type Worker @entity { "worker public key" id: ID! stakePool: StakePool - session: Session + session: Session @derivedFrom(field: "worker") confidenceLevel: Int! initialScore: Int - shares: BigDecimal } enum WorkerState { @@ -168,9 +166,7 @@ enum WorkerState { type Session @entity { "session account address" id: ID! - isBound: Boolean! - stakePool: StakePool - worker: Worker + worker: Worker @unique stake: BigDecimal! state: WorkerState! v: BigDecimal! @@ -179,6 +175,7 @@ type Session @entity { pInstant: Int! totalReward: BigDecimal! coolingDownStartTime: DateTime + shares: BigDecimal! } type AccountSnapshot @@ -187,7 +184,7 @@ type AccountSnapshot id: ID! "block time" updatedTime: DateTime! - account: Account! + account: String! delegationValue: BigDecimal! cumulativeStakePoolOwnerRewards: BigDecimal! cumulativeVaultOwnerRewards: BigDecimal! @@ -199,9 +196,10 @@ type BasePoolSnapshot id: ID! "block time" updatedTime: DateTime! - basePool: BasePool! + basePool: String! commission: BigDecimal! apr: BigDecimal! + totalShares: BigDecimal! totalValue: BigDecimal! delegatorCount: Int! sharePrice: BigDecimal! @@ -215,7 +213,6 @@ type GlobalStateSnapshot @entity { id: ID! "block time" updatedTime: DateTime! @index - totalValue: BigDecimal! averageBlockTime: Int! averageApr: BigDecimal! @@ -234,7 +231,7 @@ type DelegationSnapshot id: ID! "block time" updatedTime: DateTime! - delegation: Delegation! + delegation: String! cost: BigDecimal! value: BigDecimal! } @@ -245,16 +242,16 @@ type WorkerSnapshot id: ID! "block time" updatedTime: DateTime! - worker: Worker! - stakePoolId: String - sessionId: String + worker: String! + stakePool: String! + session: String! confidenceLevel: Int! initialScore: Int - stake: BigDecimal - state: WorkerState - v: BigDecimal - ve: BigDecimal - pInit: Int - pInstant: Int - totalReward: BigDecimal + stake: BigDecimal! + state: WorkerState! + v: BigDecimal! + ve: BigDecimal! + pInit: Int! + pInstant: Int! + totalReward: BigDecimal! } diff --git a/src/constants.ts b/src/constants.ts index c583d4a..b87bf0d 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,3 +1,3 @@ -export const DUMP_BLOCK = 3000000 +export const INITIAL_BLOCK = 3000000 export const BASE_POOL_ACCOUNT = '42qnPyfw3sbWMGGtTPPc2YFNZRKPGXswRszyQQjGs2FDxdim' diff --git a/src/decodeEvents.ts b/src/decodeEvents.ts index b72fda3..a0e51d7 100644 --- a/src/decodeEvents.ts +++ b/src/decodeEvents.ts @@ -9,7 +9,7 @@ import { phalaVault, rmrkCore, } from './types/events' -import {encodeAddress, fromBits, toBalance} from './utils/converter' +import {encodeAddress, fromBits, toBalance} from './utils' const decodeEvent = ( event: Ctx['blocks'][number]['events'][number], @@ -362,7 +362,7 @@ const decodeEvent = ( args: { sessionId: encodeAddress(session), v: fromBits(vBits), - payout: fromBits(payoutBits).round(12, 0), + payout: fromBits(payoutBits), }, } } diff --git a/src/helper/account.ts b/src/helper/account.ts new file mode 100644 index 0000000..d139e2e --- /dev/null +++ b/src/helper/account.ts @@ -0,0 +1,21 @@ +import {BigDecimal} from '@subsquid/big-decimal' +import {Account} from '../model' + +export const getAccount = (m: Map, id: string): Account => { + let acc = m.get(id) + if (acc == null) { + acc = new Account({ + id, + stakePoolValue: BigDecimal(0), + stakePoolNftCount: 0, + stakePoolAvgAprMultiplier: BigDecimal(0), + vaultValue: BigDecimal(0), + vaultNftCount: 0, + vaultAvgAprMultiplier: BigDecimal(0), + cumulativeStakePoolOwnerRewards: BigDecimal(0), + cumulativeVaultOwnerRewards: BigDecimal(0), + }) + m.set(id, acc) + } + return acc +} diff --git a/src/utils/basePool.ts b/src/helper/basePool.ts similarity index 74% rename from src/utils/basePool.ts rename to src/helper/basePool.ts index cfe6018..d7e1019 100644 --- a/src/utils/basePool.ts +++ b/src/helper/basePool.ts @@ -1,5 +1,12 @@ import {BigDecimal} from '@subsquid/big-decimal' -import {type Account, BasePool, BasePoolKind, StakePool, Vault} from '../model' +import { + type Account, + BasePool, + BasePoolKind, + GlobalState, + StakePool, + Vault, +} from '../model' export function createPool( kind: BasePoolKind.StakePool, @@ -80,15 +87,12 @@ export function updateSharePrice(basePool: BasePool): void { if (basePool.totalShares.eq(0)) { basePool.sharePrice = BigDecimal(1) basePool.totalValue = BigDecimal(0) - basePool.freeValue = BigDecimal(0) } else { - basePool.sharePrice = basePool.totalValue - .div(basePool.totalShares) - .round(12, 0) + basePool.sharePrice = basePool.totalValue.div(basePool.totalShares) } - basePool.withdrawingValue = basePool.withdrawingShares - .times(basePool.sharePrice) - .round(12, 0) + basePool.withdrawingValue = basePool.withdrawingShares.times( + basePool.sharePrice, + ) } export function updateStakePoolAprMultiplier( @@ -100,7 +104,7 @@ export function updateStakePoolAprMultiplier( : stakePool.idleWorkerShares .times(BigDecimal(1).minus(basePool.commission)) .div(basePool.totalValue) - .round(6, 0) + .round(6) } export const updateVaultAprMultiplier = ( @@ -114,7 +118,7 @@ export const updateVaultAprMultiplier = ( .times(account.stakePoolValue) .div(basePool.totalValue) .times(BigDecimal(1).minus(basePool.commission)) - .round(6, 0) + .round(6) } } @@ -134,11 +138,11 @@ export const updateStakePoolDelegable = ( } export const getBasePoolAvgAprMultiplier = ( - basePools: BasePool[], + basePoolMap: Map, ): BigDecimal => { let weight = BigDecimal(0) let totalValue = BigDecimal(0) - for (const basePool of basePools) { + for (const basePool of basePoolMap.values()) { if (basePool.kind === BasePoolKind.StakePool) { totalValue = totalValue.plus(basePool.totalValue) weight = weight.plus(basePool.totalValue.times(basePool.aprMultiplier)) @@ -148,17 +152,35 @@ export const getBasePoolAvgAprMultiplier = ( return BigDecimal(0) } - return weight.div(totalValue).round(6, 0) + return weight.div(totalValue).round(6) } -export const updateFreeValue = ( - basePool: BasePool, - value: BigDecimal, -): void => { - // free value is wPHA with minBalance - if (value.lt('0.0001')) { - basePool.freeValue = BigDecimal(0) - } else { - basePool.freeValue = value - } +export const getApr = ( + globalState: GlobalState, + aprMultiplier: BigDecimal, +): BigDecimal => { + const ONE_YEAR = 365 * 24 * 60 * 60 * 1000 + const {averageBlockTime, idleWorkerShares, budgetPerBlock, treasuryRatio} = + globalState + const value = aprMultiplier + .times(budgetPerBlock) + .times(BigDecimal(1).minus(treasuryRatio)) + .times(ONE_YEAR) + .div(averageBlockTime) + .div(idleWorkerShares) + .round(6) + + return value } + +// export const updateFreeValue = ( +// basePool: BasePool, +// value: BigDecimal, +// ): void => { +// // free value is wPHA with minBalance +// if (value.lt('0.0001')) { +// basePool.freeValue = BigDecimal(0) +// } else { +// basePool.freeValue = value +// } +// } diff --git a/src/utils/delegation.ts b/src/helper/delegation.ts similarity index 80% rename from src/utils/delegation.ts rename to src/helper/delegation.ts index 06b23b8..067dc5a 100644 --- a/src/utils/delegation.ts +++ b/src/helper/delegation.ts @@ -1,15 +1,15 @@ import {BigDecimal} from '@subsquid/big-decimal' import {type BasePool, type Delegation} from '../model' -import {sum} from './common' +import {sum} from '../utils' export const updateDelegationValue = ( delegation: Delegation, basePool: BasePool, ): void => { - delegation.value = delegation.shares.times(basePool.sharePrice).round(12, 0) - delegation.withdrawingValue = delegation.withdrawingShares - .times(basePool.sharePrice) - .round(12, 0) + delegation.value = delegation.shares.times(basePool.sharePrice) + delegation.withdrawingValue = delegation.withdrawingShares.times( + basePool.sharePrice, + ) } export const getDelegationAvgAprMultiplier = ( diff --git a/src/utils/globalState.ts b/src/helper/globalState.ts similarity index 70% rename from src/utils/globalState.ts rename to src/helper/globalState.ts index 39219f2..1b9a5e5 100644 --- a/src/utils/globalState.ts +++ b/src/helper/globalState.ts @@ -2,21 +2,22 @@ import assert from 'assert' import {type GlobalState} from '../model' import {type SubstrateBlock} from '../processor' import {phalaComputation} from '../types/storage' -import {fromBits} from './converter' +import {fromBits} from '../utils' export const updateAverageBlockTime = ( block: SubstrateBlock, globalState: GlobalState, ): void => { const blockCount = block.height - globalState.averageBlockTimeUpdatedHeight - if (blockCount < 100) return - assert(block.timestamp) - const duration = - block.timestamp - globalState.averageBlockTimeUpdatedTime.getTime() + if (blockCount >= 100) { + assert(block.timestamp) + const duration = + block.timestamp - globalState.averageBlockTimeUpdatedTime.getTime() - globalState.averageBlockTime = Math.floor(duration / blockCount) - globalState.averageBlockTimeUpdatedHeight = block.height - globalState.averageBlockTimeUpdatedTime = new Date(block.timestamp) + globalState.averageBlockTime = Math.floor(duration / blockCount) + globalState.averageBlockTimeUpdatedHeight = block.height + globalState.averageBlockTimeUpdatedTime = new Date(block.timestamp) + } } export const updateTokenomicParameters = async ( diff --git a/src/utils/identity.ts b/src/helper/identity.ts similarity index 94% rename from src/utils/identity.ts rename to src/helper/identity.ts index 2db305d..21fc10a 100644 --- a/src/utils/identity.ts +++ b/src/helper/identity.ts @@ -2,8 +2,8 @@ import {decodeHex} from '@subsquid/substrate-processor' import {type Account, IdentityJudgement} from '../model' import {type SubstrateBlock} from '../processor' import {identity} from '../types/storage' -import {getAccount} from './common' -import {decodeAddress} from './converter' +import {decodeAddress} from '../utils' +import {getAccount} from './account' const decoder = new TextDecoder() diff --git a/src/utils/postUpdate.ts b/src/helper/postUpdate.ts similarity index 58% rename from src/utils/postUpdate.ts rename to src/helper/postUpdate.ts index 19f748c..cd0b55b 100644 --- a/src/utils/postUpdate.ts +++ b/src/helper/postUpdate.ts @@ -3,57 +3,37 @@ import {BigDecimal} from '@subsquid/big-decimal' import {groupBy} from 'lodash' import { type Account, - type AccountSnapshot, type BasePool, BasePoolKind, - type BasePoolSnapshot, type Delegation, - type DelegationSnapshot, type GlobalState, - type StakePool, - Worker, - type WorkerSnapshot, } from '../model' -import {type Ctx} from '../processor' +import {type SubstrateBlock} from '../processor' +import {assertGet, max, sum} from '../utils' import { + getApr, getBasePoolAvgAprMultiplier, updateSharePrice, updateVaultAprMultiplier, } from './basePool' -import {assertGet, max, sum, toMap} from './common' import { getDelegationAvgAprMultiplier, updateDelegationValue, } from './delegation' -import { - createAccountSnapshot, - createBasePoolSnapshot, - createDelegationSnapshot, - createGlobalStateSnapshot, - createWorkerSnapshot, -} from './snapshot' - -const ONE_YEAR = 365 * 24 * 60 * 60 * 1000 +import {updateAverageBlockTime} from './globalState' -const postUpdate = async ( - ctx: Ctx, +const postUpdate = ( + block: SubstrateBlock, globalState: GlobalState, accountMap: Map, - basePools: BasePool[], - stakePoolMap: Map, + basePoolMap: Map, delegations: Delegation[], -): Promise => { - const latestBlock = ctx.blocks.at(-1) - assert(latestBlock?.header.timestamp) - const updatedTime = new Date(latestBlock.header.timestamp) - updatedTime.setUTCMinutes(0, 0, 0) - const shouldTakeSnapshot = - updatedTime.getTime() !== globalState.snapshotUpdatedTime.getTime() +): void => { + updateAverageBlockTime(block, globalState) + const timestamp = block.timestamp + assert(timestamp) const delegatorSet = new Set() - const accountSnapshots: AccountSnapshot[] = [] - const delegationSnapshots: DelegationSnapshot[] = [] - const basePoolMap = toMap(basePools) const delegationAccountIdMap = groupBy(delegations, (x) => x.account.id) if (globalState.withdrawalDustCleared !== true) { @@ -65,10 +45,7 @@ const postUpdate = async ( } catch (err) { // noop } - if ( - clearWithdrawalDate != null && - latestBlock.header.timestamp >= clearWithdrawalDate - ) { + if (clearWithdrawalDate != null && timestamp >= clearWithdrawalDate) { const clearWithdrawalThreshold = Bun.env.CLEAR_WITHDRAWAL_THRESHOLD ?? '0.01' for (const delegation of delegations) { @@ -96,22 +73,8 @@ const postUpdate = async ( } } - const getApr = (aprMultiplier: BigDecimal): BigDecimal => { - const {averageBlockTime, idleWorkerShares, budgetPerBlock, treasuryRatio} = - globalState - const value = aprMultiplier - .times(budgetPerBlock) - .times(BigDecimal(1).minus(treasuryRatio)) - .times(ONE_YEAR) - .div(averageBlockTime) - .div(idleWorkerShares) - .round(6, 0) - - return value - } - globalState.delegatorCount = 0 - for (const basePool of basePools) { + for (const basePool of basePoolMap.values()) { basePool.delegatorCount = 0 } @@ -126,7 +89,7 @@ const postUpdate = async ( } } - for (const [, account] of accountMap) { + for (const account of accountMap.values()) { const accountDelegations = delegationAccountIdMap[account.id] if (accountDelegations === undefined) continue const accountStakePoolDelegations = accountDelegations.filter( @@ -143,7 +106,7 @@ const postUpdate = async ( ) } - for (const [, basePool] of basePoolMap) { + for (const basePool of basePoolMap.values()) { const account = assertGet(accountMap, basePool.account.id) if (basePool.kind === BasePoolKind.Vault) { basePool.totalValue = basePool.freeValue.plus(account.stakePoolValue) @@ -171,15 +134,9 @@ const postUpdate = async ( if (delegation.value.gt(0) && !basePoolMap.has(delegation.account.id)) { delegatorSet.add(delegation.account.id) } - - if (shouldTakeSnapshot && delegation.shares.gt(0)) { - delegationSnapshots.push( - createDelegationSnapshot({delegation, updatedTime}), - ) - } } - for (const [, account] of accountMap) { + for (const account of accountMap.values()) { const accountDelegations = delegationAccountIdMap[account.id] if (accountDelegations === undefined) continue const accountVaultDelegations = accountDelegations.filter( @@ -189,67 +146,19 @@ const postUpdate = async ( account.vaultNftCount = accountVaultDelegations.filter((x) => x.shares.gt(0), ).length - - if (shouldTakeSnapshot) { - accountSnapshots.push(createAccountSnapshot({account, updatedTime})) - } - account.vaultAvgAprMultiplier = getDelegationAvgAprMultiplier( accountVaultDelegations, ) } - globalState.averageAprMultiplier = getBasePoolAvgAprMultiplier(basePools) + globalState.averageAprMultiplier = getBasePoolAvgAprMultiplier(basePoolMap) globalState.budgetPerShare = globalState.budgetPerBlock .div(globalState.idleWorkerShares) .div(globalState.averageBlockTime) - .times(1e7 * 24 * 60 * 60) - .round(12, 0) - globalState.averageApr = getApr(globalState.averageAprMultiplier) + .times(1e7) + .times(24 * 60 * 60) + globalState.averageApr = getApr(globalState, globalState.averageAprMultiplier) globalState.delegatorCount = delegatorSet.size - if (shouldTakeSnapshot) { - globalState.snapshotUpdatedTime = updatedTime - } - - if (shouldTakeSnapshot) { - const workerSnapshots: WorkerSnapshot[] = [] - const basePoolSnapshots: BasePoolSnapshot[] = [] - - // Take worker snapshot at 00:00 UTC - if (updatedTime.getUTCHours() === 0) { - const workers = await ctx.store.find(Worker, { - relations: { - stakePool: true, - session: true, - }, - }) - for (const worker of workers) { - workerSnapshots.push(createWorkerSnapshot({worker, updatedTime})) - } - } - - for (const basePool of basePools) { - basePoolSnapshots.push( - createBasePoolSnapshot({ - basePool, - updatedTime, - apr: getApr(basePool.aprMultiplier), - stakePool: stakePoolMap.get(basePool.id), - }), - ) - } - - const globalStateSnapshot = createGlobalStateSnapshot( - globalState, - updatedTime, - ) - - await ctx.store.save(workerSnapshots) - await ctx.store.save(basePoolSnapshots) - await ctx.store.save(globalStateSnapshot) - await ctx.store.save(accountSnapshots) - await ctx.store.save(delegationSnapshots) - } } export default postUpdate diff --git a/src/helper/snapshot.ts b/src/helper/snapshot.ts new file mode 100644 index 0000000..98e640e --- /dev/null +++ b/src/helper/snapshot.ts @@ -0,0 +1,213 @@ +import assert from 'assert' +import {type BigDecimal} from '@subsquid/big-decimal' +import { + type Account, + AccountSnapshot, + type BasePool, + BasePoolSnapshot, + type Delegation, + DelegationSnapshot, + type GlobalState, + GlobalStateSnapshot, + type Session, + type StakePool, + type Worker, + WorkerSnapshot, +} from '../model' +import type {Ctx, SubstrateBlock} from '../processor' +import {assertGet, join} from '../utils' +import {getApr} from './basePool' + +export const createAccountSnapshot = ({ + account, + updatedTime, +}: { + account: Account + updatedTime: Date +}): AccountSnapshot => { + const date = new Date(updatedTime) + date.setUTCHours(0, 0, 0, 0) + return new AccountSnapshot({ + id: join(account.id, date.toISOString()), + account: account.id, + delegationValue: account.vaultValue.plus(account.stakePoolValue), + updatedTime: date, + cumulativeStakePoolOwnerRewards: account.cumulativeStakePoolOwnerRewards, + cumulativeVaultOwnerRewards: account.cumulativeVaultOwnerRewards, + }) +} + +export const createBasePoolSnapshot = ({ + basePool, + updatedTime, + apr, + stakePool, +}: { + basePool: BasePool + updatedTime: Date + apr: BigDecimal + stakePool?: StakePool +}): BasePoolSnapshot => { + return new BasePoolSnapshot({ + id: join(basePool.id, updatedTime.toISOString()), + basePool: basePool.id, + commission: basePool.commission, + totalShares: basePool.totalShares, + totalValue: basePool.totalValue, + sharePrice: basePool.sharePrice, + delegatorCount: basePool.delegatorCount, + apr, + updatedTime, + workerCount: stakePool?.workerCount, + idleWorkerCount: stakePool?.idleWorkerCount, + stakePoolCount: + stakePool == null ? basePool.account.stakePoolNftCount : undefined, + cumulativeOwnerRewards: basePool.cumulativeOwnerRewards, + }) +} + +export const createDelegationSnapshot = ({ + delegation, + updatedTime, +}: { + delegation: Delegation + updatedTime: Date +}): DelegationSnapshot => { + return new DelegationSnapshot({ + id: join(delegation.id, updatedTime.toISOString()), + delegation: delegation.id, + cost: delegation.cost, + value: delegation.value, + updatedTime, + }) +} + +export const createWorkerSnapshot = ({ + worker, + session, + updatedTime, +}: { + worker: Worker + session: Session + updatedTime: Date +}): WorkerSnapshot => { + assert(session.worker) + assert(worker.stakePool) + return new WorkerSnapshot({ + id: join(session.id, updatedTime.toISOString()), + updatedTime, + worker: worker.id, + session: session.id, + stakePool: worker.stakePool.id, + confidenceLevel: worker.confidenceLevel, + initialScore: worker.initialScore, + stake: session.stake, + state: session.state, + v: session.v, + ve: session.ve, + pInit: session.pInit, + pInstant: session.pInstant, + totalReward: session.totalReward, + }) +} + +export const createGlobalStateSnapshot = ( + globalState: GlobalState, + updatedTime: Date, +): GlobalStateSnapshot => { + return new GlobalStateSnapshot({ + id: updatedTime.toISOString(), + updatedTime, + totalValue: globalState.totalValue, + averageBlockTime: globalState.averageBlockTime, + averageApr: globalState.averageApr, + cumulativeRewards: globalState.cumulativeRewards, + budgetPerBlock: globalState.budgetPerBlock, + workerCount: globalState.workerCount, + idleWorkerCount: globalState.idleWorkerCount, + budgetPerShare: globalState.budgetPerShare, + delegatorCount: globalState.delegatorCount, + idleWorkerShares: globalState.idleWorkerShares, + }) +} + +const getUpdatedTime = (block: SubstrateBlock): Date => { + const timestamp = block.timestamp + assert(timestamp) + const updatedTime = new Date(timestamp) + updatedTime.setUTCHours(0, 0, 0, 0) + return updatedTime +} + +export const isSnapshotUpdateNeeded = ( + block: SubstrateBlock, + globalState: GlobalState, +): boolean => { + const updatedTime = getUpdatedTime(block) + return updatedTime.getTime() !== globalState.snapshotUpdatedTime.getTime() +} + +export const takeSnapshot = async ( + ctx: Ctx, + block: SubstrateBlock, + globalState: GlobalState, + accountMap: Map, + basePoolMap: Map, + stakePoolMap: Map, + workerMap: Map, + sessionMap: Map, + delegations: Delegation[], +) => { + const updatedTime = getUpdatedTime(block) + globalState.snapshotUpdatedTime = updatedTime + const accountSnapshots: AccountSnapshot[] = [] + const delegationSnapshots: DelegationSnapshot[] = [] + const workerSnapshots: WorkerSnapshot[] = [] + const basePoolSnapshots: BasePoolSnapshot[] = [] + + if (updatedTime.getUTCHours() === 0) { + for (const session of sessionMap.values()) { + if (session.worker != null) { + const worker = assertGet(workerMap, session.worker.id) + workerSnapshots.push( + createWorkerSnapshot({worker, session, updatedTime}), + ) + } + } + } + + for (const account of accountMap.values()) { + accountSnapshots.push(createAccountSnapshot({account, updatedTime})) + } + + for (const delegation of delegations) { + if (delegation.shares.gt(0)) { + delegationSnapshots.push( + createDelegationSnapshot({delegation, updatedTime}), + ) + } + } + + for (const basePool of basePoolMap.values()) { + basePoolSnapshots.push( + createBasePoolSnapshot({ + basePool, + updatedTime, + apr: getApr(globalState, basePool.aprMultiplier), + stakePool: stakePoolMap.get(basePool.id), + }), + ) + } + + const globalStateSnapshot = createGlobalStateSnapshot( + globalState, + updatedTime, + ) + + ctx.log.info(`Saving snapshots ${updatedTime.toISOString()}`) + await ctx.store.save(workerSnapshots) + await ctx.store.save(basePoolSnapshots) + await ctx.store.save(globalStateSnapshot) + await ctx.store.save(accountSnapshots) + await ctx.store.save(delegationSnapshots) +} diff --git a/src/utils/worker.ts b/src/helper/worker.ts similarity index 84% rename from src/utils/worker.ts rename to src/helper/worker.ts index 25f175e..2622edf 100644 --- a/src/utils/worker.ts +++ b/src/helper/worker.ts @@ -13,10 +13,10 @@ const confidenceScoreMap: Record = { 5: '0.7', } -export function updateWorkerShares( - worker: Worker, +export function updateSessionShares( session: Session, -): asserts worker is Worker & {shares: BigDecimal} { + worker: Worker, +): asserts session is Session & {shares: BigDecimal} { const {v, pInstant} = session const {confidenceLevel} = worker if (validateConfidenceLevel(confidenceLevel)) { @@ -25,8 +25,6 @@ export function updateWorkerShares( .pow(2) .plus(BigDecimal(2).mul(pInstant).mul(confidenceScore).pow(2)) .sqrt() - .round(12, 0) - - worker.shares = shares + session.shares = shares } } diff --git a/src/importDump.ts b/src/loadInitialState.ts similarity index 85% rename from src/importDump.ts rename to src/loadInitialState.ts index 0bbcc03..47d37ef 100644 --- a/src/importDump.ts +++ b/src/loadInitialState.ts @@ -1,9 +1,23 @@ import assert from 'assert' import path from 'path' import {BigDecimal} from '@subsquid/big-decimal' -import {readFile} from 'fs/promises' import {groupBy} from 'lodash' -import {BASE_POOL_ACCOUNT, DUMP_BLOCK} from './constants' +import {BASE_POOL_ACCOUNT, INITIAL_BLOCK} from './constants' +import {getAccount} from './helper/account' +import { + createPool, + updateSharePrice, + updateStakePoolAprMultiplier, + updateStakePoolDelegable, + updateVaultAprMultiplier, +} from './helper/basePool' +import { + getDelegationAvgAprMultiplier, + updateDelegationValue, +} from './helper/delegation' +import {updateTokenomicParameters} from './helper/globalState' +import {createAccountSnapshot} from './helper/snapshot' +import {updateSessionShares} from './helper/worker' import { type Account, type AccountSnapshot, @@ -21,22 +35,8 @@ import { WorkerState, } from './model' import {type Ctx} from './processor' -import { - createPool, - updateSharePrice, - updateStakePoolAprMultiplier, - updateStakePoolDelegable, - updateVaultAprMultiplier, -} from './utils/basePool' -import {assertGet, getAccount, join, sum} from './utils/common' -import {fromBits, toBalance} from './utils/converter' -import { - getDelegationAvgAprMultiplier, - updateDelegationValue, -} from './utils/delegation' -import {updateTokenomicParameters} from './utils/globalState' -import {createAccountSnapshot} from './utils/snapshot' -import {updateWorkerShares} from './utils/worker' +import {fromBits, toBalance} from './utils' +import {assertGet, join, sum} from './utils' interface IBasePool { pid: string @@ -72,7 +72,7 @@ interface BasePoolWithStakePool extends IBasePool { } } -interface Dump { +interface InitialState { timestamp: number basePools: Array workers: Array<{ @@ -106,18 +106,16 @@ interface Dump { }> } -const importDump = async (ctx: Ctx): Promise => { - const dumpFile = await readFile( - path.join(__dirname, `../dump_${DUMP_BLOCK}.json`), - 'utf8', - ) - const dump: Dump = JSON.parse(dumpFile) - const updatedTime = new Date(dump.timestamp) +const loadInitialState = async (ctx: Ctx): Promise => { + const initialState: InitialState = await Bun.file( + path.resolve(__dirname, `../initial_state/${INITIAL_BLOCK}.json`), + ).json() + const updatedTime = new Date(initialState.timestamp) const globalState = new GlobalState({ id: '0', averageApr: BigDecimal(0), averageAprMultiplier: BigDecimal(0), - averageBlockTimeUpdatedHeight: DUMP_BLOCK, + averageBlockTimeUpdatedHeight: INITIAL_BLOCK, averageBlockTimeUpdatedTime: updatedTime, snapshotUpdatedTime: updatedTime, averageBlockTime: 12000, @@ -132,11 +130,12 @@ const importDump = async (ctx: Ctx): Promise => { await updateTokenomicParameters(ctx.blocks[0].header, globalState) const accountMap = new Map() const workerMap = new Map() + const sessionMap = new Map() + const workerSessionMap = new Map() const basePoolMap = new Map() const basePoolCidMap = new Map() const stakePoolMap = new Map() const vaultMap = new Map() - const sessionMap = new Map() const delegationMap = new Map() const nftMap = new Map() const basePoolWhitelistMap = new Map() @@ -144,7 +143,7 @@ const importDump = async (ctx: Ctx): Promise => { const accountValueSnapshots: AccountSnapshot[] = [] const whitelists: BasePoolWhitelist[] = [] - for (const i of dump.identities) { + for (const i of initialState.identities) { const account = getAccount(accountMap, i.id) account.identityDisplay = i.identity if (i.judgements.length > 0) { @@ -154,7 +153,7 @@ const importDump = async (ctx: Ctx): Promise => { accountMap.set(account.id, account) } - for (const w of dump.workers) { + for (const w of initialState.workers) { const worker = new Worker({ id: w.id, confidenceLevel: w.confidenceLevel, @@ -163,13 +162,9 @@ const importDump = async (ctx: Ctx): Promise => { workerMap.set(worker.id, worker) } - // MEMO: insert worker first to avoid invalid foreign key - await ctx.store.insert([...workerMap.values()]) - - for (const s of dump.sessions) { + for (const s of initialState.sessions) { const session = new Session({ id: s.id, - isBound: false, v: fromBits(s.v), ve: fromBits(s.ve), state: s.state, @@ -181,17 +176,17 @@ const importDump = async (ctx: Ctx): Promise => { ? null : new Date(s.coolingDownStartTime * 1000), stake: toBalance(s.stake), + shares: BigDecimal(0), }) if (s.worker != null) { + workerSessionMap.set(s.worker, session) const worker = assertGet(workerMap, s.worker) - session.isBound = true session.worker = worker - worker.session = session - updateWorkerShares(worker, session) + updateSessionShares(session, worker) globalState.workerCount++ if (session.state === WorkerState.WorkerIdle) { globalState.idleWorkerShares = globalState.idleWorkerShares.plus( - worker.shares, + session.shares, ) globalState.idleWorkerCount++ } @@ -199,7 +194,7 @@ const importDump = async (ctx: Ctx): Promise => { sessionMap.set(session.id, session) } - for (const b of dump.basePools) { + for (const b of initialState.basePools) { const isVault = b.vault !== undefined const props = { pid: b.pid, @@ -238,19 +233,15 @@ const importDump = async (ctx: Ctx): Promise => { for (const w of b.stakePool.workers) { const worker = assertGet(workerMap, w) worker.stakePool = stakePool - assert(worker.session) - worker.session.stakePool = stakePool - if (worker.session.state === WorkerState.WorkerIdle) { - assert(worker.shares) + const session = assertGet(workerSessionMap, w) + if (session.state === WorkerState.WorkerIdle) { + const session = assertGet(workerSessionMap, w) stakePool.idleWorkerCount++ stakePool.idleWorkerShares = stakePool.idleWorkerShares.plus( - worker.shares, - ) - } - if (worker.session.state === WorkerState.WorkerCoolingDown) { - basePool.releasingValue = basePool.releasingValue.plus( - worker.session.stake, + session.shares, ) + } else if (session.state === WorkerState.WorkerCoolingDown) { + basePool.releasingValue = basePool.releasingValue.plus(session.stake) } } @@ -269,7 +260,7 @@ const importDump = async (ctx: Ctx): Promise => { account: getAccount(accountMap, address), basePool, // MEMO: keep the order of whitelists - createTime: new Date(dump.timestamp - whitelists.length + i), + createTime: new Date(initialState.timestamp - whitelists.length + i), }), ) } @@ -300,7 +291,7 @@ const importDump = async (ctx: Ctx): Promise => { basePoolCidMap.set(basePool.cid.toString(), basePool) } - for (const d of dump.nfts) { + for (const d of initialState.nfts) { const owner = getAccount(accountMap, d.owner) const nftId = join(d.cid, d.nftId) @@ -396,7 +387,10 @@ const importDump = async (ctx: Ctx): Promise => { getDelegationAvgAprMultiplier(stakePoolDelegations) accountValueSnapshots.push( - createAccountSnapshot({account, updatedTime: new Date(dump.timestamp)}), + createAccountSnapshot({ + account, + updatedTime: new Date(initialState.timestamp), + }), ) } @@ -411,9 +405,9 @@ const importDump = async (ctx: Ctx): Promise => { ...stakePoolDelegations.map((x) => x.withdrawingValue), ) } - basePool.withdrawingValue = basePool.withdrawingShares - .times(basePool.sharePrice) - .round(12, 0) + basePool.withdrawingValue = basePool.withdrawingShares.times( + basePool.sharePrice, + ) } for (const stakePool of stakePoolMap.values()) { @@ -435,8 +429,8 @@ const importDump = async (ctx: Ctx): Promise => { basePoolMap, stakePoolMap, vaultMap, - sessionMap, workerMap, + sessionMap, nftMap, delegationMap, basePoolWhitelistMap, @@ -444,13 +438,13 @@ const importDump = async (ctx: Ctx): Promise => { whitelists, ]) { if (x instanceof Map) { - await ctx.store.save([...x.values()]) + await ctx.store.insert([...x.values()]) } else if (Array.isArray(x)) { - await ctx.store.save([...x]) + await ctx.store.insert([...x]) } else { - await ctx.store.save(x) + await ctx.store.insert(x) } } } -export default importDump +export default loadInitialState diff --git a/src/main.ts b/src/main.ts index d5713fe..c6847f9 100644 --- a/src/main.ts +++ b/src/main.ts @@ -4,7 +4,20 @@ import {TypeormDatabase} from '@subsquid/typeorm-store' import {In} from 'typeorm' import {BASE_POOL_ACCOUNT} from './constants' import decodeEvents from './decodeEvents' -import importDump from './importDump' +import {getAccount} from './helper/account' +import { + createPool, + updateSharePrice, + updateStakePoolAprMultiplier, + updateStakePoolDelegable, +} from './helper/basePool' +import {updateDelegationValue} from './helper/delegation' +import {updateTokenomicParameters} from './helper/globalState' +import {queryIdentities} from './helper/identity' +import postUpdate from './helper/postUpdate' +import {isSnapshotUpdateNeeded, takeSnapshot} from './helper/snapshot' +import {updateSessionShares} from './helper/worker' +import loadInitialState from './loadInitialState' import { Account, BasePool, @@ -29,27 +42,13 @@ import { phalaVault, rmrkCore, } from './types/events' -import { - createPool, - updateSharePrice, - updateStakePoolAprMultiplier, - updateStakePoolDelegable, -} from './utils/basePool' -import {assertGet, getAccount, join, max, toMap} from './utils/common' -import {updateDelegationValue} from './utils/delegation' -import { - updateAverageBlockTime, - updateTokenomicParameters, -} from './utils/globalState' -import {queryIdentities} from './utils/identity' -import postUpdate from './utils/postUpdate' -import {updateWorkerShares} from './utils/worker' +import {assertGet, join, max, toMap} from './utils' processor.run(new TypeormDatabase(), async (ctx) => { if ((await ctx.store.get(GlobalState, '0')) == null) { - ctx.log.info('Importing dump') - await importDump(ctx) - ctx.log.info('Dump imported') + ctx.log.info('Loading initial state') + await loadInitialState(ctx) + ctx.log.info('Initial state loaded') } const events = decodeEvents(ctx) @@ -146,16 +145,27 @@ processor.run(new TypeormDatabase(), async (ctx) => { const accountMap: Map = await ctx.store .find(Account) .then(toMap) - const sessionMap = await ctx.store - .find(Session, { - where: [ - {id: In([...sessionIdSet])}, - {worker: {id: In([...workerIdSet])}}, - ], - relations: {stakePool: true, worker: true}, + const sessions = await ctx.store.find(Session, { + where: [{id: In([...sessionIdSet])}, {worker: {id: In([...workerIdSet])}}], + relations: {worker: true}, + }) + const sessionMap = toMap(sessions) + const workerSessionMap = toMap( + sessions.filter((s): s is Session & {worker: Worker} => s.worker != null), + (session) => session.worker.id, + ) + for (const session of sessions) { + if (session.worker) { + workerIdSet.add(session.worker.id) + } + } + const workerMap = await ctx.store + .find(Worker, { + where: [{id: In([...workerIdSet])}], + relations: {stakePool: true}, }) .then(toMap) - for (const {stakePool} of sessionMap.values()) { + for (const {stakePool} of workerMap.values()) { if (stakePool != null) { basePoolIdSet.add(stakePool.id) } @@ -163,13 +173,11 @@ processor.run(new TypeormDatabase(), async (ctx) => { const basePools = await ctx.store.find(BasePool, { relations: {owner: true, account: true}, }) - const basePoolMap = toMap(basePools) const basePoolAccountIdMap = toMap( basePools, (basePool) => basePool.account.id, ) - const stakePoolMap = await ctx.store .find(StakePool, {relations: {basePool: true}}) .then(toMap) @@ -179,15 +187,7 @@ processor.run(new TypeormDatabase(), async (ctx) => { relations: {basePool: true}, }) .then(toMap) - const workerMap = await ctx.store - .find(Worker, { - where: [ - {id: In([...workerIdSet])}, - {session: {id: In([...sessionIdSet])}}, - ], - relations: {stakePool: true, session: true}, - }) - .then(toMap) + const delegations = await ctx.store.find(Delegation, { relations: { account: true, @@ -210,9 +210,11 @@ processor.run(new TypeormDatabase(), async (ctx) => { }) .then(toMap) - for (const {name, args, block} of events) { + for (let i = 0; i < events.length; i++) { + const {name, args, block} = events[i] assert(block.timestamp) const blockTime = new Date(block.timestamp) + switch (name) { case phalaStakePoolv2.poolCreated.name: { const {pid, owner, cid, poolAccountId} = args @@ -227,10 +229,6 @@ processor.run(new TypeormDatabase(), async (ctx) => { basePoolMap.set(pid, basePool) basePoolAccountIdMap.set(poolAccountId, basePool) stakePoolMap.set(pid, stakePool) - await ctx.store.save(ownerAccount) - await ctx.store.insert(poolAccount) - await ctx.store.insert(basePool) - await ctx.store.insert(stakePool) break } case phalaStakePoolv2.poolCommissionSet.name: { @@ -253,12 +251,10 @@ processor.run(new TypeormDatabase(), async (ctx) => { const {pid, workerId} = args const stakePool = assertGet(stakePoolMap, pid) const worker = assertGet(workerMap, workerId) - assert(worker.session) // MEMO: SessionBound happens before PoolWorkerAdded - const session = assertGet(sessionMap, worker.session.id) + // MEMO: SessionBound happens before PoolWorkerAdded stakePool.workerCount++ globalState.workerCount++ worker.stakePool = stakePool - session.stakePool = stakePool break } case phalaStakePoolv2.poolWorkerRemoved.name: { @@ -274,9 +270,7 @@ processor.run(new TypeormDatabase(), async (ctx) => { case phalaStakePoolv2.workingStarted.name: { const {pid, workerId, amount} = args const basePool = assertGet(basePoolMap, pid) - const worker = assertGet(workerMap, workerId) - assert(worker.session) - const session = assertGet(sessionMap, worker.session.id) + const session = assertGet(workerSessionMap, workerId) session.stake = amount basePool.freeValue = basePool.freeValue.minus(amount) break @@ -325,22 +319,6 @@ processor.run(new TypeormDatabase(), async (ctx) => { updateStakePoolDelegable(basePool, stakePool) break } - case phalaStakePoolv2.workerReclaimed.name: { - const {pid, workerId} = args - const basePool = assertGet(basePoolMap, pid) - const worker = assertGet(workerMap, workerId) - assert(worker.session) - const session = assertGet(sessionMap, worker.session.id) - basePool.releasingValue = basePool.releasingValue.minus(session.stake) - // MEMO: freeValue is reset to 0 when pool is empty - if (basePool.totalShares.gt(0)) { - basePool.freeValue = basePool.freeValue.plus(session.stake) - } - session.state = WorkerState.Ready - session.coolingDownStartTime = null - session.stake = BigDecimal(0) - break - } case phalaBasePool.poolWhitelistCreated.name: { const {pid} = args const basePool = assertGet(basePoolMap, pid) @@ -388,10 +366,6 @@ processor.run(new TypeormDatabase(), async (ctx) => { basePoolMap.set(pid, basePool) basePoolAccountIdMap.set(poolAccountId, basePool) vaultMap.set(pid, vault) - await ctx.store.insert(poolAccount) - await ctx.store.save(ownerAccount) - await ctx.store.insert(basePool) - await ctx.store.insert(vault) break } case phalaVault.vaultCommissionSet.name: { @@ -409,7 +383,7 @@ processor.run(new TypeormDatabase(), async (ctx) => { updateSharePrice(basePool) vault.claimableOwnerShares = vault.claimableOwnerShares.plus(shares) vault.lastSharePriceCheckpoint = basePool.sharePrice - const rewards = shares.times(basePool.sharePrice).round(12, 0) + const rewards = shares.times(basePool.sharePrice) basePool.cumulativeOwnerRewards = basePool.cumulativeOwnerRewards.plus(rewards) owner.cumulativeVaultOwnerRewards = @@ -459,11 +433,9 @@ processor.run(new TypeormDatabase(), async (ctx) => { const prevShares = delegation.shares delegation.shares = shares.plus(delegation.withdrawingShares) updateDelegationValue(delegation, basePool) - delegation.cost = delegation.cost - .plus( - delegation.shares.minus(prevShares).times(basePool.sharePrice), - ) - .round(12, 0) + delegation.cost = delegation.cost.plus( + delegation.shares.minus(prevShares).times(basePool.sharePrice), + ) delegationMap.set(delegationId, delegation) } break @@ -484,9 +456,9 @@ processor.run(new TypeormDatabase(), async (ctx) => { basePool.withdrawingShares.minus(removedShares), BigDecimal(0), ) - basePool.withdrawingValue = basePool.withdrawingShares - .times(basePool.sharePrice) - .round(12, 0) + basePool.withdrawingValue = basePool.withdrawingShares.times( + basePool.sharePrice, + ) if (basePool.totalShares.eq(0)) { updateSharePrice(basePool) // MEMO: reset share price } @@ -523,9 +495,9 @@ processor.run(new TypeormDatabase(), async (ctx) => { basePool.withdrawingShares = basePool.withdrawingShares .minus(prevWithdrawingShares) .plus(shares) - basePool.withdrawingValue = basePool.withdrawingShares - .times(basePool.sharePrice) - .round(12, 0) + basePool.withdrawingValue = basePool.withdrawingShares.times( + basePool.sharePrice, + ) // Replace previous withdrawal delegation.withdrawingShares = shares delegation.withdrawalStartTime = blockTime @@ -550,7 +522,6 @@ processor.run(new TypeormDatabase(), async (ctx) => { if (session == null) { session = new Session({ id: sessionId, - isBound: true, state: WorkerState.Ready, v: BigDecimal(0), ve: BigDecimal(0), @@ -558,45 +529,43 @@ processor.run(new TypeormDatabase(), async (ctx) => { pInstant: 0, totalReward: BigDecimal(0), stake: BigDecimal(0), + shares: BigDecimal(0), }) sessionMap.set(sessionId, session) } - session.isBound = true session.worker = worker - worker.session = session + workerSessionMap.set(workerId, session as Session & {worker: Worker}) break } case phalaComputation.sessionUnbound.name: { const {sessionId, workerId} = args const session = assertGet(sessionMap, sessionId) - const worker = assertGet(workerMap, workerId) assert(session.worker) assert(session.worker.id === workerId) - worker.session = null - worker.shares = null - session.isBound = false + session.shares = BigDecimal(0) + session.worker = null + workerSessionMap.delete(workerId) break } case phalaComputation.sessionSettled.name: { const {sessionId, v, payout} = args const session = assertGet(sessionMap, sessionId) assert(session.worker) - assert(session.stakePool) session.totalReward = session.totalReward.plus(payout) session.v = v const worker = assertGet(workerMap, session.worker.id) - assert(worker.shares) - const basePool = assertGet(basePoolMap, session.stakePool.id) - const stakePool = assertGet(stakePoolMap, session.stakePool.id) - const prevShares = worker.shares - updateWorkerShares(worker, session) + assert(worker.stakePool) + const basePool = assertGet(basePoolMap, worker.stakePool.id) + const stakePool = assertGet(stakePoolMap, worker.stakePool.id) + const prevShares = session.shares + updateSessionShares(session, worker) if (session.state === WorkerState.WorkerIdle) { globalState.idleWorkerShares = globalState.idleWorkerShares .minus(prevShares) - .plus(worker.shares) + .plus(session.shares) stakePool.idleWorkerShares = stakePool.idleWorkerShares .minus(prevShares) - .plus(worker.shares) + .plus(session.shares) updateStakePoolAprMultiplier(basePool, stakePool) } break @@ -605,22 +574,22 @@ processor.run(new TypeormDatabase(), async (ctx) => { const {sessionId, initP, initV} = args const session = assertGet(sessionMap, sessionId) assert(session.worker) - assert(session.stakePool) - const basePool = assertGet(basePoolMap, session.stakePool.id) - const stakePool = assertGet(stakePoolMap, session.stakePool.id) + const worker = assertGet(workerMap, session.worker.id) + assert(worker.stakePool) + const basePool = assertGet(basePoolMap, worker.stakePool.id) + const stakePool = assertGet(stakePoolMap, worker.stakePool.id) stakePool.idleWorkerCount++ globalState.idleWorkerCount++ session.pInit = initP session.ve = initV session.v = initV session.state = WorkerState.WorkerIdle - const worker = assertGet(workerMap, session.worker.id) - updateWorkerShares(worker, session) + updateSessionShares(session, worker) globalState.idleWorkerShares = globalState.idleWorkerShares.plus( - worker.shares, + session.shares, ) stakePool.idleWorkerShares = stakePool.idleWorkerShares.plus( - worker.shares, + session.shares, ) updateStakePoolAprMultiplier(basePool, stakePool) break @@ -629,17 +598,16 @@ processor.run(new TypeormDatabase(), async (ctx) => { const {sessionId} = args const session = assertGet(sessionMap, sessionId) assert(session.worker) - assert(session.stakePool) - const basePool = assertGet(basePoolMap, session.stakePool.id) - const stakePool = assertGet(stakePoolMap, session.stakePool.id) const worker = assertGet(workerMap, session.worker.id) - assert(worker.shares) + assert(worker.stakePool) + const basePool = assertGet(basePoolMap, worker.stakePool.id) + const stakePool = assertGet(stakePoolMap, worker.stakePool.id) if (session.state === WorkerState.WorkerIdle) { globalState.idleWorkerShares = globalState.idleWorkerShares.minus( - worker.shares, + session.shares, ) stakePool.idleWorkerShares = stakePool.idleWorkerShares.minus( - worker.shares, + session.shares, ) updateStakePoolAprMultiplier(basePool, stakePool) stakePool.idleWorkerCount-- @@ -650,24 +618,37 @@ processor.run(new TypeormDatabase(), async (ctx) => { basePool.releasingValue = basePool.releasingValue.plus(session.stake) break } + case phalaComputation.workerReclaimed.name: { + const {sessionId} = args + const session = assertGet(sessionMap, sessionId) + assert(session.worker) + const worker = assertGet(workerMap, session.worker.id) + assert(worker.stakePool) + const basePool = assertGet(basePoolMap, worker.stakePool.id) + basePool.releasingValue = basePool.releasingValue.minus(session.stake) + basePool.freeValue = basePool.freeValue.plus(session.stake) + session.state = WorkerState.Ready + session.coolingDownStartTime = null + session.stake = BigDecimal(0) + break + } case phalaComputation.workerEnterUnresponsive.name: { const {sessionId} = args const session = assertGet(sessionMap, sessionId) assert(session.worker) - assert(session.stakePool) - const basePool = assertGet(basePoolMap, session.stakePool.id) - const stakePool = assertGet(stakePoolMap, session.stakePool.id) + const worker = assertGet(workerMap, session.worker.id) + assert(worker.stakePool) + const basePool = assertGet(basePoolMap, worker.stakePool.id) + const stakePool = assertGet(stakePoolMap, worker.stakePool.id) if (session.state === WorkerState.WorkerIdle) { session.state = WorkerState.WorkerUnresponsive stakePool.idleWorkerCount-- globalState.idleWorkerCount-- - const worker = assertGet(workerMap, session.worker.id) - assert(worker.shares) globalState.idleWorkerShares = globalState.idleWorkerShares.minus( - worker.shares, + session.shares, ) stakePool.idleWorkerShares = stakePool.idleWorkerShares.minus( - worker.shares, + session.shares, ) updateStakePoolAprMultiplier(basePool, stakePool) } @@ -677,19 +658,18 @@ processor.run(new TypeormDatabase(), async (ctx) => { const {sessionId} = args const session = assertGet(sessionMap, sessionId) assert(session.worker) - assert(session.stakePool) - const basePool = assertGet(basePoolMap, session.stakePool.id) - const stakePool = assertGet(stakePoolMap, session.stakePool.id) + const worker = assertGet(workerMap, session.worker.id) + assert(worker.stakePool) + const basePool = assertGet(basePoolMap, worker.stakePool.id) + const stakePool = assertGet(stakePoolMap, worker.stakePool.id) if (session.state === WorkerState.WorkerUnresponsive) { stakePool.idleWorkerCount++ globalState.idleWorkerCount++ - const worker = assertGet(workerMap, session.worker.id) - assert(worker.shares) globalState.idleWorkerShares = globalState.idleWorkerShares.plus( - worker.shares, + session.shares, ) stakePool.idleWorkerShares = stakePool.idleWorkerShares.plus( - worker.shares, + session.shares, ) updateStakePoolAprMultiplier(basePool, stakePool) } @@ -699,21 +679,21 @@ processor.run(new TypeormDatabase(), async (ctx) => { case phalaComputation.benchmarkUpdated.name: { const {sessionId, pInstant} = args const session = assertGet(sessionMap, sessionId) - session.pInstant = pInstant assert(session.worker) - assert(session.stakePool) const worker = assertGet(workerMap, session.worker.id) - const prevShares = worker.shares ?? BigDecimal(0) - updateWorkerShares(worker, session) + assert(worker.stakePool) + session.pInstant = pInstant + const prevShares = session.shares + updateSessionShares(session, worker) if (session.state === WorkerState.WorkerIdle) { globalState.idleWorkerShares = globalState.idleWorkerShares .minus(prevShares) - .plus(worker.shares) - const basePool = assertGet(basePoolMap, session.stakePool.id) - const stakePool = assertGet(stakePoolMap, session.stakePool.id) + .plus(session.shares) + const basePool = assertGet(basePoolMap, worker.stakePool.id) + const stakePool = assertGet(stakePoolMap, worker.stakePool.id) stakePool.idleWorkerShares = stakePool.idleWorkerShares .minus(prevShares) - .plus(worker.shares) + .plus(session.shares) updateStakePoolAprMultiplier(basePool, stakePool) } break @@ -726,7 +706,6 @@ processor.run(new TypeormDatabase(), async (ctx) => { const {workerId, confidenceLevel} = args const worker = new Worker({id: workerId, confidenceLevel}) workerMap.set(workerId, worker) - await ctx.store.insert(worker) break } case phalaRegistry.workerUpdated.name: { @@ -762,7 +741,29 @@ processor.run(new TypeormDatabase(), async (ctx) => { break } } - updateAverageBlockTime(block, globalState) + + const nextEvent = events[i + 1] + const isLastEvent = nextEvent == null + const isLastEventInBlock = + isLastEvent || block.height !== nextEvent.block.height + const shouldTakeSnapshot = + isLastEventInBlock && isSnapshotUpdateNeeded(block, globalState) + if (isLastEvent) { + postUpdate(block, globalState, accountMap, basePoolMap, delegations) + } + if (shouldTakeSnapshot) { + // await takeSnapshot( + // ctx, + // block, + // globalState, + // accountMap, + // basePoolMap, + // stakePoolMap, + // workerMap, + // sessionMap, + // delegations, + // ) + } } if (Bun.env.REFRESH_IDENTITY === '1') { @@ -780,23 +781,19 @@ processor.run(new TypeormDatabase(), async (ctx) => { ) } - await postUpdate( - ctx, - globalState, - accountMap, - basePools, - stakePoolMap, - delegations, + ctx.log.info( + `Saving state from ${ctx.blocks[0].header.height} to ${ + ctx.blocks[ctx.blocks.length - 1].header.height + }`, ) - for (const x of [ globalState, accountMap, basePoolMap, stakePoolMap, vaultMap, - sessionMap, workerMap, + sessionMap, nftMap, delegationMap, basePoolWhitelistMap, diff --git a/src/model/generated/accountSnapshot.model.ts b/src/model/generated/accountSnapshot.model.ts index bd70cb1..6a8bbd4 100644 --- a/src/model/generated/accountSnapshot.model.ts +++ b/src/model/generated/accountSnapshot.model.ts @@ -1,7 +1,6 @@ import {BigDecimal} from "@subsquid/big-decimal" -import {Entity as Entity_, Column as Column_, PrimaryColumn as PrimaryColumn_, Index as Index_, ManyToOne as ManyToOne_} from "typeorm" +import {Entity as Entity_, Column as Column_, PrimaryColumn as PrimaryColumn_, Index as Index_} from "typeorm" import * as marshal from "./marshal" -import {Account} from "./account.model" @Index_(["account", "updatedTime"], {unique: true}) @Entity_() @@ -19,8 +18,8 @@ export class AccountSnapshot { @Column_("timestamp with time zone", {nullable: false}) updatedTime!: Date - @ManyToOne_(() => Account, {nullable: true}) - account!: Account + @Column_("text", {nullable: false}) + account!: string @Column_("numeric", {transformer: marshal.bigdecimalTransformer, nullable: false}) delegationValue!: BigDecimal diff --git a/src/model/generated/basePoolSnapshot.model.ts b/src/model/generated/basePoolSnapshot.model.ts index 5fef4e4..cd4442d 100644 --- a/src/model/generated/basePoolSnapshot.model.ts +++ b/src/model/generated/basePoolSnapshot.model.ts @@ -1,7 +1,6 @@ import {BigDecimal} from "@subsquid/big-decimal" -import {Entity as Entity_, Column as Column_, PrimaryColumn as PrimaryColumn_, Index as Index_, ManyToOne as ManyToOne_} from "typeorm" +import {Entity as Entity_, Column as Column_, PrimaryColumn as PrimaryColumn_, Index as Index_} from "typeorm" import * as marshal from "./marshal" -import {BasePool} from "./basePool.model" @Index_(["basePool", "updatedTime"], {unique: true}) @Entity_() @@ -19,8 +18,8 @@ export class BasePoolSnapshot { @Column_("timestamp with time zone", {nullable: false}) updatedTime!: Date - @ManyToOne_(() => BasePool, {nullable: true}) - basePool!: BasePool + @Column_("text", {nullable: false}) + basePool!: string @Column_("numeric", {transformer: marshal.bigdecimalTransformer, nullable: false}) commission!: BigDecimal @@ -28,6 +27,9 @@ export class BasePoolSnapshot { @Column_("numeric", {transformer: marshal.bigdecimalTransformer, nullable: false}) apr!: BigDecimal + @Column_("numeric", {transformer: marshal.bigdecimalTransformer, nullable: false}) + totalShares!: BigDecimal + @Column_("numeric", {transformer: marshal.bigdecimalTransformer, nullable: false}) totalValue!: BigDecimal diff --git a/src/model/generated/delegation.model.ts b/src/model/generated/delegation.model.ts index b52bcdd..18706b9 100644 --- a/src/model/generated/delegation.model.ts +++ b/src/model/generated/delegation.model.ts @@ -1,10 +1,9 @@ import {BigDecimal} from "@subsquid/big-decimal" -import {Entity as Entity_, Column as Column_, PrimaryColumn as PrimaryColumn_, Index as Index_, ManyToOne as ManyToOne_, OneToOne as OneToOne_, JoinColumn as JoinColumn_, OneToMany as OneToMany_} from "typeorm" +import {Entity as Entity_, Column as Column_, PrimaryColumn as PrimaryColumn_, Index as Index_, ManyToOne as ManyToOne_, OneToOne as OneToOne_, JoinColumn as JoinColumn_} from "typeorm" import * as marshal from "./marshal" import {Account} from "./account.model" import {BasePool} from "./basePool.model" import {Nft} from "./nft.model" -import {DelegationSnapshot} from "./delegationSnapshot.model" @Index_(["basePool", "account"], {unique: true}) @Entity_() @@ -52,7 +51,4 @@ export class Delegation { @Index_() @ManyToOne_(() => Nft, {nullable: true}) withdrawalNft!: Nft | undefined | null - - @OneToMany_(() => DelegationSnapshot, e => e.delegation) - snapshots!: DelegationSnapshot[] } diff --git a/src/model/generated/delegationSnapshot.model.ts b/src/model/generated/delegationSnapshot.model.ts index 8b2cbfd..0ea9486 100644 --- a/src/model/generated/delegationSnapshot.model.ts +++ b/src/model/generated/delegationSnapshot.model.ts @@ -1,7 +1,6 @@ import {BigDecimal} from "@subsquid/big-decimal" -import {Entity as Entity_, Column as Column_, PrimaryColumn as PrimaryColumn_, Index as Index_, ManyToOne as ManyToOne_} from "typeorm" +import {Entity as Entity_, Column as Column_, PrimaryColumn as PrimaryColumn_, Index as Index_} from "typeorm" import * as marshal from "./marshal" -import {Delegation} from "./delegation.model" @Index_(["delegation", "updatedTime"], {unique: true}) @Entity_() @@ -19,8 +18,8 @@ export class DelegationSnapshot { @Column_("timestamp with time zone", {nullable: false}) updatedTime!: Date - @ManyToOne_(() => Delegation, {nullable: true}) - delegation!: Delegation + @Column_("text", {nullable: false}) + delegation!: string @Column_("numeric", {transformer: marshal.bigdecimalTransformer, nullable: false}) cost!: BigDecimal diff --git a/src/model/generated/session.model.ts b/src/model/generated/session.model.ts index 68ca227..6a1faef 100644 --- a/src/model/generated/session.model.ts +++ b/src/model/generated/session.model.ts @@ -1,7 +1,6 @@ import {BigDecimal} from "@subsquid/big-decimal" -import {Entity as Entity_, Column as Column_, PrimaryColumn as PrimaryColumn_, ManyToOne as ManyToOne_, Index as Index_} from "typeorm" +import {Entity as Entity_, Column as Column_, PrimaryColumn as PrimaryColumn_, OneToOne as OneToOne_, Index as Index_, JoinColumn as JoinColumn_} from "typeorm" import * as marshal from "./marshal" -import {StakePool} from "./stakePool.model" import {Worker} from "./worker.model" import {WorkerState} from "./_workerState" @@ -17,15 +16,9 @@ export class Session { @PrimaryColumn_() id!: string - @Column_("bool", {nullable: false}) - isBound!: boolean - - @Index_() - @ManyToOne_(() => StakePool, {nullable: true}) - stakePool!: StakePool | undefined | null - - @Index_() - @ManyToOne_(() => Worker, {nullable: true}) + @Index_({unique: true}) + @OneToOne_(() => Worker, {nullable: true}) + @JoinColumn_() worker!: Worker | undefined | null @Column_("numeric", {transformer: marshal.bigdecimalTransformer, nullable: false}) @@ -51,4 +44,7 @@ export class Session { @Column_("timestamp with time zone", {nullable: true}) coolingDownStartTime!: Date | undefined | null + + @Column_("numeric", {transformer: marshal.bigdecimalTransformer, nullable: false}) + shares!: BigDecimal } diff --git a/src/model/generated/worker.model.ts b/src/model/generated/worker.model.ts index 81f6c54..70e94f4 100644 --- a/src/model/generated/worker.model.ts +++ b/src/model/generated/worker.model.ts @@ -1,6 +1,4 @@ -import {BigDecimal} from "@subsquid/big-decimal" import {Entity as Entity_, Column as Column_, PrimaryColumn as PrimaryColumn_, ManyToOne as ManyToOne_, Index as Index_} from "typeorm" -import * as marshal from "./marshal" import {StakePool} from "./stakePool.model" import {Session} from "./session.model" @@ -20,16 +18,10 @@ export class Worker { @ManyToOne_(() => StakePool, {nullable: true}) stakePool!: StakePool | undefined | null - @Index_() - @ManyToOne_(() => Session, {nullable: true}) - session!: Session | undefined | null @Column_("int4", {nullable: false}) confidenceLevel!: number @Column_("int4", {nullable: true}) initialScore!: number | undefined | null - - @Column_("numeric", {transformer: marshal.bigdecimalTransformer, nullable: true}) - shares!: BigDecimal | undefined | null } diff --git a/src/model/generated/workerSnapshot.model.ts b/src/model/generated/workerSnapshot.model.ts index c2b22a8..2277f67 100644 --- a/src/model/generated/workerSnapshot.model.ts +++ b/src/model/generated/workerSnapshot.model.ts @@ -1,7 +1,6 @@ import {BigDecimal} from "@subsquid/big-decimal" -import {Entity as Entity_, Column as Column_, PrimaryColumn as PrimaryColumn_, Index as Index_, ManyToOne as ManyToOne_} from "typeorm" +import {Entity as Entity_, Column as Column_, PrimaryColumn as PrimaryColumn_, Index as Index_} from "typeorm" import * as marshal from "./marshal" -import {Worker} from "./worker.model" import {WorkerState} from "./_workerState" @Index_(["worker", "updatedTime"], {unique: true}) @@ -20,14 +19,14 @@ export class WorkerSnapshot { @Column_("timestamp with time zone", {nullable: false}) updatedTime!: Date - @ManyToOne_(() => Worker, {nullable: true}) - worker!: Worker + @Column_("text", {nullable: false}) + worker!: string - @Column_("text", {nullable: true}) - stakePoolId!: string | undefined | null + @Column_("text", {nullable: false}) + stakePool!: string - @Column_("text", {nullable: true}) - sessionId!: string | undefined | null + @Column_("text", {nullable: false}) + session!: string @Column_("int4", {nullable: false}) confidenceLevel!: number @@ -35,24 +34,24 @@ export class WorkerSnapshot { @Column_("int4", {nullable: true}) initialScore!: number | undefined | null - @Column_("numeric", {transformer: marshal.bigdecimalTransformer, nullable: true}) - stake!: BigDecimal | undefined | null + @Column_("numeric", {transformer: marshal.bigdecimalTransformer, nullable: false}) + stake!: BigDecimal - @Column_("varchar", {length: 18, nullable: true}) - state!: WorkerState | undefined | null + @Column_("varchar", {length: 18, nullable: false}) + state!: WorkerState - @Column_("numeric", {transformer: marshal.bigdecimalTransformer, nullable: true}) - v!: BigDecimal | undefined | null + @Column_("numeric", {transformer: marshal.bigdecimalTransformer, nullable: false}) + v!: BigDecimal - @Column_("numeric", {transformer: marshal.bigdecimalTransformer, nullable: true}) - ve!: BigDecimal | undefined | null + @Column_("numeric", {transformer: marshal.bigdecimalTransformer, nullable: false}) + ve!: BigDecimal - @Column_("int4", {nullable: true}) - pInit!: number | undefined | null + @Column_("int4", {nullable: false}) + pInit!: number - @Column_("int4", {nullable: true}) - pInstant!: number | undefined | null + @Column_("int4", {nullable: false}) + pInstant!: number - @Column_("numeric", {transformer: marshal.bigdecimalTransformer, nullable: true}) - totalReward!: BigDecimal | undefined | null + @Column_("numeric", {transformer: marshal.bigdecimalTransformer, nullable: false}) + totalReward!: BigDecimal } diff --git a/src/processor.ts b/src/processor.ts index 1858f20..8bcb00d 100644 --- a/src/processor.ts +++ b/src/processor.ts @@ -7,7 +7,7 @@ import { assertNotNull, } from '@subsquid/substrate-processor' import {type Store} from '@subsquid/typeorm-store' -import {DUMP_BLOCK} from './constants' +import {INITIAL_BLOCK} from './constants' import { identity, phalaBasePool, @@ -22,7 +22,7 @@ export const processor = new SubstrateBatchProcessor() .setGateway(lookupArchive('khala', {release: 'ArrowSquid'})) .setRpcEndpoint(assertNotNull(Bun.env.RPC_ENDPOINT)) .setBlockRange({ - from: DUMP_BLOCK + 1, + from: INITIAL_BLOCK + 1, to: Bun.env.TO_BLOCK != null ? parseInt(Bun.env.TO_BLOCK) : undefined, }) .includeAllBlocks() diff --git a/src/utils/converter.ts b/src/utils.ts similarity index 52% rename from src/utils/converter.ts rename to src/utils.ts index 1b008cc..b270dac 100644 --- a/src/utils/converter.ts +++ b/src/utils.ts @@ -1,7 +1,31 @@ +import assert from 'assert' import {BigDecimal} from '@subsquid/big-decimal' import * as ss58 from '@subsquid/ss58' import {isHex} from '@subsquid/util-internal-hex' +export const assertGet = (map: Map, key: U): T => { + const value = map.get(key) + assert(value) + return value +} + +export const join = (...args: Array): string => + args.map((x) => x.toString()).join('-') + +export const toMap = ( + a: T[], + fn: (a: T) => string = (a) => a.id, +): Map => new Map(a.map((a) => [fn(a), a])) + +export const max = (a: BigDecimal, b: BigDecimal): BigDecimal => + a.gt(b) ? a : b + +export const min = (a: BigDecimal, b: BigDecimal): BigDecimal => + a.lt(b) ? a : b + +export const sum = (...args: BigDecimal[]): BigDecimal => + args.reduce((a, b) => a.plus(b), BigDecimal(0)) + export type JsonBigInt = string | number // Polkadot.js toJSON() BigInt type export const toBigDecimal = (value: JsonBigInt | bigint): BigDecimal => { @@ -17,7 +41,9 @@ export const toBalance = (value: JsonBigInt | bigint): BigDecimal => // divide by 2^64 export const fromBits = (value: JsonBigInt | bigint): BigDecimal => - toBigDecimal(value).div('18446744073709551616').round(6, 0) + toBigDecimal(value) + .div(2n ** 64n) + .round(6) export const encodeAddress = (bytes: ss58.Bytes | Uint8Array): string => ss58.codec('phala').encode(bytes) diff --git a/src/utils/common.ts b/src/utils/common.ts deleted file mode 100644 index ab392b5..0000000 --- a/src/utils/common.ts +++ /dev/null @@ -1,45 +0,0 @@ -import assert from 'assert' -import {BigDecimal} from '@subsquid/big-decimal' -import {Account} from '../model' - -export const getAccount = (m: Map, id: string): Account => { - let acc = m.get(id) - if (acc == null) { - acc = new Account({ - id, - stakePoolValue: BigDecimal(0), - stakePoolNftCount: 0, - stakePoolAvgAprMultiplier: BigDecimal(0), - vaultValue: BigDecimal(0), - vaultNftCount: 0, - vaultAvgAprMultiplier: BigDecimal(0), - cumulativeStakePoolOwnerRewards: BigDecimal(0), - cumulativeVaultOwnerRewards: BigDecimal(0), - }) - m.set(id, acc) - } - return acc -} - -export const assertGet = (map: Map, key: U): T => { - const value = map.get(key) - assert(value) - return value -} - -export const join = (...args: Array): string => - args.map((x) => x.toString()).join('-') - -export const toMap = ( - a: T[], - fn: (a: T) => string = (a) => a.id, -): Map => new Map(a.map((a) => [fn(a), a])) - -export const max = (a: BigDecimal, b: BigDecimal): BigDecimal => - a.gt(b) ? a : b - -export const min = (a: BigDecimal, b: BigDecimal): BigDecimal => - a.lt(b) ? a : b - -export const sum = (...args: BigDecimal[]): BigDecimal => - args.reduce((a, b) => a.plus(b), BigDecimal(0)) diff --git a/src/utils/snapshot.ts b/src/utils/snapshot.ts deleted file mode 100644 index f70beb6..0000000 --- a/src/utils/snapshot.ts +++ /dev/null @@ -1,129 +0,0 @@ -import {type BigDecimal} from '@subsquid/big-decimal' -import { - type Account, - AccountSnapshot, - type BasePool, - BasePoolSnapshot, - type Delegation, - DelegationSnapshot, - type GlobalState, - GlobalStateSnapshot, - type StakePool, - type Worker, - WorkerSnapshot, -} from '../model' -import {join} from './common' - -export const createAccountSnapshot = ({ - account, - updatedTime, -}: { - account: Account - updatedTime: Date -}): AccountSnapshot => { - const date = new Date(updatedTime) - date.setUTCHours(0, 0, 0, 0) - return new AccountSnapshot({ - id: join(account.id, date.toISOString()), - account, - delegationValue: account.vaultValue - .plus(account.stakePoolValue) - .round(2, 0), - updatedTime: date, - cumulativeStakePoolOwnerRewards: - account.cumulativeStakePoolOwnerRewards.round(2, 0), - cumulativeVaultOwnerRewards: account.cumulativeVaultOwnerRewards.round( - 2, - 0, - ), - }) -} - -export const createBasePoolSnapshot = ({ - basePool, - updatedTime, - apr, - stakePool, -}: { - basePool: BasePool - updatedTime: Date - apr: BigDecimal - stakePool?: StakePool -}): BasePoolSnapshot => { - return new BasePoolSnapshot({ - id: join(basePool.id, updatedTime.toISOString()), - basePool, - commission: basePool.commission, - totalValue: basePool.totalValue.round(2, 0), - sharePrice: basePool.sharePrice, - delegatorCount: basePool.delegatorCount, - apr, - updatedTime, - workerCount: stakePool?.workerCount, - idleWorkerCount: stakePool?.idleWorkerCount, - stakePoolCount: - stakePool == null ? basePool.account.stakePoolNftCount : undefined, - cumulativeOwnerRewards: basePool.cumulativeOwnerRewards.round(2, 0), - }) -} - -export const createDelegationSnapshot = ({ - delegation, - updatedTime, -}: { - delegation: Delegation - updatedTime: Date -}): DelegationSnapshot => { - return new DelegationSnapshot({ - id: join(delegation.id, updatedTime.toISOString()), - delegation, - cost: delegation.cost.round(2, 0), - value: delegation.value.round(2, 0), - updatedTime, - }) -} - -export const createWorkerSnapshot = ({ - worker, - updatedTime, -}: { - worker: Worker - updatedTime: Date -}): WorkerSnapshot => { - return new WorkerSnapshot({ - id: join(worker.id, updatedTime.toISOString()), - updatedTime, - worker, - stakePoolId: worker.stakePool?.id, - sessionId: worker.session?.id, - confidenceLevel: worker.confidenceLevel, - initialScore: worker.initialScore, - stake: worker.session?.stake.round(2, 0), - state: worker.session?.state, - v: worker.session?.v.round(2, 0), - ve: worker.session?.ve.round(2, 0), - pInit: worker.session?.pInit, - pInstant: worker.session?.pInstant, - totalReward: worker.session?.totalReward.round(2, 0), - }) -} - -export const createGlobalStateSnapshot = ( - globalState: GlobalState, - updatedTime: Date, -): GlobalStateSnapshot => { - return new GlobalStateSnapshot({ - id: updatedTime.toISOString(), - updatedTime, - totalValue: globalState.totalValue, - averageBlockTime: globalState.averageBlockTime, - averageApr: globalState.averageApr, - cumulativeRewards: globalState.cumulativeRewards, - budgetPerBlock: globalState.budgetPerBlock, - workerCount: globalState.workerCount, - idleWorkerCount: globalState.idleWorkerCount, - budgetPerShare: globalState.budgetPerShare, - delegatorCount: globalState.delegatorCount, - idleWorkerShares: globalState.idleWorkerShares, - }) -}