From 314c1ea547f8af663ff651e4ab9063b130ed0a22 Mon Sep 17 00:00:00 2001 From: fwaszkiewicz Date: Fri, 11 Jul 2025 11:07:26 +0200 Subject: [PATCH 01/11] Run tests in multiple workers --- __tests__/assets/jest-helper.ts | 33 ++++++++++++++++++++++++++--- __tests__/detailed/bot_events.ts | 21 ------------------ __tests__/detailed/bot_providers.ts | 21 ------------------ package.json | 2 +- playwright.config.ts | 1 + 5 files changed, 32 insertions(+), 46 deletions(-) diff --git a/__tests__/assets/jest-helper.ts b/__tests__/assets/jest-helper.ts index 37a4160..df1dea0 100644 --- a/__tests__/assets/jest-helper.ts +++ b/__tests__/assets/jest-helper.ts @@ -1,4 +1,5 @@ -import { Page, test as base, expect } from "@playwright/test"; +/* eslint-disable no-console */ +import { ConsoleMessage, Page, test as base, expect } from "@playwright/test"; import "./globals"; import { IWorkerBee } from "../../dist/bundle"; @@ -6,7 +7,11 @@ import type { IWorkerBeeGlobals, TEnvType } from "./globals"; type TWorkerBeeTestCallable = (globals: IWorkerBeeGlobals, ...args: Args) => (R | Promise); -export interface IWorkerBeeTest { +interface IWorkerBeeTestPlaywright { + forEachTest: void; +} + +export interface IWorkerBeeFixtureMethods { /** * Runs given function in both environments: web and Node.js * Created specifically for testing the wax code - base and chain @@ -29,6 +34,12 @@ export interface IWorkerBeeTest { ) => Promise; } +export interface IWorkerBeeTest extends IWorkerBeeFixtureMethods, IWorkerBeeTestPlaywright {} + +interface IWorkerBeeWorker { + forEachWorker: void; +} + const envTestFor = ( page: Page, globalFunction: (env: TEnvType) => Promise @@ -85,7 +96,23 @@ const createWorkerBeeTest = async >( }, callback.toString()); } -export const test = base.extend({ +export const test = base.extend({ + forEachTest: [async ({ page }, use, ) => { + page.on("console", (msg: ConsoleMessage) => { + console.log(">>", msg.type(), msg.text()); + }); + + await page.goto("http://localhost:8080/__tests__/assets/test.html", { waitUntil: "load" }); + + await use(); + }, { auto: true }], + + forEachWorker: [async ({ browser }, use) => { + await use(); + + await browser.close(); + }, { scope: "worker", auto: true }], + workerbeeTest: ({ page }, use) => { use(envTestFor(page, createTestFor)); }, diff --git a/__tests__/detailed/bot_events.ts b/__tests__/detailed/bot_events.ts index 9a6267d..c2b01e1 100644 --- a/__tests__/detailed/bot_events.ts +++ b/__tests__/detailed/bot_events.ts @@ -1,31 +1,14 @@ /* eslint-disable no-console */ import { expect } from "@playwright/test"; -import { ChromiumBrowser, ConsoleMessage, chromium } from "playwright"; import type { IStartConfiguration } from "../../src/bot"; import { test } from "../assets/jest-helper"; -let browser!: ChromiumBrowser; - const HIVE_BLOCK_INTERVAL = 3000; test.describe("WorkerBee Bot events test", () => { - test.beforeAll(async() => { - browser = await chromium.launch({ - headless: true - }); - }); - - test.beforeEach(async({ page }) => { - page.on("console", (msg: ConsoleMessage) => { - console.log(">>", msg.type(), msg.text()); - }); - - await page.goto("http://localhost:8080/__tests__/assets/test.html", { waitUntil: "load" }); - }); - test("Should have a destroyable global module", async({ workerbeeTest }) => { await workerbeeTest(({ WorkerBee }) => { const bot = new WorkerBee(); @@ -1122,8 +1105,4 @@ test.describe("WorkerBee Bot events test", () => { // This might not trigger in test environment, so we just check it doesn't throw expect(typeof result).toBe("boolean"); }); - - test.afterAll(async() => { - await browser.close(); - }); }); diff --git a/__tests__/detailed/bot_providers.ts b/__tests__/detailed/bot_providers.ts index 2b5ae25..8f5d4fd 100644 --- a/__tests__/detailed/bot_providers.ts +++ b/__tests__/detailed/bot_providers.ts @@ -1,25 +1,8 @@ /* eslint-disable no-console */ -import { ChromiumBrowser, ConsoleMessage, chromium } from "playwright"; import { expect } from "playwright/test"; import { test } from "../assets/jest-helper"; -let browser!: ChromiumBrowser; - test.describe("Bot Providers", () => { - test.beforeAll(async() => { - browser = await chromium.launch({ - headless: true - }); - }); - - test.beforeEach(async({ page }) => { - page.on("console", (msg: ConsoleMessage) => { - console.log(">>", msg.type(), msg.text()); - }); - - await page.goto("http://localhost:8080/__tests__/assets/test.html", { waitUntil: "load" }); - }); - test("Should be able to provide witnesses", async({ createWorkerBeeTest }) => { const result = await createWorkerBeeTest((bot, resolve, reject) => { const observer = bot.observe.onBlock().provideWitnesses("gtg"); @@ -381,8 +364,4 @@ test.describe("Bot Providers", () => { expect(result.rcAccounts["gtg"].name).toBe("gtg"); expect(result.rcAccounts["blocktrades"].name).toBe("blocktrades"); }); - - test.afterAll(async() => { - await browser.close(); - }); }); diff --git a/package.json b/package.json index 20e1c0e..1ccbefe 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "build": "tsc", "postbuild": "rollup -c && tsx ./npm-common-config/ts-common/terser.ts && size-limit", "pretest": "playwright install chromium", - "test": "unset CI && playwright test --workers 1 --max-failures 1 --project=workerbee_testsuite" + "test": "unset CI && playwright test --workers 4 --max-failures 1 --project=workerbee_testsuite" }, "size-limit": [ { diff --git a/playwright.config.ts b/playwright.config.ts index a7a71a6..29b508f 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -2,6 +2,7 @@ import { defineConfig } from "@playwright/test"; export default defineConfig({ + fullyParallel: true, reporter: [ [ "junit", { outputFile: "results.xml" } ], [ "json", { outputFile: "results.json" } ] -- GitLab From e5f85d0f98259d26986b1d940bf9e426ae296af9 Mon Sep 17 00:00:00 2001 From: fwaszkiewicz Date: Mon, 14 Jul 2025 09:46:22 +0200 Subject: [PATCH 02/11] Extend mock tests plan --- .../detailed/complex_scenarios_test_plan.md | 91 ++++++++++++++++++- 1 file changed, 88 insertions(+), 3 deletions(-) diff --git a/__tests__/detailed/complex_scenarios_test_plan.md b/__tests__/detailed/complex_scenarios_test_plan.md index 3fcaf41..cafcef7 100644 --- a/__tests__/detailed/complex_scenarios_test_plan.md +++ b/__tests__/detailed/complex_scenarios_test_plan.md @@ -1,5 +1,91 @@ # Test Plan - Complex WorkerBee Usage Scenarios +## Individual Filter Verification Scenarios + +### 1. onPosts Filter Tests + +#### 1.1 onPosts Positive Cases +```typescript +// Multiple accounts - should trigger when any specified account creates post +bot.observe.onPosts("author1", "author2", "author3") + +// Simultaneous posts - should trigger for all accounts posting in same block +bot.observe.onPosts("author1", "author2") // Both post in block N +``` + +#### 1.2 onPosts Negative Cases +```typescript +// Should NOT trigger when account creates comment +bot.observe.onPosts("test-author") // test-author creates comment, not post + +// Multiple accounts - should NOT trigger when any specified account creates comment, not post +bot.observe.onPosts("author1", "author2", "author3") + +// Monitor for posts from a specific account - should NOT trigger as the account created no posts +bot.observe.onPosts("nonexistent-account") + +// Should handle empty account list +bot.observe.onPosts() +``` + +### 2. onComments Filter Tests + +#### 2.1 onComments Positive Cases +```typescript +// Multiple accounts - should trigger when any specified account creates comment +bot.observe.onComments("commenter1", "commenter2", "commenter3") + +// Simultaneous comments - should trigger for all accounts commenting in same block +bot.observe.onComments("commenter1", "commenter2") // Both comment in block N +``` + +#### 2.2 onComments Negative Cases +```typescript +// Should NOT trigger when account creates post +bot.observe.onComments("test-commenter") // test-commenter creates post, not comment + +// Multiple accounts - should NOT trigger when any specified account creates post, not comment +bot.observe.onComments("author1", "author2", "author3") + +// Monitor for comments from a specific account - should NOT trigger as the account created no comments +bot.observe.onComments("nonexistent-account") + +// Should handle empty account list +bot.observe.onComments() +``` + +#### 2.3 onPosts and onComments cases +```typescript +// Multiple accounts - should trigger when any specified account creates post or comment +bot.observe.onComments("test-commenter").or.onPosts("test-poster") +``` + +### 3. onVotes Filter Tests + +#### 3.1 onVotes Positive Cases +```typescript +// Multiple voters - should trigger when any specified account votes +bot.observe.onVotes("voter1", "voter2", "voter3") + +// Simultaneous votes - should trigger for all accounts voting in same block +bot.observe.onVotes("voter1", "voter2") // Both vote in block N +``` + +#### 3.2 onVotes Negative Cases +```typescript +// Should NOT trigger when account creates post/comment +bot.observe.onVotes("test-voter") // test-voter posts or comments, doesn't vote + +// Should NOT trigger when different account votes +bot.observe.onVotes("voter1") // voter2 votes, not voter1 + +// Monitor for votes from a specific account - should NOT trigger as the account did not vote +bot.observe.onVotes("nonexistent-account") + +// Should handle empty account list +bot.observe.onVotes() +``` + ## Realistic Test Scenarios ### 1. Scenarios with OR operator @@ -25,7 +111,7 @@ bot.observe.onWhaleAlert(hiveCoins(1000)).or.onInternalMarketOperation().or.onEx #### 1.4 Content Engagement Tracker ```typescript // Tracks content engagement -bot.observe.onMention("brand").or.onComments("brand").or.onReblog("brand") +bot.observe.onMention("brand").or.onPosts("brand").or.onReblog("brand") ``` #### 1.5 Cross-Platform Activity Monitor @@ -155,7 +241,7 @@ bot.observe.onFeedPriceChange(5) .provideFeedPriceData() ``` -#### 3.4 Community Moderation Bot +#### 3.4 Community Moderation Bot (TODO after `onCommunityPost` implementation) ```typescript // Community moderation monitoring bot.observe.onPosts("community-tag") @@ -179,7 +265,6 @@ bot.observe.onAccountsBalanceChange(true, "investor1", "investor2") bot.observe.onPosts("news-account1") .or.onPosts("news-account2") .or.onReblog("aggregator-account") - .or.onCustomOperation("cross-post") ``` #### 3.7 Engagement Optimization Bot -- GitLab From 316f3b4e8423901616c58de4ab5d62dfd262c51d Mon Sep 17 00:00:00 2001 From: fwaszkiewicz Date: Mon, 14 Jul 2025 13:12:49 +0200 Subject: [PATCH 03/11] Add individual filter tests --- __tests__/detailed/individual_filter_tests.ts | 611 ++++++++++++++++++ __tests__/index.spec.ts | 1 + 2 files changed, 612 insertions(+) create mode 100644 __tests__/detailed/individual_filter_tests.ts diff --git a/__tests__/detailed/individual_filter_tests.ts b/__tests__/detailed/individual_filter_tests.ts new file mode 100644 index 0000000..972c606 --- /dev/null +++ b/__tests__/detailed/individual_filter_tests.ts @@ -0,0 +1,611 @@ +/* eslint-disable no-console */ +import { expect } from "@playwright/test"; +import { test } from "../assets/jest-helper"; + +test.describe("WorkerBee Individual Filter Verification", () => { + test("1.1 - Should trigger when any specified account creates post - multiple accounts", async({ createWorkerBeeTest }) => { + const result = await createWorkerBeeTest((bot, resolve, reject) => { + const capturedPosts: string[] = []; + + bot.providePastOperations(96549390, 96549415).onPosts("mtyszczak", "author2", "author3").subscribe({ + next(data) { + for (const author of ["mtyszczak", "author2", "author3"]) + data.posts[author]?.forEach(({ operation }) => { + capturedPosts.push(`Post by ${operation.author}: ${operation.permlink}`); + }); + }, + error(err) { + console.error(err); + reject(err); + }, + complete: () => resolve(capturedPosts) + }); + }); + + expect(result).toEqual(["Post by mtyszczak: hi-ve-everyone"]); + }); + + test("1.1 - Should trigger for simultaneous posts from multiple accounts in same block", async({ createWorkerBeeTest }) => { + const result = await createWorkerBeeTest((bot, resolve, reject) => { + const capturedPosts: Array<{ author: string; blockNumber: number }> = []; + + bot.providePastOperations(97632050, 97632075).onBlock().or.onPosts("comandoyeya", "daddydog").subscribe({ + next(data) { + for (const author of ["comandoyeya", "daddydog"]) + data.posts[author]?.forEach(({ operation }) => { + capturedPosts.push({ + author: operation.author, + blockNumber: data.block.number + }); + }); + + }, + error(err) { + console.error(err); + reject(err); + }, + complete: () => resolve(capturedPosts) + }); + }); + + expect(result).toEqual([ + { + author: "comandoyeya", + blockNumber: 97632067 + }, + { + author: "daddydog", + blockNumber: 97632067 + } + ]); + }); + + test("1.2 - Should NOT trigger when account creates comment instead of post", async({ createWorkerBeeTest }) => { + const result = await createWorkerBeeTest((bot, resolve, reject) => { + let postsDetected = 0; + let commentsDetected = 0; + + /* + * Monitor an account known to create comments in this range. + * Also check for comments in the same range to verify account was active + */ + bot.providePastOperations(96549690, 96549715).onPosts("gtg").or.onComments("gtg").subscribe({ + next(data) { + // Count posts (should be 0) + data.posts["gtg"]?.forEach(() => { + postsDetected++; + }); + + // Count comments (should be > 0) + data.comments["gtg"]?.forEach(() => { + commentsDetected++; + }); + }, + error(err) { + console.error(err); + reject(err); + }, + complete: () => resolve({ postsDetected, commentsDetected }) + }); + }); + + // Should detect comments but NOT posts + expect(result.commentsDetected).toBeGreaterThan(0); + expect(result.postsDetected).toBe(0); + }); + + test("1.2 - Should NOT trigger when monitored accounts create comments instead of posts", async({ createWorkerBeeTest }) => { + const result = await createWorkerBeeTest<{ postResults: Record; commentResults: Record }>((bot, resolve, reject) => { + const postResults: Record = {}; + const commentResults: Record = {}; + + // Test accounts known to comment in this range + const testAccounts = ["gtg", "moretea", "khantaimur"]; + + /* + * Monitor multiple accounts for posts (should not trigger for comment activity) + * Also Verify these accounts were active with comments + */ + bot.providePastOperations(96549690, 96549715).onPosts(...testAccounts).or.onComments(...testAccounts).subscribe({ + next(data) { + testAccounts.forEach(account => { + data.posts[account]?.forEach(() => { + postResults[account] = (postResults[account] || 0) + 1; + }); + + data.comments[account]?.forEach(() => { + commentResults[account] = (commentResults[account] || 0) + 1; + }); + }); + }, + error(err) { + console.error(err); + reject(err); + }, + complete: () => resolve({ postResults, commentResults }) + }); + }); + + const totalComments = Object.values(result.commentResults).reduce((sum, count) => sum + count, 0); + const totalPosts = Object.values(result.postResults).reduce((sum, count) => sum + count, 0); + + expect(totalComments).toBeGreaterThan(0); + expect(totalPosts).toBe(0); + }); + + test("1.2 - Should NOT trigger when different account creates post", async({ createWorkerBeeTest }) => { + const result = await createWorkerBeeTest<{ monitoredAccountPosts: number; otherAccountPosts: number }>((bot, resolve, reject) => { + let monitoredAccountPosts = 0; + let otherAccountPosts = 0; + + /* + * Monitor for posts from a specific account + * Also Verify other accounts were posting in this range + */ + bot.providePastOperations(96549390, 96549415).onPosts("nonexistent-account").or.onPosts("mtyszczak").subscribe({ + next(data) { + data.posts["nonexistent-account"]?.forEach(() => { + monitoredAccountPosts++; + }); + + data.posts["mtyszczak"]?.forEach(() => { + otherAccountPosts++; + }); + }, + error(err) { + console.error(err); + reject(err); + }, + complete: () => resolve({ monitoredAccountPosts, otherAccountPosts }) + }); + }); + + // Should NOT detect posts from monitored account, but should detect from other account + expect(result.monitoredAccountPosts).toBe(0); + expect(result.otherAccountPosts).toBeGreaterThan(0); + }); + + test("1.2 - Should handle empty account list", async({ createWorkerBeeTest }) => { + const result = await createWorkerBeeTest((bot, resolve, reject) => { + let dataReceived = false; + + try { + // Test with no accounts (edge case) + bot.providePastOperations(96549390, 96549415).onPosts().subscribe({ + next(_data) { + dataReceived = true; + console.log("Data received for empty account list"); + }, + error(err) { + console.error("Error with empty account list:", err); + reject(err); + }, + complete: () => resolve(dataReceived) + }); + } catch { + reject(new Error("Unexpected error occurred")); + } + }); + + expect(result).toBeFalsy(); + }); + + test("2.1 - Should trigger when any specified account creates comment - multiple accounts", async({ createWorkerBeeTest }) => { + const result = await createWorkerBeeTest((bot, resolve, reject) => { + const capturedComments: string[] = []; + + bot.providePastOperations(96549690, 96549715).onComments("gtg", "moretea", "khantaimur").subscribe({ + next(data) { + for (const author of ["gtg", "moretea", "khantaimur"]) + data.comments[author]?.forEach(({ operation }) => { + capturedComments.push(`Comment by ${operation.author}: ${operation.permlink}`); + }); + }, + error(err) { + console.error(err); + reject(err); + }, + complete: () => resolve(capturedComments) + }); + }); + + expect(result).toEqual([ + "Comment by moretea: re-leothreads-2xpn8nyzd", + "Comment by khantaimur: re-vkcmjbdble", + "Comment by gtg: re-mtyszczak-1749229740753" + ]); + }); + + test("2.1 - Should trigger for simultaneous comments from multiple accounts in same block", async({ createWorkerBeeTest }) => { + const result = await createWorkerBeeTest((bot, resolve, reject) => { + const capturedComments: Array<{ author: string; blockNumber: number }> = []; + + bot.providePastOperations(97634334, 97634348).onBlock().or.onComments("zayyar99", "beckyroyal").subscribe({ + next(data) { + for (const author of ["zayyar99", "beckyroyal"]) + data.comments[author]?.forEach(({ operation }) => { + capturedComments.push({ + author: operation.author, + blockNumber: data.block.number + }); + }); + }, + error(err) { + console.error(err); + reject(err); + }, + complete: () => resolve(capturedComments) + }); + }); + + expect(result).toEqual([ + { + author: "zayyar99", + blockNumber: 97634338 + }, + { + author: "beckyroyal", + blockNumber: 97634338 + } + ]); + }); + + test("2.2 - Should NOT trigger when account creates post instead of comment", async({ createWorkerBeeTest }) => { + const result = await createWorkerBeeTest((bot, resolve, reject) => { + let commentsDetected = 0; + let postsDetected = 0; + + + /* + * Monitor an account known to create posts in this range for comments (should not trigger) + * Also check for posts in the same range to verify account was active with posts + */ + bot.providePastOperations(96549390, 96549415).onComments("mtyszczak").or.onPosts("mtyszczak").subscribe({ + next(data) { + // Count comments (should be 0) + data.comments["mtyszczak"]?.forEach(() => { + commentsDetected++; + }); + + // Count posts (should be > 0) + data.posts["mtyszczak"]?.forEach(() => { + postsDetected++; + }); + }, + error(err) { + console.error(err); + reject(err); + }, + complete: () => resolve({ commentsDetected, postsDetected }) + }); + }); + + // Should detect posts but NOT comments + expect(result.postsDetected).toBeGreaterThan(0); + expect(result.commentsDetected).toBe(0); + }); + + test("2.2 - Should NOT trigger when monitored accounts create posts instead of comments", async({ createWorkerBeeTest }) => { + const result = await createWorkerBeeTest<{ commentResults: Record; postResults: Record }>((bot, resolve, reject) => { + const commentResults: Record = {}; + const postResults: Record = {}; + + // Test accounts known to post in this range + const testAccounts = ["mtyszczak", "nickdongsik", "techstyle"]; + + /* + * Monitor multiple accounts for comments (should not trigger for post activity) + * Also verify these accounts were active with posts + */ + bot.providePastOperations(96549390, 96549415).onComments(...testAccounts).or.onPosts(...testAccounts).subscribe({ + next(data) { + testAccounts.forEach(account => { + data.comments[account]?.forEach(() => { + commentResults[account] = (commentResults[account] || 0) + 1; + }); + + data.posts[account]?.forEach(() => { + postResults[account] = (postResults[account] || 0) + 1; + }); + }); + }, + error(err) { + console.error(err); + reject(err); + }, + complete: () => resolve({ commentResults, postResults }) + }); + }); + + const totalPosts = Object.values(result.postResults).reduce((sum, count) => sum + count, 0); + const totalComments = Object.values(result.commentResults).reduce((sum, count) => sum + count, 0); + + expect(totalPosts).toBeGreaterThan(0); + expect(totalComments).toBe(0); + }); + + test("2.2 - Should NOT trigger when different account creates comment", async({ createWorkerBeeTest }) => { + const result = await createWorkerBeeTest((bot, resolve, reject) => { + let monitoredAccountComments = 0; + let otherAccountComments = 0; + + /* + * Monitor for comments from a specific account that doesn't commented + * Also verify other accounts were commenting in this range + */ + bot.providePastOperations(96549690, 96549715).onComments("nonexistent-commenter").or.onComments("gtg").subscribe({ + next(data) { + data.comments["nonexistent-commenter"]?.forEach(() => { + monitoredAccountComments++; + }); + + data.comments["gtg"]?.forEach(() => { + otherAccountComments++; + }); + }, + error(err) { + console.error(err); + reject(err); + }, + complete: () => resolve({ monitoredAccountComments, otherAccountComments }) + }); + }); + + // Should NOT detect comments from monitored account, but should detect from other account + expect(result.monitoredAccountComments).toBe(0); + expect(result.otherAccountComments).toBeGreaterThan(0); + }); + + test("2.2 - Should handle empty account list for comments", async({ createWorkerBeeTest }) => { + const result = await createWorkerBeeTest((bot, resolve, reject) => { + let dataReceived = false; + + try { + // Test with no accounts (edge case) + bot.providePastOperations(96549690, 96549715).onComments().subscribe({ + next(_data) { + dataReceived = true; + console.log("Data received for empty comment account list"); + }, + error(err) { + console.error("Error with empty comment account list:", err); + reject(err); + }, + complete: () => resolve(dataReceived) + }); + } catch { + reject(new Error("Unexpected error occurred")); + } + }); + + expect(result).toBeFalsy(); + }); + + test("2.3 - Should trigger when any specified account creates post or comment", async({ createWorkerBeeTest }) => { + const result = await createWorkerBeeTest((bot, resolve, reject) => { + const capturedPosts: string[] = []; + + bot + .providePastOperations(96549390, 96549415) + .onPosts("mtyszczak", "author2", "author3") + .or.onComments("secret-art", "author2", "author3") + .subscribe({ + next(data) { + for (const author of ["mtyszczak", "secret-art", "author2", "author3"]) { + data.comments[author]?.forEach(({ operation }) => { + capturedPosts.push(`Comment by ${operation.author}: ${operation.permlink}`); + }); + + data.posts[author]?.forEach(({ operation }) => { + capturedPosts.push(`Post by ${operation.author}: ${operation.permlink}`); + }); + } + }, + error(err) { + console.error(err); + reject(err); + }, + complete: () => resolve(capturedPosts) + }); + }); + + expect(result).toEqual([ + "Comment by secret-art: re-jfang003-sxg1lb", + "Comment by secret-art: re-aussieninja-sxg1lm", + "Post by mtyszczak: hi-ve-everyone", + "Comment by secret-art: re-aussieninja-sxg1m5", + "Comment by secret-art: re-jfang003-sxg1mg" + ]); + }); + + test("3.1 - Should trigger when any specified account votes - multiple accounts", async({ createWorkerBeeTest }) => { + const result = await createWorkerBeeTest((bot, resolve, reject) => { + const capturedVotes: string[] = []; + + bot.providePastOperations(96549390, 96549415).onVotes("dhedge", "winanda").subscribe({ + next(data) { + for (const voter of ["dhedge", "winanda"]) + data.votes[voter]?.forEach(({ operation }) => { + capturedVotes.push(`Vote by ${operation.voter} on ${operation.author}/${operation.permlink}`); + }); + }, + error(err) { + console.error(err); + reject(err); + }, + complete: () => resolve(capturedVotes) + }); + }); + + expect(result).toEqual([ + "Vote by winanda on xlety/is-it-really-worth-creating", + "Vote by dhedge on gpache/i-went-to-a-doctors-office-my-vision-is-improving-eng-esp", + "Vote by dhedge on helicreamarket/sorpresa-al-horno-esp-eng" + ]); + }); + + test("3.1 - Should trigger for simultaneous votes from multiple accounts in same block", async({ createWorkerBeeTest }) => { + const result = await createWorkerBeeTest((bot, resolve, reject) => { + const capturedVotes: Array<{ voter: string; blockNumber: number }> = []; + + bot.providePastOperations(96549390, 96549404).onBlock().or.onVotes("noctury", "the-burn").subscribe({ + next(data) { + for (const voter of ["noctury", "the-burn"]) + data.votes[voter]?.forEach(({ operation }) => { + capturedVotes.push({ + voter: operation.voter, + blockNumber: data.block.number + }); + }); + }, + error(err) { + console.error(err); + reject(err); + }, + complete: () => resolve(capturedVotes) + }); + }); + + expect(result).toEqual([ + { + voter: "noctury", + blockNumber: 96549403 + }, + { + voter: "the-burn", + blockNumber: 96549403 + } + ]); + }); + + test("3.2 - Should NOT trigger when account creates post/comment instead of voting", async({ createWorkerBeeTest }) => { + const result = await createWorkerBeeTest((bot, resolve, reject) => { + let votesDetected = 0; + let commentOperationsDetected = 0; + + /* + * Monitor an account known to create posts/comments but does not vote in this range + * Also Check for posts to verify account was active + */ + bot.providePastOperations(96549390, 96549415).onVotes("mtyszczak").or.onPosts("mtyszczak").or.onComments("mtyszczak").subscribe({ + next(data) { + // Count votes (should be 0) + data.votes["mtyszczak"]?.forEach(() => { + votesDetected++; + }); + + // Count comments (should be > 0) + data.comments["mtyszczak"]?.forEach(() => { + commentOperationsDetected++; + }); + + data.posts["mtyszczak"]?.forEach(() => { + commentOperationsDetected++; + }); + }, + error(err) { + console.error(err); + reject(err); + }, + complete: () => resolve({ votesDetected, commentOperationsDetected }) + }); + }); + + // Should detect posts/comments but no votes from this account in this range + expect(result.commentOperationsDetected).toBeGreaterThan(0); + expect(result.votesDetected).toBe(0); + }); + + test("3.2 - Should NOT trigger when different account votes", async({ createWorkerBeeTest }) => { + const result = await createWorkerBeeTest((bot, resolve, reject) => { + let monitoredAccountVotes = 0; + let otherAccountVotes = 0; + + /* + * Monitor for votes from a specific account that doesn't vote much + * Also Verify other accounts were voting in this range + */ + bot.providePastOperations(96549390, 96549415).onVotes("nonexistent-voter").or.onVotes("noctury").subscribe({ + next(data) { + data.votes["nonexistent-voter"]?.forEach(() => { + monitoredAccountVotes++; + }); + + data.votes["noctury"]?.forEach(() => { + otherAccountVotes++; + }); + }, + error(err) { + console.error(err); + reject(err); + }, + complete: () => resolve({ monitoredAccountVotes, otherAccountVotes }) + }); + }); + + // Should NOT detect votes from monitored account, but should detect from other account + expect(result.monitoredAccountVotes).toBe(0); + expect(result.otherAccountVotes).toBeGreaterThan(0); + }); + + test("3.2 - Should handle empty account list for votes", async({ createWorkerBeeTest }) => { + const result = await createWorkerBeeTest((bot, resolve, reject) => { + let dataReceived = false; + + try { + // Test with no accounts (edge case) + bot.providePastOperations(96549390, 96549415).onVotes().subscribe({ + next(_data) { + dataReceived = true; + console.log("Data received for empty votes account list"); + }, + error(err) { + console.error("Error with empty votes account list:", err); + reject(err); + }, + complete: () => resolve(dataReceived) + }); + } catch { + reject(new Error("Unexpected error occurred")); + } + }); + + expect(result).toBeFalsy(); + }); + + test("Multiple 'or' filters should work correctly", async({ createWorkerBeeTest }) => { + const result = await createWorkerBeeTest((bot, resolve, reject) => { + const capturedPosts: string[] = []; + + bot.providePastOperations(96549390, 96549415) + .onPosts("mtyszczak").or.or.or.or.or.onComments("secret-art") + .subscribe({ + next(data) { + for (const author of ["mtyszczak", "secret-art"]) { + data.posts[author]?.forEach(({ operation }) => { + capturedPosts.push(`Post by ${operation.author}: ${operation.permlink}`); + }); + + data.comments[author]?.forEach(({ operation }) => { + capturedPosts.push(`Comment by ${operation.author}: ${operation.permlink}`); + }); + } + + }, + error(err) { + console.error(err); + reject(err); + }, + complete: () => resolve(capturedPosts) + }); + }); + + expect(result).toEqual([ + "Comment by secret-art: re-jfang003-sxg1lb", + "Comment by secret-art: re-aussieninja-sxg1lm", + "Post by mtyszczak: hi-ve-everyone", + "Comment by secret-art: re-aussieninja-sxg1m5", + "Comment by secret-art: re-jfang003-sxg1mg" + ]); + }); +}); diff --git a/__tests__/index.spec.ts b/__tests__/index.spec.ts index 938ab18..0543e0b 100644 --- a/__tests__/index.spec.ts +++ b/__tests__/index.spec.ts @@ -2,3 +2,4 @@ import "./detailed/bot_providers"; import "./detailed/bot_events"; +import "./detailed/individual_filter_tests"; -- GitLab From 630979b6f9c578bf623f142be5ea31ecda249bdb Mon Sep 17 00:00:00 2001 From: fwaszkiewicz Date: Tue, 15 Jul 2025 14:22:00 +0200 Subject: [PATCH 04/11] Implement realistic scenarios tests --- __tests__/detailed/realistic_scenarios.ts | 489 ++++++++++++++++++++++ __tests__/index.spec.ts | 1 + 2 files changed, 490 insertions(+) create mode 100644 __tests__/detailed/realistic_scenarios.ts diff --git a/__tests__/detailed/realistic_scenarios.ts b/__tests__/detailed/realistic_scenarios.ts new file mode 100644 index 0000000..0e860fe --- /dev/null +++ b/__tests__/detailed/realistic_scenarios.ts @@ -0,0 +1,489 @@ +/* eslint-disable no-console */ +import { custom_json } from "@hiveio/wax"; +import { expect } from "playwright/test"; +import { test } from "../assets/jest-helper"; + +test.describe("Bot Realistic Scenarios", () => { + test("1.1 - Should be able to monitor posts OR comments from multiple authors", async({ createWorkerBeeTest }) => { + const result = await createWorkerBeeTest((bot, resolve, reject) => { + const content: string[] = []; + + bot.providePastOperations(96549390, 96549415).onPosts("mtyszczak").or.onPosts("nickdongsik").or.onComments("brando28").subscribe({ + next(data) { + for (const author in data.posts) + data.posts[author].forEach(({ operation }) => content.push(`${operation.author} - ${operation.permlink}`)); + + for (const author in data.comments) + data.comments[author].forEach(({ operation }) => content.push(`${operation.author} - ${operation.permlink}`)); + }, + error: (err) => { + console.error(err); + reject(err); + }, + complete: () => resolve(content) + }); + }, true); + + expect(result).toEqual([ + "brando28 - re-bitcoinman-ovjhawi6", + "mtyszczak - hi-ve-everyone", + "nickdongsik - yay-hb1hao" + ]); + }); + + test("1.2 - Should be able to create social activity aggregator", async({ createWorkerBeeTest }) => { + const result = await createWorkerBeeTest((bot, resolve, reject) => { + const content: string[] = []; + + bot.providePastOperations(97146285, 97146300).onVotes("e-sport-gamer").or.onFollow("fwaszkiewicz").or.onReblog("maxinpower").subscribe({ + next(data) { + for (const author in data.votes) + data.votes[author].forEach(({ operation }) => content.push(`Vote: ${operation.voter} - ${operation.permlink}`)); + + for (const author in data.follows) + data.follows[author].forEach(({ operation }) => content.push(`Follow: ${operation.follower} - ${operation.following}`)); + + for (const author in data.reblogs) + data.reblogs[author].forEach(({ operation }) => content.push(`Reblog: ${operation.author} - ${operation.permlink}`)); + }, + error: (err) => { + console.error(err); + reject(err); + }, + complete: () => resolve(content) + }); + }, true); + + expect(result).toEqual([ + "Vote: e-sport-gamer - city-pingeons", + "Follow: fwaszkiewicz - thebeedevs", + "Follow: fwaszkiewicz - thebeedevs", + "Reblog: maxinpower - erinnnerungen-an-eine-gute-currywurst-berlin-impressions" + ]); + }); + + test("1.3 - Should be able to create financial activity monitor", async({ createWorkerBeeTest }) => { + const result = await createWorkerBeeTest((bot, resolve, reject) => { + const content: string[] = []; + + bot + .providePastOperations(97347575, 97347585) + .onWhaleAlert(bot.chain!.hiveCoins(50)) + .or.onInternalMarketOperation() + .or.onExchangeTransfer() + .subscribe({ + next(data) { + data.exchangeTransferOperations.forEach(({ operation }) => { + content.push(`Exchange Transfer: ${operation.from} -> ${operation.to} - ${operation.amount.amount}`); + }); + + data.internalMarketOperations.forEach(({ operation }) => { + content.push(`Internal Market Operation: ${operation.owner} - ${operation.orderId}`); + }); + + data.whaleOperations.forEach(({ operation }) => { + content.push(`Whale Alert: ${operation.from} -> ${operation.to} - ${operation.amount.amount}`); + }); + }, + error: (err) => { + console.error(err); + reject(err); + }, + complete: () => resolve(content) + }); + }, true); + + expect(result).toEqual([ + "Internal Market Operation: honeybot - 243293707", + "Whale Alert: honey-swap -> luluwinda - 53308", + "Internal Market Operation: honeybot - 1485200410", + "Exchange Transfer: mxchive -> inhivepool - 23890" + ]); + }); + + test("1.4 - Should be able to create content engagement tracker", async({ createWorkerBeeTest }) => { + const result = await createWorkerBeeTest((bot, resolve, reject) => { + const content: string[] = []; + + bot.providePastOperations(97639665, 97639695).onMention("thebeedevs").or.onPosts("thebeedevs").or.onReblog("thebeedevs").subscribe({ + next(data) { + data.posts.thebeedevs?.forEach(({ operation }) => { + content.push(`Post: ${operation.author} - ${operation.permlink}`); + }); + + data.mentioned.thebeedevs?.forEach((operation) => { + content.push(`Mention: ${operation.author} - ${operation.permlink}`); + }); + + data.reblogs.thebeedevs?.forEach(({ operation }) => { + content.push(`Reblog: ${operation.author} - ${operation.permlink}`); + }); + }, + error: (err) => { + console.error(err); + reject(err); + }, + complete: () => resolve(content) + }); + }, true); + + expect(result).toEqual([ + "Post: thebeedevs - hivesense-why-nothing-worked-at-first-and-what-we-did-about-it", + "Mention: thebeedevs - hivesense-why-nothing-worked-at-first-and-what-we-did-about-it", + "Reblog: thebeedevs - hivesense-why-nothing-worked-at-first-and-what-we-did-about-it" + ]); + }); + + test("1.5 - Should be able to create cross-platform activity monitor", async({ createWorkerBeeTest }) => { + const result = await createWorkerBeeTest((bot, resolve, reject) => { + const content: string[] = []; + + bot + .providePastOperations(97664614, 97664618) + .onCustomOperation("follow") + .or.onCustomOperation("reblog") + .or.onNewAccount().subscribe({ + next(data) { + data.customOperations.follow?.forEach(({ operation }) => { + content.push(`Follow: ${(operation as custom_json).json}`); + }); + + data.customOperations.reblog?.forEach(({ operation }) => { + content.push(`Reblog: ${(operation as custom_json).json}`); + }); + + data.newAccounts.forEach((operation) => { + content.push(`New Account: ${operation.accountName}`); + }); + }, + error: (err) => { + console.error(err); + reject(err); + }, + complete: () => resolve(content) + }); + }, true); + + expect(result).toEqual([ + "Follow: [\"reblog\",{\"account\":\"cribbio\",\"author\":\"donasycafe\",\"permlink\":\"feliz-4o-aniversario-mi-historia\"}]", + "Follow: [\"reblog\",{\"account\":\"gasaeightyfive\",\"author\":\"donasycafe\",\"permlink\":\"feliz-4o-aniversario-mi-historia\"}]", + "Reblog: [\"reblog\",{\"account\":\"dehai\",\"author\":\"rubenjr\",\"permlink\":\"hello-its-me-what-can-a-father-do\"}]", + "New Account: ayasolene20" + ]); + }); + + test("1.6 - Should be able to create content creator dashboard", async({ createWorkerBeeTest }) => { + const result = await createWorkerBeeTest((bot, resolve, reject) => { + const content: string[] = []; + + bot + .providePastOperations(97547200, 97547250) + .onPosts("thebeedevs") + .or.onComments("thebeedevs") + .or.onMention("thebeedevs") + .or.onReblog("thebeedevs") + .or.onVotes("thebeedevs") + .subscribe({ + next(data) { + data.posts.thebeedevs?.forEach(({ operation }) => { + content.push(`Post: ${operation.author} - ${operation.permlink}`); + }); + + data.comments.thebeedevs?.forEach(({ operation }) => { + content.push(`Comment: ${operation.author} - ${operation.permlink}`); + }); + + data.mentioned.thebeedevs?.forEach((operation) => { + content.push(`Mention: ${operation.author} - ${operation.permlink}`); + }); + + data.reblogs.thebeedevs?.forEach(({ operation }) => { + content.push(`Reblog: ${operation.author} - ${operation.permlink}`); + }); + + data.votes.thebeedevs?.forEach(({ operation }) => { + content.push(`Vote: ${operation.voter} - ${operation.permlink}`); + }); + }, + error: (err) => { + console.error(err); + reject(err); + }, + complete: () => resolve(content) + }); + }, true); + + expect(result).toEqual([ + "Post: thebeedevs - meet-workerbee-the-easy-way-to-build-smart-blockchain-bots", + "Mention: thebeedevs - meet-workerbee-the-easy-way-to-build-smart-blockchain-bots", + "Vote: thebeedevs - meet-workerbee-the-easy-way-to-build-smart-blockchain-bots", + "Reblog: thebeedevs - meet-workerbee-the-easy-way-to-build-smart-blockchain-bots" + ]); + }); + + test("1.7 - Should be able to create market movement detector", async({ createWorkerBeeTest }) => { + const result = await createWorkerBeeTest((bot, resolve, reject) => { + const content: string[] = []; + + bot + .providePastOperations(97347545, 97347555) + .or.onWhaleAlert(bot.chain!.hiveCoins(10000)) + .or.onInternalMarketOperation() + .or.onExchangeTransfer() + .subscribe({ + next(data) { + data.whaleOperations.forEach(({ operation }) => { + content.push(`Whale Alert: ${operation.from} -> ${operation.to} - ${operation.amount.amount}`); + }); + + data.internalMarketOperations.forEach(({ operation }) => { + content.push(`Internal Market Operation: ${operation.owner} - ${operation.orderId}`); + }); + + data.exchangeTransferOperations.forEach(({ operation }) => { + content.push(`Exchange Transfer: ${operation.from} -> ${operation.to} - ${operation.amount.amount}`); + }); + }, + error: (err) => { + console.error(err); + reject(err); + }, + complete: () => resolve(content) + }); + }, true); + + expect(result).toEqual([ + "Whale Alert: huobi-pro -> huobi-withdrawal - 1598290", + "Exchange Transfer: huobi-pro -> huobi-withdrawal - 1598290", + "Whale Alert: aerrilee -> checkyzk - 2", + "Internal Market Operation: daverick - 1751626472" + ]); + }); + + test("2.1 - Should be able to create pattern analysis bot", async({ createWorkerBeeTest }) => { + const result = await createWorkerBeeTest((bot, resolve, reject) => { + const content: string[] = []; + + bot + .providePastOperations(97547200, 97547250) + .onVotes("thebeedevs") + .or.onPosts("thebeedevs") + .subscribe({ + next(data) { + data.votes.thebeedevs?.forEach(({ operation }) => { + content.push(`Vote: ${operation.voter} - ${operation.permlink}`); + }); + + data.posts.thebeedevs?.forEach(({ operation }) => { + content.push(`Post: ${operation.author} - ${operation.permlink}`); + }); + }, + error: (err) => { + console.error(err); + reject(err); + }, + complete: () => resolve(content) + }); + }, true); + + expect(result).toEqual([ + "Post: thebeedevs - meet-workerbee-the-easy-way-to-build-smart-blockchain-bots", + "Vote: thebeedevs - meet-workerbee-the-easy-way-to-build-smart-blockchain-bots" + ]); + }); + + test("2.2 - Should be able to create market trend analyzer", async({ createWorkerBeeTest }) => { + const result = await createWorkerBeeTest((bot, resolve, reject) => { + const content: string[] = []; + + bot + .providePastOperations(97347545, 97347555) + .onWhaleAlert(bot.chain!.hiveCoins(10000)) + .or.onInternalMarketOperation() + .subscribe({ + next(data) { + data.whaleOperations.forEach(({ operation }) => { + content.push(`Whale Alert: ${operation.from} -> ${operation.to} - ${operation.amount.amount}`); + }); + + data.internalMarketOperations.forEach(({ operation }) => { + content.push(`Internal Market: ${operation.owner} - ${operation.orderId}`); + }); + }, + error: (err) => { + console.error(err); + reject(err); + }, + complete: () => resolve(content) + }); + }, true); + + expect(result).toEqual([ + "Whale Alert: huobi-pro -> huobi-withdrawal - 1598290", + "Whale Alert: aerrilee -> checkyzk - 2", + "Internal Market: daverick - 1751626472", + ]); + }); + + test("2.3 - Should be able to create community growth monitor", async({ createWorkerBeeTest }) => { + const result = await createWorkerBeeTest((bot, resolve, reject) => { + const content: string[] = []; + + bot + .providePastOperations(97664610, 97664620) + .onNewAccount() + .or.onFollow("thebeedevs") + .or.onCustomOperation("follow") + .subscribe({ + next(data) { + data.newAccounts.forEach((operation) => { + content.push(`New Account: ${operation.accountName}`); + }); + + data.follows.thebeedevs?.forEach(({ operation }) => { + content.push(`Follow: ${operation.follower} -> ${operation.following}`); + }); + + data.customOperations.follow?.forEach(({ operation }) => { + content.push(`Custom Follow: ${(operation as custom_json).json}`); + }); + }, + error: (err) => { + console.error(err); + reject(err); + }, + complete: () => resolve(content) + }); + }, true); + + expect(result).toEqual([ + "Custom Follow: [\"follow\",{\"follower\":\"dehai\",\"following\":\"rubenjr\",\"what\":[\"blog\"]}]", + "Custom Follow: [\"follow\",{\"follower\":\"dehai\",\"following\":\"rubenjr\",\"what\":[]}]", + "Custom Follow: [\"follow\",{\"follower\":\"dehai\",\"following\":\"rubenjr\",\"what\":[\"blog\"]}]", + "Custom Follow: [\"reblog\",{\"account\":\"cribbio\",\"author\":\"donasycafe\",\"permlink\":\"feliz-4o-aniversario-mi-historia\"}]", + "New Account: ayasolene20", + "Custom Follow: [\"reblog\",{\"account\":\"gasaeightyfive\",\"author\":\"donasycafe\",\"permlink\":\"feliz-4o-aniversario-mi-historia\"}]" + ]); + }); + + test("2.4 - Should be able to create content performance analyzer", async({ createWorkerBeeTest }) => { + const result = await createWorkerBeeTest((bot, resolve, reject) => { + const content: string[] = []; + + bot + .providePastOperations(97547200, 97547250) + .onPosts("thebeedevs") + .or.onComments("thebeedevs") + .or.onVotes("thebeedevs") + .subscribe({ + next(data) { + data.posts.thebeedevs?.forEach(({ operation }) => { + content.push(`Post: ${operation.author} - ${operation.permlink}`); + }); + + data.comments.thebeedevs?.forEach(({ operation }) => { + content.push(`Comment: ${operation.author} - ${operation.permlink}`); + }); + + data.votes.thebeedevs?.forEach(({ operation }) => { + content.push(`Vote: ${operation.voter} - ${operation.permlink}`); + }); + }, + error: (err) => { + console.error(err); + reject(err); + }, + complete: () => resolve(content) + }); + }, true); + + expect(result).toEqual([ + "Post: thebeedevs - meet-workerbee-the-easy-way-to-build-smart-blockchain-bots", + "Vote: thebeedevs - meet-workerbee-the-easy-way-to-build-smart-blockchain-bots" + ]); + }); + + test("2.5 - Should be able to create economic activity tracker", async({ createWorkerBeeTest }) => { + const result = await createWorkerBeeTest((bot, resolve, reject) => { + const content: string[] = []; + + bot + .providePastOperations(97347575, 97347585) + .onWhaleAlert(bot.chain!.hiveCoins(1000)) + .or.onExchangeTransfer() + .or.onInternalMarketOperation() + .subscribe({ + next(data) { + data.whaleOperations.forEach(({ operation }) => { + content.push(`Whale: ${operation.from} -> ${operation.to} - ${operation.amount.amount}`); + }); + + data.exchangeTransferOperations.forEach(({ operation }) => { + content.push(`Exchange: ${operation.from} -> ${operation.to} - ${operation.amount.amount}`); + }); + + data.internalMarketOperations.forEach(({ operation }) => { + content.push(`Market: ${operation.owner} - ${operation.orderId}`); + }); + }, + error: (err) => { + console.error(err); + reject(err); + }, + complete: () => resolve(content) + }); + }, true); + + expect(result).toEqual([ + "Whale: honey-swap -> hive-engine - 403", + "Whale: honey-swap -> luluwinda - 53308", + "Market: honeybot - 243293707", + "Market: honeybot - 1485200410", + "Whale: mxchive -> inhivepool - 23890", + "Exchange: mxchive -> inhivepool - 23890" + ]); + }); + + test("2.6 - Should be able to create account behavior analysis", async({ createWorkerBeeTest }) => { + const result = await createWorkerBeeTest((bot, resolve, reject) => { + const content: string[] = []; + + bot + .providePastOperations(97547200, 97547250) + .onPosts("thebeedevs") + .or.onVotes("thebeedevs") + .or.onFollow("thebeedevs") + .or.onReblog("thebeedevs") + .subscribe({ + next(data) { + data.posts.thebeedevs?.forEach(({ operation }) => { + content.push(`Post: ${operation.author} - ${operation.permlink}`); + }); + + data.votes.thebeedevs?.forEach(({ operation }) => { + content.push(`Vote: ${operation.voter} - ${operation.permlink}`); + }); + + data.follows.thebeedevs?.forEach(({ operation }) => { + content.push(`Follow: ${operation.follower} -> ${operation.following}`); + }); + + data.reblogs.thebeedevs?.forEach(({ operation }) => { + content.push(`Reblog: ${operation.author} - ${operation.permlink}`); + }); + }, + error: (err) => { + console.error(err); + reject(err); + }, + complete: () => resolve(content) + }); + }, true); + + expect(result).toEqual([ + "Post: thebeedevs - meet-workerbee-the-easy-way-to-build-smart-blockchain-bots", + "Vote: thebeedevs - meet-workerbee-the-easy-way-to-build-smart-blockchain-bots", + "Reblog: thebeedevs - meet-workerbee-the-easy-way-to-build-smart-blockchain-bots" + ]); + }); +}); diff --git a/__tests__/index.spec.ts b/__tests__/index.spec.ts index 0543e0b..4ce95b8 100644 --- a/__tests__/index.spec.ts +++ b/__tests__/index.spec.ts @@ -3,3 +3,4 @@ import "./detailed/bot_providers"; import "./detailed/bot_events"; import "./detailed/individual_filter_tests"; +import "./detailed/realistic_scenarios"; -- GitLab From 26a6808eed55391e51703b071ed99389251b7e85 Mon Sep 17 00:00:00 2001 From: fwaszkiewicz Date: Wed, 16 Jul 2025 14:23:42 +0200 Subject: [PATCH 05/11] Add mock api call logs --- .../api-call-logs/block_api_get_block.json | 636 ++++++ .../database_api_find_accounts.json | 1794 +++++++++++++++++ .../database_api_find_witnesses.json | 175 ++ ...ase_api_get_dynamic_global_properties.json | 992 +++++++++ .../database_api_get_feed_history.json | 1075 ++++++++++ .../rc_api_find_rc_accounts.json | 104 + 6 files changed, 4776 insertions(+) create mode 100644 __tests__/assets/api-call-logs/block_api_get_block.json create mode 100644 __tests__/assets/api-call-logs/database_api_find_accounts.json create mode 100644 __tests__/assets/api-call-logs/database_api_find_witnesses.json create mode 100644 __tests__/assets/api-call-logs/database_api_get_dynamic_global_properties.json create mode 100644 __tests__/assets/api-call-logs/database_api_get_feed_history.json create mode 100644 __tests__/assets/api-call-logs/rc_api_find_rc_accounts.json diff --git a/__tests__/assets/api-call-logs/block_api_get_block.json b/__tests__/assets/api-call-logs/block_api_get_block.json new file mode 100644 index 0000000..3b8918a --- /dev/null +++ b/__tests__/assets/api-call-logs/block_api_get_block.json @@ -0,0 +1,636 @@ +[ + { + "req": { + "jsonrpc": "2.0", + "method": "block_api.get_block", + "params": { + "block_num": 97477291 + }, + "id": 1 + }, + "res": { + "id": 1, + "jsonrpc": "2.0", + "result": { + "block": { + "block_id": "05cf62ab3f2151a60e601ed86bdb43137949873d", + "extensions": [], + "previous": "05cf62aa64e54158fd61938b410c80366004b7fd", + "signing_key": "STM6LLegbAgLAy28EHrffBVuANFWcFgmqRMW13wBmTExqFE9SCkg4", + "timestamp": "2025-07-16T10:29:18", + "transaction_ids": [], + "transaction_merkle_root": "0000000000000000000000000000000000000000", + "transactions": [], + "witness": "ocd-witness", + "witness_signature": "204bc1f7343463a111570f51748aab9ca36da3fd7dfecaf2bacd2114738231275f51b4b04fecc810b2da7dcab518af03618c2bf7484be14722cc1011deb31b2843" + } + } + } + }, + { + "req": { + "jsonrpc": "2.0", + "method": "block_api.get_block", + "params": { + "block_num": 97477292 + }, + "id": 1 + }, + "res": { + "id": 1, + "jsonrpc": "2.0", + "result": { + "block": { + "block_id": "05cf62ab3f2151a60e601ed86bdb43137949873d", + "extensions": [], + "previous": "05cf62aa64e54158fd61938b410c80366004b7fd", + "signing_key": "STM6LLegbAgLAy28EHrffBVuANFWcFgmqRMW13wBmTExqFE9SCkg4", + "timestamp": "2025-07-16T10:29:18", + "transaction_ids": [ + "6bcf068618d8b66882cca5b94cd8de74215553df" + ], + "transaction_merkle_root": "0000000000000000000000000000000000000000", + "transactions": [ + { + "expiration": "2025-07-16T10:02:20", + "extensions": [], + "operations": [ + { + "type": "vote_operation", + "value": { + "voter": "gtg", + "author": "hbd.funder", + "weight": 10000, + "permlink": "re-upvote-this-post-to-fund-hbdstabilizer-20250716t045515z" + } + } + ], + "signatures": [ + "1f3395709c602d2a0643bbe1ed29ca0378412d6da504845fa3f174aec0437abcbc0831bd8817251f0eb8d113a5837fa433f25e886a7c6c30cd0c92f9bcae35d261" + ], + "ref_block_num": 43042, + "ref_block_prefix": 1380442540 + } + ], + "witness": "ocd-witness", + "witness_signature": "204bc1f7343463a111570f51748aab9ca36da3fd7dfecaf2bacd2114738231275f51b4b04fecc810b2da7dcab518af03618c2bf7484be14722cc1011deb31b2843" + } + } + } + }, + { + "req": { + "jsonrpc": "2.0", + "method": "block_api.get_block", + "params": { + "block_num": 97477293 + }, + "id": 1 + }, + "res": { + "id": 1, + "jsonrpc": "2.0", + "result": { + "block": { + "block_id": "05cf62ab3f2151a60e601ed86bdb43137949873d", + "extensions": [], + "previous": "05cf62aa64e54158fd61938b410c80366004b7fd", + "signing_key": "STM6LLegbAgLAy28EHrffBVuANFWcFgmqRMW13wBmTExqFE9SCkg4", + "timestamp": "2025-07-16T10:29:18", + "transaction_ids": [], + "transaction_merkle_root": "0000000000000000000000000000000000000000", + "transactions": [], + "witness": "ocd-witness", + "witness_signature": "204bc1f7343463a111570f51748aab9ca36da3fd7dfecaf2bacd2114738231275f51b4b04fecc810b2da7dcab518af03618c2bf7484be14722cc1011deb31b2843" + } + } + } + }, + { + "req": { + "jsonrpc": "2.0", + "method": "block_api.get_block", + "params": { + "block_num": 97477294 + }, + "id": 1 + }, + "res": { + "id": 1, + "jsonrpc": "2.0", + "result": { + "block": { + "block_id": "05cf62ab3f2151a60e601ed86bdb43137949873d", + "extensions": [], + "previous": "05cf62aa64e54158fd61938b410c80366004b7fd", + "signing_key": "STM6LLegbAgLAy28EHrffBVuANFWcFgmqRMW13wBmTExqFE9SCkg4", + "timestamp": "2025-07-16T10:29:18", + "transaction_ids": [ + "1c4b64f563f143284ca38dc66b3c2c71d314780f" + ], + "transaction_merkle_root": "0000000000000000000000000000000000000000", + "transactions": [ + { + "expiration": "2025-06-27T11:04:39", + "extensions": [], + "operations": [ + { + "type": "custom_json_operation", + "value": { + "id": "follow", + "json": "[\"follow\",{\"follower\":\"gtg\",\"following\":\"thebeedevs\",\"what\":[\"blog\"]}]", + "required_auths": [], + "required_posting_auths": [ + "gtg" + ] + } + } + ], + "signatures": [ + "1f00ac9a744bec96aed8ec9041bb45ec45a73d739b9b23d84120ab2d3b927bc8b71df03de7585d05352519ba4c52c24ada670100f527e1a68d206d140fe0e436f5" + ], + "ref_block_num": 22025, + "ref_block_prefix": 3008336972 + }, + { + "expiration": "2025-06-27T11:04:39", + "extensions": [], + "operations": [ + { + "type": "custom_json_operation", + "value": { + "id": "follow", + "json": "[\"follow\",{\"follower\":\"blocktrades\",\"following\":\"thebeedevs\",\"what\":[\"blog\"]}]", + "required_auths": [], + "required_posting_auths": [ + "blocktrades" + ] + } + } + ], + "signatures": [ + "1f00ac9a744bec96aed8ec9041bb45ec45a73d739b9b23d84120ab2d3b927bc8b71df03de7585d05352519ba4c52c24ada670100f527e1a68d206d140fe0e436f5" + ], + "ref_block_num": 22025, + "ref_block_prefix": 3008336972 + }, + { + "expiration": "2025-07-04T11:06:03", + "extensions": [], + "operations": [ + { + "type": "transfer_operation", + "value": { + "to": "inhivepool", + "from": "mxchive", + "memo": "114406", + "amount": { + "nai": "@@000000021", + "amount": "23890", + "precision": 3 + } + } + } + ], + "signatures": [ + "1f7319ba8eb2dea0eb79f96b7f365575b1249f7ee57d67d03e9f11a5dfec4356e8703c3849edb127277c1e11f392c960cf5ae050c8b7e51c9228ae155d8e4edb3d" + ], + "ref_block_num": 26618, + "ref_block_prefix": 1666306812 + }, + { + "expiration": "2025-07-04T11:05:36", + "extensions": [], + "operations": [ + { + "type": "limit_order_cancel_operation", + "value": { + "owner": "honeybot", + "orderid": 1485200410 + } + } + ], + "signatures": [ + "2042efb7142db143e406e8c8452839a3a9622d559e4c458cbcdaa0cba3c709fecf1d3a6064dfc56a187374b886078704b9fde44732a52156b4244765429ae3354b" + ], + "ref_block_num": 26609, + "ref_block_prefix": 3575588823 + }, + { + "expiration": "2025-07-16T21:18:51", + "extensions": [], + "operations": [ + { + "type": "custom_json_operation", + "value": { + "id": "follow", + "json": "[\"reblog\",{\"account\":\"thebeedevs\",\"author\":\"fwaszkiewicz\",\"permlink\":\"hi-to-hive\"}]", + "required_auths": [], + "required_posting_auths": [ + "thebeedevs" + ] + } + } + ], + "signatures": [ + "20d0b0d37581a0ad263bd49a60f96f09f2b2d12620c2f6824fccb4d1d470e5a39313f4e31b5d73dd4ebcee5e0e5f5335d9ebd9fc6650ae2600f6d6de5443fb657a" + ], + "ref_block_num": 56564, + "ref_block_prefix": 4096474193 + }, + { + "expiration": "2025-07-15T09:52:12", + "extensions": [], + "operations": [ + { + "type": "custom_json_operation", + "value": { + "id": "follow", + "json": "[\"reblog\",{\"account\":\"gtg\",\"author\":\"fwaszkiewicz\",\"permlink\":\"hi-to-hive\"}]", + "required_auths": [], + "required_posting_auths": [ + "gtg" + ] + } + } + ], + "signatures": [ + "1f9f5e132e12ea613314ea54901607baade72da7b58a5b79f7bed922ae3fd367e6458c531f26592b48a5856d6f6c9e91b7d5420ce08a207918f49d618013fa380b" + ], + "ref_block_num": 14069, + "ref_block_prefix": 844257793 + }, + { + "expiration": "2025-06-15T20:05:27", + "extensions": [], + "operations": [ + { + "type": "comment_operation", + "value": { + "body": "# Write on Hive, Read Everywhere!\n\nHello, dear Hive community! ꙮ\n\nEven though it's only been about a week since [my last post](https://blog.dev.openhive.network/hive-139531/@mtyszczak/hi-ve-everyone), I've missed you all so much! 🤗\n\nRecently, our dev team had a productive chat with @crimsonclad and @gtg about Hive components that users can embed on their websites. So, I got busy trying to bring these ideas to life as quickly as I could! 🏃\n\n ![img1.png](https://images.hive.blog/DQmYMwGJVN58EbpT5RPddsSh8tZcRK9KHPjcLuu6jNYXSmW/img1.png) \n\n## 📖 User Stories\n\nWe began by asking simple questions 🤔 about which components are essential and how they should be used, and we got immediate answers!\n\n- I want to **embed Hive posts** 🧩 on my website\n- I want my visitors to **view comments** 🗪\n- I want my visitors to be able to **❤️ like & 💬 comment** on the content I create\n- I want to display a paginated list of the **latest posts by tag** 📚\n- I want to show details of my **Hive account** 👦\n- I want to display my **witness details** 👀\n\n ![img2.png](https://images.hive.blog/DQmUkRJCBrBmQ1zYJAwDF6e7eoBvW6s84JmV3WgDuBsh24w/img2.png) \n\n## 📊 Check Out the Components!\n\n### Witness\n\n```html\n\n```\n\n ![img3.png](https://images.hive.blog/DQmSrkbu7pCVpgiVfCPMBGvyBaNgk6cW2UAdD6EWA51w42X/img3.png) \n\n### Post\n\n```html\n\n```\n\n ![img4.png](https://images.hive.blog/DQmfN7ufSamd9GvFP3b7Y6Py9ix1TtgTAqsrXqTY2bVzrRg/img4.png) \n\n### Comments\n\n```html\n\n```\n\n ![img5.png](https://images.hive.blog/DQmNMze5vfPhXy2gykvtQU2RrSG76u6hycFCXHfEPD8kojR/img5.png) \n\n### Posts by Tag\n\n```html\n\n```\n\n ![img6.png](https://images.hive.blog/DQmXLz7KdmwYcVGrxLrUqcdZESZBMrGCYkgjyvDv4tzjtGE/img6.png) \n\n## 💻 Sample Website\n\nThanks to @gtg, you can see these components [in action](https://gtg.openhive.network/5bb236) 💥\n\nFeel free to explore the source code of the website (visit: `view-source:https://gtg.openhive.network/5bb236`). It's impressively simple! ♻️\n\n## 📱 Mobile Users Welcome!\n\nNo worries! The components are fully responsive! ⚡\n\n ![img7.png](https://images.hive.blog/DQmcGoPbnekagshgHdLxLU98LH1pMY1WLTiCGCnXXmrayFY/img7.png) \n\nNo need to adjust settings. They automatically adapt to the viewport! 😊\n\n## 🔍 How to Use Them?\n\nI created a [quick start guide](https://github.com/mtyszczak/hive-components?tab=readme-ov-file#-quick-start) 🧠 in my repository.\n\nTL;DR:\n\n```html\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n```\n\n## 🧛🏻‍♀️ For Night Owls\n\nIntroducing the ✨ **dark theme** ✨:\n\n ![img8.png](https://images.hive.blog/DQmdAAobQMwVS4qFNLvSrVFnqr7iHda2t6ErwZefWTf3yxn/img8.png) \n\nJust set the `theme=\"dark\"` attribute on any component and you're good to go! 💪\n\n## 🎨 Want More Colors?\n\nCustomize your communities and websites with just a few lines of CSS! 🤩\n\n```css\nhive-comments {\n --hive-on-surface: blue;\n}\n```\n\nAnd here are the results: 👇\n\n ![img9.png](https://images.hive.blog/DQmVeRbsM31kshvF8LXXRauRMVfjdSYKHWRJTCvhMhTZKvJ/img9.png) \n\n## 📈 Need More Components?\n\nGreat! I love your spirit! 👻\n\nYou can request a new component by [creating an issue](https://github.com/mtyszczak/hive-components/issues/new) 💡 or suggest edits by [opening a pull request](https://github.com/mtyszczak/hive-components/pulls) 🛠️\n\n## 💾 Component Sizes\n\nI understand not everyone has super-fast internet 📟\n\nSo, I worked to make the components as compact as possible! ⬇️\n\n| Name | Size |\n|------|------|\n| Lit core | 7 kB |\n| Hive Witness | 19 kB |\n| Hive Post | 29.3 kB |\n| Hive Comments | 46.9 kB |\n| Hive Tag | 50.2 kB |\n| Hive internals | 640 kB |\n\nAnd remember, these script sizes are not gzipped yet! They are cached by browsers and executed only once per page load, on demand! 🤯\n\n## 💲 Pricing\n\nJust kidding 🤣 It's completely 🆓 🗽\n\nFeel free to visit [the repository](https://github.com/mtyszczak/hive-components) to contribute or use the components via CDN, thanks to @gtg 🧙‍♂️\n\n## 🌟 Future Plans\n\nI have a [few ideas](https://github.com/mtyszczak/hive-components/issues) in mind, and there are areas I can improve, but we did it! 📣\n\nMVP is on board! 💎\n\nI strongly encourage you to use the Hive components! 🖼️\n\n---\n\nImages from private archive & chatgpt.com\n", + "title": "Write on Hive, Read Everywhere!", + "author": "mtyszczak", + "permlink": "write-on-hive-read-everywhere", + "json_metadata": "{\"format\":\"markdown+html\",\"summary\":\"Bring Hive to your site! Embed posts, comments, tags & account data easily. Try new Hive web components - fast, free & mobile-ready!\",\"app\":\"hive.blog/0.9\",\"tags\":[\"hive\",\"dev\",\"web\",\"components\",\"html\",\"embed\"],\"image\":[\"\"],\"author\":\"\"}", + "parent_author": "", + "parent_permlink": "hive-139531" + } + }, + { + "type": "comment_options_operation", + "value": { + "author": "mtyszczak", + "permlink": "write-on-hive-read-everywhere", + "extensions": [], + "allow_votes": true, + "percent_hbd": 10000, + "max_accepted_payout": { + "nai": "@@000000013", + "amount": "1000000000", + "precision": 3 + }, + "allow_curation_rewards": true + } + } + ], + "signatures": [ + "20acb866dfb0e66afb6a5dcd507111da268107a5f8fbf34983b169f5ceb1ac5e0864e57fd02391a240037d46dfc3d89e7fda6ad96673c932e8636cd7924bdf8dc3" + ], + "ref_block_num": 15412, + "ref_block_prefix": 2290083372 + }, + { + "expiration": "2025-07-15T09:51:46", + "extensions": [], + "operations": [ + { + "type": "comment_operation", + "value": { + "body": "# Hi To Hive! 🐝\n\nI am a software developer who loves frontend technologies especially creating UI applications. Great **Look 'n' Feel** like also ergonomy are my best principles in the app development.\n \nIt's been over a year since I started my journey developing on Hive, and now — after some strong encouragement from [@gtg](/@gtg) and [@small.minion](/@small.minion) — I finally decided to share my work with you! 😄\n\n\n![image](https://hackmd.io/_uploads/Hypprp8Exg.png)\n\n\n## Short Summary\n\n### Welcome to Wax! 🕯️\n\nI hope by now you've all heard about **Wax** (thanks to [@thebeedevs' article](/@thebeedevs/for-those-developing-a-hive)). This library is a powerful toolset for interacting with Hive, and it didn’t take long before I became deeply involved in improving and testing it.\n\nAt first, I treated **Wax** as a black box 📦 — something powerful, but a bit mysterious. It was also a little gluey like true beewax. 🙂 My missing knowledge specific to Hive platform also made our relationship difficult. 🤔\n\nBut honestly, without great support for IDE intellisense, involving into Hive developer platform would be dramatically hard. I started by exploring how transactions work and slowly learned what **Wax** offers. \n\nSince then, **Wax** has taken a few steps forward — and of course, to ensure it's as great as we intended, someone had to test it thoroughly. 🧪\n\n### Wax well tested! 🕵️‍♂️\n\nAs I write this, there are **thousands of lines of code** dedicated to testing **Wax's** features — and a lot of that is my work. 🧑‍💻\n\nWhat’s more, the way we test the TypeScript part of **Wax** is a bit unconventional. We wanted the tests to run in **both web and Node environments**, but without duplicating code. That’s where [Microsoft Playwright](https://playwright.dev) came in with its awesome fixture system. 🛠️\n\nThis library allows developers to define custom fixtures — reusable rules and behaviors — which extend the base Playwright `test` object. To make this setup work, we created a helper file called `jest-helper`. Although honestly, a more fitting name would be `jest-confuser`... or maybe even `jest-UNhelper`. 😅\n\nBut the twisted backstory of our `jest-helper` deserves a dedicated post of its own - it is almost imposible to shorten the story... 📚\n\nFor now, you can [take a look at current jest-helper state](https://gitlab.syncad.com/hive/wax/-/blob/7e6218a060b6bc73b4fd8323fc7be62106f6566c/ts/wasm/__tests__/assets/jest-helper.ts) - and trust me - now it looks clean! 🚿\n\n\n### Inspect all your transactions! 🔍\n\nTight integration of 🇹🇸 **Wax** layer and Hive Protocol 🇨 code ☢️, allowed us to make our dreams of visualizing the Hive authorization process come true 👂\nSince my knowledge related to **Wax** library improved significantly, the next step was to use it in practice. \n\nThat’s why I built **Transaction Inspector** - a tool created for those who've always wondered what really happens behind the scenes when blockchain rejects their transaction (which creation was occupied by a lot of sweat 💦).\n\nI'm pretty sure you've had moments in your Hive journey when you submitted a transaction and wished you could easily see all its details. That's where **Transaction Inspector** comes in — it gathers all the information in one place, making it simple to read, verify, and understand! ✅ We announced it already in the [Transaction Inspector chapter.](/hive-139531/@thebeedevs/hive-is-five)\n\n![image](https://hackmd.io/_uploads/HJWCScL4gg.png)\n\nBut wait, there's more! Let's try breaking the signature in the same transaction... 🤫\n\n![image](https://hackmd.io/_uploads/BkrpU5UEgg.png)\n\nOf course, this will end in an error — but now, thanks to Transaction Inspector, you can **analyze exactly what went wrong** and why the broadcast failed. 💥\n\nI know this is a simple case, but the tool offers many more features and is still actively being developed. So it definitely deserves a dedicated post in the future! 🚧\n\nFor now, feel free to [test it yourself!](https://tx.openhive.network/?transaction=KQdgQsAMCCwEyXoucCmAPADgSwE4EMAXbAewDt45gBmWBShOAVgFpIA2FuagFQ5ujUAHALghK8AMJQ6yZGnSFUZAM6lVE2kmBMITACJSZ2%2BihKZUBYuRWbZOiDBNzt4Y6ZceTcQgE8Ldt4AbiRKAPrmlkTqEnDSTl6JnnBB%2BAA2AK6ogfRuCZ4FzsGhljnyAOaE5bHx9klFiXD4GYQAFiS4ZZStAEYAJgB0AGYZZH2lKEb5DYWNAO6o2OWthGUAjJCbyLUzu40WuAC2adhkANZdKLioLBmYIUosbdgqLJgkKoRPJCwjYyy9PqffA9bAnABeli4kGYHG4hEgABYmExIGtwRJpvUvCBDFjCrj3C4DFM6vI1OUyEQMtdbJMtPRdES9nA1kNID0hj12EN8Gt8OxET0AMZ9HnsACc%2BGoHBAwrgwrWEuFqGFiKETCGIFQfTW7CYIGoQz6KOocERPMgqCGiJAiL6QnwcAd1HYcCGQzWqEgwuoevYPQ5qDWQj6%2BExZJ0hjizNMcGuQzCPTSJGFZzCZAyhzKZrta1JDXj1qTKbTYUwCew6BzazW1ERrsRSOMuKAA)\n(The link takes you straight to the example shown in the above screenshot 😉 — yep, that's another **cool feature!**)\n\nBeside nice design, usage simplicity and good ergonomics, I am also proud of internal architecture of the application. Strong separation of UI and data processing layers improved a lot of automated testing process like also provided good performance level.\n\nWas it a big challenge? Definitely. 😅\nWorth the effort? Absolutely. 💪\n\nWhat I can promise is another detailed post describing challenges ⚔️ I had while working on it‼️\n\n\n### Another brick in my (programming) wall 🧱: design data structures and algorithm\n\nSomewhere between commits on **Transaction Inspector**, I caught myself thinking — What if I made a bot, which could vote automatically to avoid wasting manabar? No manual transactions ⚙️, no screen-staring while waiting on full manabar 👀.\n\nEnter **VoterBee** — a bot that votes for you. The first prototype was whipped up quickly — a rough concept, built without **WorkerBee**. But let’s be honest: coding everything from scratch is a fast track to API burnout.\n\nAnd than the question appeared:\n> **Okay... but how am I supposed to use this?** 🤔\n\nThe best sign that a library’s interface is well-designed is when a developer can jump in and figure out how to achieve their goals **without needing a massive wall of documentation**.\n\nIt wasn't easy at the beggining, but now, after many iterations, tons of feedback, boards full of concepts and thoughts, and lots of code improvements, we (that is: me, the *annoying user* who keeps complaining 😅, and [@mtyszczak](/@mtyszczak), the *patient developer* who built it) finally reached the point when **WorkerBee meets that standard** ❤️‍🔥\n\nIf you're curious and want to dive deeper into the technical side of **WorkerBee**, which I strongly recommend, check out [this post](/hive-139531/@thebeedevs/meet-workerbee-the-easy-way-to-build-smart-blockchain-bots) 📚 and if you want to start using the library immediately, check out the [public repo](https://gitlab.syncad.com/hive/workerbee).\n\n## Final thoughts 🧠💬\n\nThat’s it for now! Roughly a year of hard work led to this point. 🥳\n\nThis post turned out longer than I expected — and yet I feel like I’ve only scratched the surface. There’s still a lot more I’d love to share. 😅 \n\nI hope this gave you a little insight into the tools we're building around Hive — and how we try to make them not only powerful, but actually *nice to use*. Whether you’re a developer already building on Hive or just curious about what’s under the hood, I truly believe these tools can make your life easier.\n\nAnd hey, if you try them out and something breaks — that’s a feature, not a bug. Just kidding (kind of). 😜\n\nThanks for reading and stay tuned — more is coming soon! 🚀🐝\n", + "title": "Hi To Hive! 🐝", + "author": "fwaszkiewicz", + "permlink": "hi-to-hive", + "json_metadata": "{\"format\":\"markdown+html\",\"summary\":\"From Wax testing to the Transaction Inspector tool — a frontend dev's journey building smart tools on the Hive blockchain 🐝💻\",\"app\":\"hive.blog/0.9\",\"tags\":[\"introduceyourself\",\"hive\",\"dev\",\"hivedevs\",\"thebeedevs\"],\"image\":[\"https://images.hive.blog/1536x0/https://hackmd.io/_uploads/Hypprp8Exg.png\"],\"author\":\"\"}", + "parent_author": "", + "parent_permlink": "hive-139531" + } + } + ], + "signatures": [ + "1f0f4552e47cf22ec8c2c21044dacaca06fd7f170a0a1888f236d9c93e68264c117678ac4e430925ef08a55ded88fd6c26ab2f0bfc119208b8c96b9a7d94c721c5" + ], + "ref_block_num": 14060, + "ref_block_prefix": 2524420619 + }, + { + "expiration": "2025-07-15T09:51:46", + "extensions": [], + "operations": [ + { + "type": "comment_operation", + "value": { + "body": "# Hi To Hive! 🐝\n\nI am a software developer who loves frontend technologies especially creating UI applications. Great **Look 'n' Feel** like also ergonomy are my best principles in the app development.\n \nIt's been over a year since I started my journey developing on Hive, and now — after some strong encouragement from [@gtg](/@gtg) and [@small.minion](/@small.minion) — I finally decided to share my work with you! 😄\n\n\n![image](https://hackmd.io/_uploads/Hypprp8Exg.png)\n\n\n## Short Summary\n\n### Welcome to Wax! 🕯️\n\nI hope by now you've all heard about **Wax** (thanks to [@thebeedevs' article](/@thebeedevs/for-those-developing-a-hive)). This library is a powerful toolset for interacting with Hive, and it didn’t take long before I became deeply involved in improving and testing it.\n\nAt first, I treated **Wax** as a black box 📦 — something powerful, but a bit mysterious. It was also a little gluey like true beewax. 🙂 My missing knowledge specific to Hive platform also made our relationship difficult. 🤔\n\nBut honestly, without great support for IDE intellisense, involving into Hive developer platform would be dramatically hard. I started by exploring how transactions work and slowly learned what **Wax** offers. \n\nSince then, **Wax** has taken a few steps forward — and of course, to ensure it's as great as we intended, someone had to test it thoroughly. 🧪\n\n### Wax well tested! 🕵️‍♂️\n\nAs I write this, there are **thousands of lines of code** dedicated to testing **Wax's** features — and a lot of that is my work. 🧑‍💻\n\nWhat’s more, the way we test the TypeScript part of **Wax** is a bit unconventional. We wanted the tests to run in **both web and Node environments**, but without duplicating code. That’s where [Microsoft Playwright](https://playwright.dev) came in with its awesome fixture system. 🛠️\n\nThis library allows developers to define custom fixtures — reusable rules and behaviors — which extend the base Playwright `test` object. To make this setup work, we created a helper file called `jest-helper`. Although honestly, a more fitting name would be `jest-confuser`... or maybe even `jest-UNhelper`. 😅\n\nBut the twisted backstory of our `jest-helper` deserves a dedicated post of its own - it is almost imposible to shorten the story... 📚\n\nFor now, you can [take a look at current jest-helper state](https://gitlab.syncad.com/hive/wax/-/blob/7e6218a060b6bc73b4fd8323fc7be62106f6566c/ts/wasm/__tests__/assets/jest-helper.ts) - and trust me - now it looks clean! 🚿\n\n\n### Inspect all your transactions! 🔍\n\nTight integration of 🇹🇸 **Wax** layer and Hive Protocol 🇨 code ☢️, allowed us to make our dreams of visualizing the Hive authorization process come true 👂\nSince my knowledge related to **Wax** library improved significantly, the next step was to use it in practice. \n\nThat’s why I built **Transaction Inspector** - a tool created for those who've always wondered what really happens behind the scenes when blockchain rejects their transaction (which creation was occupied by a lot of sweat 💦).\n\nI'm pretty sure you've had moments in your Hive journey when you submitted a transaction and wished you could easily see all its details. That's where **Transaction Inspector** comes in — it gathers all the information in one place, making it simple to read, verify, and understand! ✅ We announced it already in the [Transaction Inspector chapter.](/hive-139531/@thebeedevs/hive-is-five)\n\n![image](https://hackmd.io/_uploads/HJWCScL4gg.png)\n\nBut wait, there's more! Let's try breaking the signature in the same transaction... 🤫\n\n![image](https://hackmd.io/_uploads/BkrpU5UEgg.png)\n\nOf course, this will end in an error — but now, thanks to Transaction Inspector, you can **analyze exactly what went wrong** and why the broadcast failed. 💥\n\nI know this is a simple case, but the tool offers many more features and is still actively being developed. So it definitely deserves a dedicated post in the future! 🚧\n\nFor now, feel free to [test it yourself!](https://tx.openhive.network/?transaction=KQdgQsAMCCwEyXoucCmAPADgSwE4EMAXbAewDt45gBmWBShOAVgFpIA2FuagFQ5ujUAHALghK8AMJQ6yZGnSFUZAM6lVE2kmBMITACJSZ2%2BihKZUBYuRWbZOiDBNzt4Y6ZceTcQgE8Ldt4AbiRKAPrmlkTqEnDSTl6JnnBB%2BAA2AK6ogfRuCZ4FzsGhljnyAOaE5bHx9klFiXD4GYQAFiS4ZZStAEYAJgB0AGYZZH2lKEb5DYWNAO6o2OWthGUAjJCbyLUzu40WuAC2adhkANZdKLioLBmYIUosbdgqLJgkKoRPJCwjYyy9PqffA9bAnABeli4kGYHG4hEgABYmExIGtwRJpvUvCBDFjCrj3C4DFM6vI1OUyEQMtdbJMtPRdES9nA1kNID0hj12EN8Gt8OxET0AMZ9HnsACc%2BGoHBAwrgwrWEuFqGFiKETCGIFQfTW7CYIGoQz6KOocERPMgqCGiJAiL6QnwcAd1HYcCGQzWqEgwuoevYPQ5qDWQj6%2BExZJ0hjizNMcGuQzCPTSJGFZzCZAyhzKZrta1JDXj1qTKbTYUwCew6BzazW1ERrsRSOMuKAA)\n(The link takes you straight to the example shown in the above screenshot 😉 — yep, that's another **cool feature!**)\n\nBeside nice design, usage simplicity and good ergonomics, I am also proud of internal architecture of the application. Strong separation of UI and data processing layers improved a lot of automated testing process like also provided good performance level.\n\nWas it a big challenge? Definitely. 😅\nWorth the effort? Absolutely. 💪\n\nWhat I can promise is another detailed post describing challenges ⚔️ I had while working on it‼️\n\n\n### Another brick in my (programming) wall 🧱: design data structures and algorithm\n\nSomewhere between commits on **Transaction Inspector**, I caught myself thinking — What if I made a bot, which could vote automatically to avoid wasting manabar? No manual transactions ⚙️, no screen-staring while waiting on full manabar 👀.\n\nEnter **VoterBee** — a bot that votes for you. The first prototype was whipped up quickly — a rough concept, built without **WorkerBee**. But let’s be honest: coding everything from scratch is a fast track to API burnout.\n\nAnd than the question appeared:\n> **Okay... but how am I supposed to use this?** 🤔\n\nThe best sign that a library’s interface is well-designed is when a developer can jump in and figure out how to achieve their goals **without needing a massive wall of documentation**.\n\nIt wasn't easy at the beggining, but now, after many iterations, tons of feedback, boards full of concepts and thoughts, and lots of code improvements, we (that is: me, the *annoying user* who keeps complaining 😅, and [@mtyszczak](/@mtyszczak), the *patient developer* who built it) finally reached the point when **WorkerBee meets that standard** ❤️‍🔥\n\nIf you're curious and want to dive deeper into the technical side of **WorkerBee**, which I strongly recommend, check out [this post](/hive-139531/@thebeedevs/meet-workerbee-the-easy-way-to-build-smart-blockchain-bots) 📚 and if you want to start using the library immediately, check out the [public repo](https://gitlab.syncad.com/hive/workerbee).\n\n## Final thoughts 🧠💬\n\nThat’s it for now! Roughly a year of hard work led to this point. 🥳\n\nThis post turned out longer than I expected — and yet I feel like I’ve only scratched the surface. There’s still a lot more I’d love to share. 😅 \n\nI hope this gave you a little insight into the tools we're building around Hive — and how we try to make them not only powerful, but actually *nice to use*. Whether you’re a developer already building on Hive or just curious about what’s under the hood, I truly believe these tools can make your life easier.\n\nAnd hey, if you try them out and something breaks — that’s a feature, not a bug. Just kidding (kind of). 😜\n\nThanks for reading and stay tuned — more is coming soon! 🚀🐝\n", + "title": "Hi To Hive! 🐝", + "author": "fwaszkiewicz", + "permlink": "hi-to-hive", + "json_metadata": "{\"format\":\"markdown+html\",\"summary\":\"From Wax testing to the Transaction Inspector tool — a frontend dev's journey building smart tools on the Hive blockchain 🐝💻\",\"app\":\"hive.blog/0.9\",\"tags\":[\"introduceyourself\",\"hive\",\"dev\",\"hivedevs\",\"thebeedevs\"],\"image\":[\"https://images.hive.blog/1536x0/https://hackmd.io/_uploads/Hypprp8Exg.png\"],\"author\":\"\"}", + "parent_author": "mtyszczak", + "parent_permlink": "hive-139531" + } + } + ], + "signatures": [ + "1f0f4552e47cf22ec8c2c21044dacaca06fd7f170a0a1888f236d9c93e68264c117678ac4e430925ef08a55ded88fd6c26ab2f0bfc119208b8c96b9a7d94c721c5" + ], + "ref_block_num": 14060, + "ref_block_prefix": 2524420619 + }, + { + "expiration": "2025-07-18T02:31:03", + "extensions": [], + "operations": [ + { + "type": "transfer_operation", + "value": { + "to": "gtg", + "from": "blocktrades", + "memo": "Daily reward | Day 721 | Lucoin in the wallet 1.000 Lu | Rank 96", + "amount": { + "nai": "@@000000021", + "amount": "10000000", + "precision": 3 + } + } + } + ], + "signatures": [ + "200126af7ac6781fa5563170b13078802a73224f794abab7b666a3009b0eeb77912e746167d9079ac2cfc7a9457cea27a7df5b6c81427a36f941daf6a4f3a12ca6" + ], + "ref_block_num": 26038, + "ref_block_prefix": 432684587 + }, + { + "expiration": "2025-07-18T02:31:03", + "extensions": [], + "operations": [ + { + "type": "transfer_operation", + "value": { + "to": "gtg", + "from": "bdhivesteem", + "memo": "Daily reward | Day 721 | Lucoin in the wallet 1.000 Lu | Rank 96", + "amount": { + "nai": "@@000000021", + "amount": "1000", + "precision": 3 + } + } + } + ], + "signatures": [ + "200126af7ac6781fa5563170b13078802a73224f794abab7b666a3009b0eeb77912e746167d9079ac2cfc7a9457cea27a7df5b6c81427a36f941daf6a4f3a12ca6" + ], + "ref_block_num": 26038, + "ref_block_prefix": 432684587 + }, + { + "expiration": "2025-07-15T20:31:28", + "extensions": [], + "operations": [ + { + "type": "comment_operation", + "value": { + "body": "Oh, I'm sorry, I haven't understood properly what you are asking for, I assumed something else.\nI think the problem is that you have \"auto power up\" setting there, it should be unchecked when you are starting power down, otherwise HP powered down will again be automatically powered up.", + "title": "", + "author": "gtg", + "permlink": "re-purepinay-1752611428637", + "json_metadata": "{\"format\":\"markdown+html\",\"app\":\"@hiveio/wax/1.27.6-rc7-stable.250708094236\"}", + "parent_author": "purepinay", + "parent_permlink": "re-gtg-2025715t104337480z" + } + } + ], + "signatures": [ + "1fd570ff32b69df3146c670c1ccc0e9b9c66f23d8a966f208af9e3637309ec13382c6681cbae24fd8c9aca238e38ec8dfc808f0d61d2c817bb381a6f03f4b432df" + ], + "ref_block_num": 26841, + "ref_block_prefix": 55555419 + } + ], + "witness": "ocd-witness", + "witness_signature": "204bc1f7343463a111570f51748aab9ca36da3fd7dfecaf2bacd2114738231275f51b4b04fecc810b2da7dcab518af03618c2bf7484be14722cc1011deb31b2843" + } + } + } + }, + { + "req": { + "jsonrpc": "2.0", + "method": "block_api.get_block", + "params": { + "block_num": 97477295 + }, + "id": 1 + }, + "res": { + "id": 1, + "jsonrpc": "2.0", + "result": { + "block": { + "block_id": "05cf62ab3f2151a60e601ed86bdb43137949873d", + "extensions": [], + "previous": "05cf62aa64e54158fd61938b410c80366004b7fd", + "signing_key": "STM6LLegbAgLAy28EHrffBVuANFWcFgmqRMW13wBmTExqFE9SCkg4", + "timestamp": "2025-07-16T10:29:18", + "transaction_ids": [], + "transaction_merkle_root": "0000000000000000000000000000000000000000", + "transactions": [], + "witness": "ocd-witness", + "witness_signature": "204bc1f7343463a111570f51748aab9ca36da3fd7dfecaf2bacd2114738231275f51b4b04fecc810b2da7dcab518af03618c2bf7484be14722cc1011deb31b2843" + } + } + } + }, + { + "req": { + "jsonrpc": "2.0", + "method": "block_api.get_block", + "params": { + "block_num": 97477296 + }, + "id": 1 + }, + "res": { + "id": 1, + "jsonrpc": "2.0", + "result": { + "block": { + "block_id": "05cf62ab3f2151a60e601ed86bdb43137949873d", + "extensions": [], + "previous": "05cf62aa64e54158fd61938b410c80366004b7fd", + "signing_key": "STM6LLegbAgLAy28EHrffBVuANFWcFgmqRMW13wBmTExqFE9SCkg4", + "timestamp": "2025-07-16T10:29:18", + "transaction_ids": [ + "3f6a99bf0106bcb9d77a2119ebc559a1f4a0343d" + ], + "transaction_merkle_root": "0000000000000000000000000000000000000000", + "transactions": [ + { + "expiration": "2025-05-14T20:06:28", + "extensions": [], + "operations": [ + { + "type": "comment_operation", + "value": { + "body": "HiveFest is back for another round, usually unusual and boringly awesome as always. For the fourth time, we're partnering not with a single airline, but with the entire SkyTeam airline alliance as our official travel partner!\n\n![Sky is the limit... or is it?](https://images.hive.blog/DQmRDoi3dAqoCPF6ji1riLGMNcj2ESHbQar9DkWSnu4q78a/hive_clouds2.png)\n\n> _The airlines of SkyTeam, your Preferred Alliance for travel, offer exclusive discounts of up to 15% on all SkyTeam airlines serving 1,088 destinations\nin 184 countries with over 10,084 daily flights._\n\n# SkyTeam Airlines:\n- Aerolíneas Argentinas\n- Aeroméxico\n- Air Europa\n- Air France\n- China Airlines\n- China Eastern Airlines\n- Delta Air Lines\n- Garuda Indonesia\n- Kenya Airways\n- KLM Royal Dutch Airlines\n- Korean Air\n- Middle East Airlines\n- Saudia\n- TAROM\n- Vietnam Airlines\n- Virgin Atlantic\n- Xiamen Airlines\n\n# How to book\nUse this link:\n[https://res.skyteam.com/Search/promoDefault.aspx?vendor=sky&promocode=5121S](https://res.skyteam.com/Search/promoDefault.aspx?vendor=sky&promocode=5121S)\nor provide the unique Event ID while booking.\n\n#### Event ID: `5121S`\n#### Valid Departure Dates: **08/10/2025 – 26/10/2025**\n\n> \"Only Participants and one companion traveling with the Participant within the designated travel period (7 days prior/post the Event date) to and from the Event and able to provide the qualifying \"Event ID\", are eligible to benefit from the discount offer. Please note that a proof of participation to an Event may be requested at any time during a Participant's journey (i.e. a HiveFest ticket).\"\n\n![Your job is the event, ours is the travel](https://a.storyblok.com/f/271050/585x150/445bdd642b/skyteam-anniversary-logo.png)\n\n## _“SkyTeam is pleased to be your preferred alliance for travel, official partner of HiveFest”_\n\nHiveFest lands in vibrant Kuala Lumpur, Malaysia from 15 to 19 October 2025, bringing together Hive users, builders, creators and decentralization dreamers for its 10th edition. Join us for five days of tropical vibes, real conversations and practical Web3 energy. Explore blockchain apps that people actually use, meet the humans behind the handles and discover what makes Hive and its ecosystem uniquely resilient. Whether you're Hive-native or Web3-curious, HiveFest is your gateway to a creative, decentralized future in real life.\n\n![HiveFest10](https://trisept.widen.net/content/kokt7jl5d6/png/SKT_IMG_PROMO_Event_5121_HiveFest10-KUL.png)\n\nFor more details about the event, visit [https://hivefe.st](https://hivefe.st) – the site is continuously updated as the event details crystallize.\n", + "title": "SkyTeam Airline Alliance - Official partner of HiveFest", + "author": "gtg", + "permlink": "67juuw-skyteam-airline-alliance-official-partner-of-hivefest", + "json_metadata": "{\"format\":\"markdown+html\",\"summary\":\"\",\"app\":\"hive.blog/0.9\",\"tags\":[\"hivefest\",\"hivefest10\",\"roadtohivefest\",\"hive\",\"travel\",\"kul\",\"malaysia\",\"skyteam\"],\"image\":[\"https://images.hive.blog/1536x0/https://trisept.widen.net/content/kokt7jl5d6/png/SKT_IMG_PROMO_Event_5121_HiveFest10-KUL.png\"],\"author\":\"\"}", + "parent_author": "", + "parent_permlink": "hive-106258" + } + }, + { + "type": "comment_options_operation", + "value": { + "author": "gtg", + "permlink": "67juuw-skyteam-airline-alliance-official-partner-of-hivefest", + "extensions": [], + "allow_votes": true, + "percent_hbd": 10000, + "max_accepted_payout": { + "nai": "@@000000013", + "amount": "1000000000", + "precision": 3 + }, + "allow_curation_rewards": true + } + } + ], + "signatures": [ + "202b0bb03c7594a3b761311b23e8e48a966970073443b1f566a60b88eb52167fee579f31af223692258e66626d49fbf4bdd27a056c8fde9244f46a136c97c98e82" + ], + "ref_block_num": 12359, + "ref_block_prefix": 2019715493 + } + ], + "witness": "ocd-witness", + "witness_signature": "204bc1f7343463a111570f51748aab9ca36da3fd7dfecaf2bacd2114738231275f51b4b04fecc810b2da7dcab518af03618c2bf7484be14722cc1011deb31b2843" + } + } + } + }, + { + "req": { + "jsonrpc": "2.0", + "method": "block_api.get_block", + "params": { + "block_num": 97477297 + }, + "id": 1 + }, + "res": { + "id": 1, + "jsonrpc": "2.0", + "result": { + "block": { + "block_id": "05cf62ab3f2151a60e601ed86bdb43137949873d", + "extensions": [], + "previous": "05cf62aa64e54158fd61938b410c80366004b7fd", + "signing_key": "STM6LLegbAgLAy28EHrffBVuANFWcFgmqRMW13wBmTExqFE9SCkg4", + "timestamp": "2025-07-16T10:29:18", + "transaction_ids": [], + "transaction_merkle_root": "0000000000000000000000000000000000000000", + "transactions": [], + "witness": "ocd-witness", + "witness_signature": "204bc1f7343463a111570f51748aab9ca36da3fd7dfecaf2bacd2114738231275f51b4b04fecc810b2da7dcab518af03618c2bf7484be14722cc1011deb31b2843" + } + } + } + }, + { + "req": { + "jsonrpc": "2.0", + "method": "block_api.get_block", + "params": { + "block_num": 97477298 + }, + "id": 1 + }, + "res": { + "id": 1, + "jsonrpc": "2.0", + "result": { + "block": { + "block_id": "05cf62ab3f2151a60e601ed86bdb43137949873d", + "extensions": [], + "previous": "05cf62aa64e54158fd61938b410c80366004b7fd", + "signing_key": "STM6LLegbAgLAy28EHrffBVuANFWcFgmqRMW13wBmTExqFE9SCkg4", + "timestamp": "2025-07-16T10:29:18", + "transaction_ids": [], + "transaction_merkle_root": "0000000000000000000000000000000000000000", + "transactions": [], + "witness": "ocd-witness", + "witness_signature": "204bc1f7343463a111570f51748aab9ca36da3fd7dfecaf2bacd2114738231275f51b4b04fecc810b2da7dcab518af03618c2bf7484be14722cc1011deb31b2843" + } + } + } + }, + { + "req": { + "jsonrpc": "2.0", + "method": "block_api.get_block", + "params": { + "block_num": 97477299 + }, + "id": 1 + }, + "res": { + "id": 1, + "jsonrpc": "2.0", + "result": { + "block": { + "block_id": "05cf62ab3f2151a60e601ed86bdb43137949873d", + "extensions": [], + "previous": "05cf62aa64e54158fd61938b410c80366004b7fd", + "signing_key": "STM6LLegbAgLAy28EHrffBVuANFWcFgmqRMW13wBmTExqFE9SCkg4", + "timestamp": "2025-07-16T10:29:18", + "transaction_ids": [], + "transaction_merkle_root": "0000000000000000000000000000000000000000", + "transactions": [], + "witness": "ocd-witness", + "witness_signature": "204bc1f7343463a111570f51748aab9ca36da3fd7dfecaf2bacd2114738231275f51b4b04fecc810b2da7dcab518af03618c2bf7484be14722cc1011deb31b2843" + } + } + } + }, + { + "req": { + "jsonrpc": "2.0", + "method": "block_api.get_block", + "params": { + "block_num": 97477300 + }, + "id": 1 + }, + "res": { + "id": 1, + "jsonrpc": "2.0", + "result": { + "block": { + "block_id": "05cf62ab3f2151a60e601ed86bdb43137949873d", + "extensions": [], + "previous": "05cf62aa64e54158fd61938b410c80366004b7fd", + "signing_key": "STM6LLegbAgLAy28EHrffBVuANFWcFgmqRMW13wBmTExqFE9SCkg4", + "timestamp": "2025-07-16T10:29:18", + "transaction_ids": [], + "transaction_merkle_root": "0000000000000000000000000000000000000000", + "transactions": [], + "witness": "ocd-witness", + "witness_signature": "204bc1f7343463a111570f51748aab9ca36da3fd7dfecaf2bacd2114738231275f51b4b04fecc810b2da7dcab518af03618c2bf7484be14722cc1011deb31b2843" + } + } + } + } +] \ No newline at end of file diff --git a/__tests__/assets/api-call-logs/database_api_find_accounts.json b/__tests__/assets/api-call-logs/database_api_find_accounts.json new file mode 100644 index 0000000..4f818ea --- /dev/null +++ b/__tests__/assets/api-call-logs/database_api_find_accounts.json @@ -0,0 +1,1794 @@ +[ + { + "req": { + "jsonrpc": "2.0", + "method": "database_api.find_accounts", + "params": { + "accounts": [ + "gtg", + "blocktrades", + "thebeedevs" + ] + }, + "id": 1 + }, + "res": { + "id": 1, + "jsonrpc": "2.0", + "result": { + "accounts": [ + { + "active": { + "account_auths": [], + "key_auths": [ + [ + "STM8NWQYG4BvjGNu8zqqV9fbR7aSCZHcxkVib41PYnpGmPRe6BHVG", + 1 + ] + ], + "weight_threshold": 1 + }, + "balance": { + "amount": "0", + "nai": "@@000000021", + "precision": 3 + }, + "can_vote": true, + "comment_count": 0, + "created": "2016-06-30T17:22:21", + "curation_rewards": 448470260, + "delayed_votes": [], + "delegated_vesting_shares": { + "amount": "0", + "nai": "@@000000037", + "precision": 6 + }, + "downvote_manabar": { + "current_mana": 735609018860040, + "last_update_time": 1753096515 + }, + "governance_vote_expiration_ts": "2026-06-26T16:55:21", + "hbd_balance": { + "amount": "0", + "nai": "@@000000013", + "precision": 3 + }, + "hbd_last_interest_payment": "2021-06-13T21:34:42", + "hbd_seconds": "26576708016", + "hbd_seconds_last_update": "2021-06-30T11:10:30", + "id": 14007, + "is_smt": false, + "json_metadata": "{\"profile\":{\"witness_description\": \"Gandalf the Grey, building Hive, improving Hive infrastructure.\",\"profile_image\":\"https://grey.house/img/grey_4.jpg\",\"name\":\"Gandalf the Grey\",\"about\":\"IT Wizard, Hive Witness\",\"location\":\"Hive\",\"version\":2}}", + "last_account_recovery": "2016-07-21T21:48:06", + "last_account_update": "2024-10-24T14:19:24", + "last_owner_update": "2017-03-21T18:37:42", + "last_post": "2025-07-20T18:19:45", + "last_post_edit": "2025-07-20T18:19:45", + "last_root_post": "2025-05-14T20:05:27", + "last_vote_time": "2025-07-21T10:40:06", + "lifetime_vote_count": 0, + "memo_key": "STM4uD3dfLvbz7Tkd7of4K9VYGnkgrY5BHSQt52vE52CBL5qBfKHN", + "mined": true, + "name": "gtg", + "next_vesting_withdrawal": "1969-12-31T23:59:59", + "open_recurrent_transfers": 0, + "owner": { + "account_auths": [], + "key_auths": [ + [ + "STM5RLQ1Jh8Kf56go3xpzoodg4vRsgCeWhANXoEXrYH7bLEwSVyjh", + 1 + ] + ], + "weight_threshold": 1 + }, + "pending_claimed_accounts": 67846, + "pending_transfers": 0, + "post_bandwidth": 10000, + "post_count": 7117, + "post_voting_power": { + "amount": "2942436075440162", + "nai": "@@000000037", + "precision": 6 + }, + "posting": { + "account_auths": [ + [ + "voterbee", + 1 + ] + ], + "key_auths": [ + [ + "STM5tp5hWbGLL1R3tMVsgYdYxLPyAQFdKoYFbT2hcWUmrU42p1MQC", + 1 + ] + ], + "weight_threshold": 1 + }, + "posting_json_metadata": "{\"profile\":{\"witness_description\":\"Gandalf the Grey, Building Hive.\",\"about\":\"IT Wizard, Hive Witness\",\"profile_image\":\"https://grey.house/img/grey_4.jpg\",\"name\":\"Gandalf the Grey\",\"location\":\"Hive\",\"version\":2}}", + "posting_rewards": 22416928, + "previous_owner_update": "2016-07-21T21:48:03", + "proxied_vsf_votes": [ + 6318802112650823, + 67757102670970, + 0, + 0 + ], + "proxy": "", + "received_vesting_shares": { + "amount": "106902000000", + "nai": "@@000000037", + "precision": 6 + }, + "recovery_account": "roelandp", + "reset_account": "null", + "reward_hbd_balance": { + "amount": "0", + "nai": "@@000000013", + "precision": 3 + }, + "reward_hive_balance": { + "amount": "0", + "nai": "@@000000021", + "precision": 3 + }, + "reward_vesting_balance": { + "amount": "0", + "nai": "@@000000037", + "precision": 6 + }, + "reward_vesting_hive": { + "amount": "0", + "nai": "@@000000021", + "precision": 3 + }, + "savings_balance": { + "amount": "0", + "nai": "@@000000021", + "precision": 3 + }, + "savings_hbd_balance": { + "amount": "0", + "nai": "@@000000013", + "precision": 3 + }, + "savings_hbd_last_interest_payment": "2025-07-09T09:55:15", + "savings_hbd_seconds": "0", + "savings_hbd_seconds_last_update": "2025-07-09T09:55:15", + "savings_withdraw_requests": 0, + "to_withdraw": 0, + "vesting_shares": { + "amount": "2942329173440162", + "nai": "@@000000037", + "precision": 6 + }, + "vesting_withdraw_rate": { + "amount": "0", + "nai": "@@000000037", + "precision": 6 + }, + "voting_manabar": { + "current_mana": 2897631713028020, + "last_update_time": 1753096515 + }, + "withdraw_routes": 0, + "withdrawn": 0, + "witnesses_voted_for": 29 + }, + { + "active": { + "account_auths": [], + "key_auths": [ + [ + "STM5vgGoHBrUuDCspAPYi3dLwSyistyrz61NWkZNUAXAifZJaDLPF", + 1 + ] + ], + "weight_threshold": 1 + }, + "balance": { + "amount": "590482806", + "nai": "@@000000021", + "precision": 3 + }, + "can_vote": true, + "comment_count": 0, + "created": "2016-03-30T00:04:36", + "curation_rewards": 3628059720, + "delayed_votes": [], + "delegated_vesting_shares": { + "amount": "6909522651976083", + "nai": "@@000000037", + "precision": 6 + }, + "downvote_manabar": { + "current_mana": 3891043924648526, + "last_update_time": 1753096536 + }, + "governance_vote_expiration_ts": "2026-07-03T18:05:30", + "hbd_balance": { + "amount": "45992", + "nai": "@@000000013", + "precision": 3 + }, + "hbd_last_interest_payment": "2021-06-10T03:21:45", + "hbd_seconds": "4013278129191", + "hbd_seconds_last_update": "2021-06-30T13:51:27", + "id": 440, + "is_smt": false, + "json_metadata": "{\"profile\":{\"profile_image\":\"https://s18.postimg.org/be2c25f2h/blocktrades_icon.png\"}}", + "last_account_recovery": "1970-01-01T00:00:00", + "last_account_update": "2022-03-20T20:16:48", + "last_owner_update": "2016-07-14T13:02:06", + "last_post": "2025-07-15T00:52:36", + "last_post_edit": "2025-07-15T00:52:36", + "last_root_post": "2025-07-07T22:39:36", + "last_vote_time": "2025-07-21T10:10:30", + "lifetime_vote_count": 0, + "memo_key": "STM7EAUbNf1CdTrMbydPoBTRMG4afXCoAErBJYevhgne6zEP6rVBT", + "mined": true, + "name": "blocktrades", + "next_vesting_withdrawal": "1969-12-31T23:59:59", + "open_recurrent_transfers": 0, + "owner": { + "account_auths": [], + "key_auths": [ + [ + "STM7WdrxF6iuSiHUB4maoLGXXBKXbqAJ9AZbzACX1MPK2AkuCh23S", + 1 + ] + ], + "weight_threshold": 1 + }, + "pending_claimed_accounts": 470490, + "pending_transfers": 0, + "post_bandwidth": 10000, + "post_count": 4897, + "post_voting_power": { + "amount": "15564175698594105", + "nai": "@@000000037", + "precision": 6 + }, + "posting": { + "account_auths": [ + [ + "downvote-tool", + 1 + ], + [ + "steemauto", + 1 + ] + ], + "key_auths": [ + [ + "STM8UVQ7xATRUYNJkbrctSqo7FAexKoJqHAUjHWXLs2oGtS3MDCUV", + 1 + ] + ], + "weight_threshold": 1 + }, + "posting_json_metadata": "{\"profile\":{\"profile_image\":\"https://s18.postimg.org/be2c25f2h/blocktrades_icon.png\",\"about\":\"Exchange cryptocurrency fast and easy\",\"website\":\"https://blocktrades.us\",\"version\":2},\"did\":\"did:3:kjzl6cwe1jw147kr5qe9lkaqr83j33wzt64c29sa0oviewxjpuihrbabc2658qj\"}", + "posting_rewards": 128567416, + "previous_owner_update": "1970-01-01T00:00:00", + "proxied_vsf_votes": [ + "23816257853602808", + 0, + 0, + 0 + ], + "proxy": "", + "received_vesting_shares": { + "amount": "93229078992219", + "nai": "@@000000037", + "precision": 6 + }, + "recovery_account": "steem", + "reset_account": "null", + "reward_hbd_balance": { + "amount": "38694", + "nai": "@@000000013", + "precision": 3 + }, + "reward_hive_balance": { + "amount": "0", + "nai": "@@000000021", + "precision": 3 + }, + "reward_vesting_balance": { + "amount": "43370994600027", + "nai": "@@000000037", + "precision": 6 + }, + "reward_vesting_hive": { + "amount": "26026745", + "nai": "@@000000021", + "precision": 3 + }, + "savings_balance": { + "amount": "52795", + "nai": "@@000000021", + "precision": 3 + }, + "savings_hbd_balance": { + "amount": "130076015", + "nai": "@@000000013", + "precision": 3 + }, + "savings_hbd_last_interest_payment": "2025-07-05T06:05:48", + "savings_hbd_seconds": "0", + "savings_hbd_seconds_last_update": "2025-07-05T06:05:48", + "savings_withdraw_requests": 0, + "to_withdraw": 0, + "vesting_shares": { + "amount": "22380469271577969", + "nai": "@@000000037", + "precision": 6 + }, + "vesting_withdraw_rate": { + "amount": "0", + "nai": "@@000000037", + "precision": 6 + }, + "voting_manabar": { + "current_mana": 8749216332432022, + "last_update_time": 1753096536 + }, + "withdraw_routes": 3, + "withdrawn": 0, + "witnesses_voted_for": 27 + }, + { + "active": { + "account_auths": [], + "key_auths": [ + [ + "STM8CidwjgjWMU1yFrr5dRpMddJ3sqwpUJ2vvN8nX3UV6GkoJcu1Z", + 1 + ] + ], + "weight_threshold": 1 + }, + "balance": { + "amount": "174", + "nai": "@@000000021", + "precision": 3 + }, + "can_vote": true, + "comment_count": 0, + "created": "2023-09-14T11:06:45", + "curation_rewards": 191294, + "delayed_votes": [], + "delegated_vesting_shares": { + "amount": "0", + "nai": "@@000000037", + "precision": 6 + }, + "downvote_manabar": { + "current_mana": 961490159759, + "last_update_time": 1753095357 + }, + "governance_vote_expiration_ts": "2025-07-23T17:47:06", + "hbd_balance": { + "amount": "0", + "nai": "@@000000013", + "precision": 3 + }, + "hbd_last_interest_payment": "1970-01-01T00:00:00", + "hbd_seconds": "0", + "hbd_seconds_last_update": "1970-01-01T00:00:00", + "id": 2471034, + "is_smt": false, + "json_metadata": "", + "last_account_recovery": "1970-01-01T00:00:00", + "last_account_update": "2025-07-10T14:40:30", + "last_owner_update": "1970-01-01T00:00:00", + "last_post": "2025-07-17T13:46:51", + "last_post_edit": "2025-07-17T13:46:51", + "last_root_post": "2025-07-17T13:46:51", + "last_vote_time": "2025-07-21T10:55:57", + "lifetime_vote_count": 0, + "memo_key": "STM5KXGmNUBca3f35Y5sp6Vv42LA8AwGkDVZC6E42M3vzrXQYQ4Xh", + "mined": false, + "name": "thebeedevs", + "next_vesting_withdrawal": "1969-12-31T23:59:59", + "open_recurrent_transfers": 0, + "owner": { + "account_auths": [], + "key_auths": [ + [ + "STM7uwP8TNxSvZZKkVmnAC26iKo9wthwfzS6vax2Uh2AkqQuCQfRh", + 1 + ] + ], + "weight_threshold": 1 + }, + "pending_claimed_accounts": 0, + "pending_transfers": 0, + "post_bandwidth": 0, + "post_count": 41, + "post_voting_power": { + "amount": "3845960639036", + "nai": "@@000000037", + "precision": 6 + }, + "posting": { + "account_auths": [ + [ + "itsola", + 1 + ], + [ + "mtyszczak", + 1 + ], + [ + "small.minion", + 1 + ], + [ + "voterbee", + 1 + ], + [ + "zgredek", + 1 + ] + ], + "key_auths": [ + [ + "STM6ovoFrK6WMsh6pTDNMywPuFpAsa5HJbubeyZZsQmhs16Nq6knq", + 1 + ] + ], + "weight_threshold": 1 + }, + "posting_json_metadata": "{\"profile\":{\"profile_image\":\"https://images.hive.blog/DQmNzDBjKGhadc6A8AYyD93SZkJ9RHtS15LSzK3Fw5Da6gw/clive_bee_logo.png\",\"version\":2}}", + "posting_rewards": 5189943, + "previous_owner_update": "1970-01-01T00:00:00", + "proxied_vsf_votes": [ + 0, + 0, + 0, + 0 + ], + "proxy": "gtg", + "received_vesting_shares": { + "amount": "0", + "nai": "@@000000037", + "precision": 6 + }, + "recovery_account": "gtg", + "reset_account": "null", + "reward_hbd_balance": { + "amount": "47896", + "nai": "@@000000013", + "precision": 3 + }, + "reward_hive_balance": { + "amount": "0", + "nai": "@@000000021", + "precision": 3 + }, + "reward_vesting_balance": { + "amount": "382909579592", + "nai": "@@000000037", + "precision": 6 + }, + "reward_vesting_hive": { + "amount": "229366", + "nai": "@@000000021", + "precision": 3 + }, + "savings_balance": { + "amount": "0", + "nai": "@@000000021", + "precision": 3 + }, + "savings_hbd_balance": { + "amount": "215216", + "nai": "@@000000013", + "precision": 3 + }, + "savings_hbd_last_interest_payment": "2025-06-09T22:33:27", + "savings_hbd_seconds": "460310127789", + "savings_hbd_seconds_last_update": "2025-07-09T10:57:24", + "savings_withdraw_requests": 0, + "to_withdraw": 0, + "vesting_shares": { + "amount": "3845960639036", + "nai": "@@000000037", + "precision": 6 + }, + "vesting_withdraw_rate": { + "amount": "0", + "nai": "@@000000037", + "precision": 6 + }, + "voting_manabar": { + "current_mana": 3768713604826, + "last_update_time": 1753095357 + }, + "withdraw_routes": 0, + "withdrawn": 0, + "witnesses_voted_for": 0 + } + ] + } + } + }, + { + "req": { + "jsonrpc": "2.0", + "method": "database_api.find_accounts", + "params": { + "accounts": [ + "gtg" + ] + }, + "id": 1 + }, + "res": { + "jsonrpc": "2.0", + "result": { + "accounts": [ + { + "id": 14007, + "name": "gtg", + "owner": { + "weight_threshold": 1, + "account_auths": [], + "key_auths": [ + [ + "STM5RLQ1Jh8Kf56go3xpzoodg4vRsgCeWhANXoEXrYH7bLEwSVyjh", + 1 + ], + [ + "STM6LLegbAgLAy28EHrffBVuANFWcFgmqRMW13wBmTExqFE9SCkg4", + 1 + ] + ] + }, + "active": { + "weight_threshold": 1, + "account_auths": [], + "key_auths": [ + [ + "STM4vuEE8F2xyJhwiNCnHxjUVLNXxdFXtVxgghBq5LVLt49zLKLRX", + 1 + ], + [ + "STM6LLegbAgLAy28EHrffBVuANFWcFgmqRMW13wBmTExqFE9SCkg4", + 1 + ] + ] + }, + "posting": { + "weight_threshold": 1, + "account_auths": [], + "key_auths": [ + [ + "STM5tp5hWbGLL1R3tMVsgYdYxLPyAQFdKoYFbT2hcWUmrU42p1MQC", + 1 + ], + [ + "STM6LLegbAgLAy28EHrffBVuANFWcFgmqRMW13wBmTExqFE9SCkg4", + 1 + ] + ] + }, + "memo_key": "STM4uD3dfLvbz7Tkd7of4K9VYGnkgrY5BHSQt52vE52CBL5qBfKHN", + "json_metadata": "", + "posting_json_metadata": "", + "proxy": "", + "previous_owner_update": "2016-07-14T23:05:30", + "last_owner_update": "2016-07-21T21:48:03", + "last_account_update": "2016-07-21T21:48:06", + "created": "2016-06-30T17:22:21", + "mined": true, + "recovery_account": "steem", + "last_account_recovery": "2016-07-21T21:48:06", + "reset_account": "null", + "comment_count": 0, + "lifetime_vote_count": 0, + "post_count": 57, + "can_vote": true, + "voting_manabar": { + "current_mana": 18469160006473, + "last_update_time": 1474663833 + }, + "downvote_manabar": { + "current_mana": 4617290001618, + "last_update_time": 1474663833 + }, + "balance": { + "amount": "0", + "precision": 3, + "nai": "@@000000021" + }, + "savings_balance": { + "amount": "0", + "precision": 3, + "nai": "@@000000021" + }, + "hbd_balance": { + "amount": "3465", + "precision": 3, + "nai": "@@000000013" + }, + "hbd_seconds": "0", + "hbd_seconds_last_update": "2016-09-09T17:18:09", + "hbd_last_interest_payment": "2016-09-09T17:18:09", + "savings_hbd_balance": { + "amount": "3468", + "precision": 3, + "nai": "@@000000013" + }, + "savings_hbd_seconds": "0", + "savings_hbd_seconds_last_update": "1970-01-01T00:00:00", + "savings_hbd_last_interest_payment": "1970-01-01T00:00:00", + "savings_withdraw_requests": 0, + "reward_hbd_balance": { + "amount": "194", + "precision": 3, + "nai": "@@000000013" + }, + "reward_hive_balance": { + "amount": "0", + "precision": 3, + "nai": "@@000000021" + }, + "reward_vesting_balance": { + "amount": "2617000164", + "precision": 6, + "nai": "@@000000037" + }, + "reward_vesting_hive": { + "amount": "872", + "precision": 3, + "nai": "@@000000021" + }, + "vesting_shares": { + "amount": "18469160006473", + "precision": 6, + "nai": "@@000000037" + }, + "delegated_vesting_shares": { + "amount": "0", + "precision": 6, + "nai": "@@000000037" + }, + "received_vesting_shares": { + "amount": "0", + "precision": 6, + "nai": "@@000000037" + }, + "vesting_withdraw_rate": { + "amount": "0", + "precision": 6, + "nai": "@@000000037" + }, + "post_voting_power": { + "amount": "18469160006473", + "precision": 6, + "nai": "@@000000037" + }, + "next_vesting_withdrawal": "1969-12-31T23:59:59", + "withdrawn": 0, + "to_withdraw": 0, + "withdraw_routes": 0, + "pending_transfers": 0, + "curation_rewards": 20403, + "posting_rewards": 1973628, + "proxied_vsf_votes": [ + 30412408791348, + 438966760068, + 0, + 0 + ], + "witnesses_voted_for": 20, + "last_post": "2016-11-14T20:57:27", + "last_root_post": "2016-10-10T20:55:45", + "last_post_edit": "2016-11-14T20:57:27", + "last_vote_time": "2016-09-15T19:46:21", + "post_bandwidth": 10000, + "pending_claimed_accounts": 0, + "open_recurrent_transfers": 0, + "is_smt": false, + "delayed_votes": [], + "governance_vote_expiration_ts": "2017-09-14T10:54:48" + } + ] + }, + "id": 1 + } + }, + { + "req": { + "jsonrpc": "2.0", + "method": "database_api.find_accounts", + "params": { + "accounts": [ + "gtg" + ] + }, + "id": 1 + }, + "res": { + "jsonrpc": "2.0", + "result": { + "accounts": [ + { + "id": 14007, + "name": "gtg", + "owner": { + "weight_threshold": 1, + "account_auths": [], + "key_auths": [ + [ + "STM5RLQ1Jh8Kf56go3xpzoodg4vRsgCeWhANXoEXrYH7bLEwSVyjh", + 1 + ], + [ + "STM6LLegbAgLAy28EHrffBVuANFWcFgmqRMW13wBmTExqFE9SCkg4", + 1 + ] + ] + }, + "active": { + "weight_threshold": 1, + "account_auths": [], + "key_auths": [ + [ + "STM4vuEE8F2xyJhwiNCnHxjUVLNXxdFXtVxgghBq5LVLt49zLKLRX", + 1 + ], + [ + "STM6LLegbAgLAy28EHrffBVuANFWcFgmqRMW13wBmTExqFE9SCkg4", + 1 + ] + ] + }, + "posting": { + "weight_threshold": 1, + "account_auths": [], + "key_auths": [ + [ + "STM5tp5hWbGLL1R3tMVsgYdYxLPyAQFdKoYFbT2hcWUmrU42p1MQC", + 1 + ], + [ + "STM6LLegbAgLAy28EHrffBVuANFWcFgmqRMW13wBmTExqFE9SCkg4", + 1 + ] + ] + }, + "memo_key": "STM4uD3dfLvbz7Tkd7of4K9VYGnkgrY5BHSQt52vE52CBL5qBfKHN", + "json_metadata": "{\"profile\":{\"witness_description\": \"Gandalf the Grey, building Hive, improving Hive infrastructure.\",\"profile_image\":\"https://grey.house/img/grey_4.jpg\",\"name\":\"Gandalf the Grey\",\"about\":\"IT Wizard, Hive Witness\",\"location\":\"Hive\",\"version\":2}}", + "posting_json_metadata": "", + "proxy": "", + "previous_owner_update": "2016-07-14T23:05:30", + "last_owner_update": "2016-07-21T21:48:03", + "last_account_update": "2016-07-21T21:48:06", + "created": "2016-06-30T17:22:21", + "mined": true, + "recovery_account": "steem", + "last_account_recovery": "2016-07-21T21:48:06", + "reset_account": "null", + "comment_count": 0, + "lifetime_vote_count": 0, + "post_count": 57, + "can_vote": true, + "voting_manabar": { + "current_mana": 18469160006473, + "last_update_time": 1474663833 + }, + "downvote_manabar": { + "current_mana": 4617290001618, + "last_update_time": 1474663833 + }, + "balance": { + "amount": "0", + "precision": 3, + "nai": "@@000000021" + }, + "savings_balance": { + "amount": "0", + "precision": 3, + "nai": "@@000000021" + }, + "hbd_balance": { + "amount": "3465", + "precision": 3, + "nai": "@@000000013" + }, + "hbd_seconds": "0", + "hbd_seconds_last_update": "2016-09-09T17:18:09", + "hbd_last_interest_payment": "2016-09-09T17:18:09", + "savings_hbd_balance": { + "amount": "0", + "precision": 3, + "nai": "@@000000013" + }, + "savings_hbd_seconds": "0", + "savings_hbd_seconds_last_update": "1970-01-01T00:00:00", + "savings_hbd_last_interest_payment": "1970-01-01T00:00:00", + "savings_withdraw_requests": 0, + "reward_hbd_balance": { + "amount": "194", + "precision": 3, + "nai": "@@000000013" + }, + "reward_hive_balance": { + "amount": "0", + "precision": 3, + "nai": "@@000000021" + }, + "reward_vesting_balance": { + "amount": "2617000164", + "precision": 6, + "nai": "@@000000037" + }, + "reward_vesting_hive": { + "amount": "872", + "precision": 3, + "nai": "@@000000021" + }, + "vesting_shares": { + "amount": "18469160006473", + "precision": 6, + "nai": "@@000000037" + }, + "delegated_vesting_shares": { + "amount": "0", + "precision": 6, + "nai": "@@000000037" + }, + "received_vesting_shares": { + "amount": "0", + "precision": 6, + "nai": "@@000000037" + }, + "vesting_withdraw_rate": { + "amount": "0", + "precision": 6, + "nai": "@@000000037" + }, + "post_voting_power": { + "amount": "18469160006473", + "precision": 6, + "nai": "@@000000037" + }, + "next_vesting_withdrawal": "1969-12-31T23:59:59", + "withdrawn": 0, + "to_withdraw": 0, + "withdraw_routes": 0, + "pending_transfers": 0, + "curation_rewards": 20403, + "posting_rewards": 1973628, + "proxied_vsf_votes": [ + 30412408791348, + 438966760068, + 0, + 0 + ], + "witnesses_voted_for": 20, + "last_post": "2016-11-14T20:57:27", + "last_root_post": "2016-10-10T20:55:45", + "last_post_edit": "2016-11-14T20:57:27", + "last_vote_time": "2016-09-15T19:46:21", + "post_bandwidth": 10000, + "pending_claimed_accounts": 0, + "open_recurrent_transfers": 0, + "is_smt": false, + "delayed_votes": [], + "governance_vote_expiration_ts": "2017-09-14T10:54:48" + } + ] + }, + "id": 1 + } + }, + { + "req": { + "jsonrpc": "2.0", + "method": "database_api.find_accounts", + "params": { + "accounts": [ + "gtg" + ] + }, + "id": 1 + }, + "res": { + "jsonrpc": "2.0", + "result": { + "accounts": [ + { + "id": 14007, + "name": "gtg", + "owner": { + "weight_threshold": 1, + "account_auths": [], + "key_auths": [ + [ + "STM5RLQ1Jh8Kf56go3xpzoodg4vRsgCeWhANXoEXrYH7bLEwSVyjh", + 1 + ], + [ + "STM6LLegbAgLAy28EHrffBVuANFWcFgmqRMW13wBmTExqFE9SCkg4", + 1 + ] + ] + }, + "active": { + "weight_threshold": 1, + "account_auths": [], + "key_auths": [ + [ + "STM4vuEE8F2xyJhwiNCnHxjUVLNXxdFXtVxgghBq5LVLt49zLKLRX", + 1 + ], + [ + "STM6LLegbAgLAy28EHrffBVuANFWcFgmqRMW13wBmTExqFE9SCkg4", + 1 + ] + ] + }, + "posting": { + "weight_threshold": 1, + "account_auths": [], + "key_auths": [ + [ + "STM5tp5hWbGLL1R3tMVsgYdYxLPyAQFdKoYFbT2hcWUmrU42p1MQC", + 1 + ], + [ + "STM6LLegbAgLAy28EHrffBVuANFWcFgmqRMW13wBmTExqFE9SCkg4", + 1 + ] + ] + }, + "memo_key": "STM4uD3dfLvbz7Tkd7of4K9VYGnkgrY5BHSQt52vE52CBL5qBfKHN", + "json_metadata": "{\"profile\":{\"witness_description\": \"Gandalf the Grey, building Hive, improving Hive infrastructure.\",\"profile_image\":\"https://grey.house/img/grey_4.jpg\",\"name\":\"Gandalf the Grey\",\"about\":\"IT Wizard, Hive Witness\",\"location\":\"Hive\",\"version\":2}}", + "posting_json_metadata": "", + "proxy": "", + "previous_owner_update": "2016-07-14T23:05:30", + "last_owner_update": "2016-07-21T21:48:03", + "last_account_update": "2016-07-21T21:48:06", + "created": "2016-06-30T17:22:21", + "mined": true, + "recovery_account": "steem", + "last_account_recovery": "2016-07-21T21:48:06", + "reset_account": "null", + "comment_count": 0, + "lifetime_vote_count": 0, + "post_count": 57, + "can_vote": true, + "voting_manabar": { + "current_mana": 2890067228183842, + "last_update_time": 1474663833 + }, + "downvote_manabar": { + "current_mana": 4617290001618, + "last_update_time": 1474663833 + }, + "balance": { + "amount": "0", + "precision": 3, + "nai": "@@000000021" + }, + "savings_balance": { + "amount": "0", + "precision": 3, + "nai": "@@000000021" + }, + "hbd_balance": { + "amount": "3468", + "precision": 3, + "nai": "@@000000013" + }, + "hbd_seconds": "0", + "hbd_seconds_last_update": "2016-09-09T17:18:09", + "hbd_last_interest_payment": "2016-09-09T17:18:09", + "savings_hbd_balance": { + "amount": "3468", + "precision": 3, + "nai": "@@000000013" + }, + "savings_hbd_seconds": "0", + "savings_hbd_seconds_last_update": "1970-01-01T00:00:00", + "savings_hbd_last_interest_payment": "1970-01-01T00:00:00", + "savings_withdraw_requests": 0, + "reward_hbd_balance": { + "amount": "194", + "precision": 3, + "nai": "@@000000013" + }, + "reward_hive_balance": { + "amount": "0", + "precision": 3, + "nai": "@@000000021" + }, + "reward_vesting_balance": { + "amount": "2617000164", + "precision": 6, + "nai": "@@000000037" + }, + "reward_vesting_hive": { + "amount": "872", + "precision": 3, + "nai": "@@000000021" + }, + "vesting_shares": { + "amount": "18469160006473", + "precision": 6, + "nai": "@@000000037" + }, + "delegated_vesting_shares": { + "amount": "0", + "precision": 6, + "nai": "@@000000037" + }, + "received_vesting_shares": { + "amount": "0", + "precision": 6, + "nai": "@@000000037" + }, + "vesting_withdraw_rate": { + "amount": "0", + "precision": 6, + "nai": "@@000000037" + }, + "post_voting_power": { + "amount": "18469160006473", + "precision": 6, + "nai": "@@000000037" + }, + "next_vesting_withdrawal": "1969-12-31T23:59:59", + "withdrawn": 0, + "to_withdraw": 0, + "withdraw_routes": 0, + "pending_transfers": 0, + "curation_rewards": 20403, + "posting_rewards": 1973628, + "proxied_vsf_votes": [ + 30412408791348, + 438966760068, + 0, + 0 + ], + "witnesses_voted_for": 20, + "last_post": "2016-11-14T20:57:27", + "last_root_post": "2016-10-10T20:55:45", + "last_post_edit": "2016-11-14T20:57:27", + "last_vote_time": "2016-09-15T19:46:21", + "post_bandwidth": 10000, + "pending_claimed_accounts": 0, + "open_recurrent_transfers": 0, + "is_smt": false, + "delayed_votes": [], + "governance_vote_expiration_ts": "2017-09-14T10:54:48" + } + ] + }, + "id": 1 + } + }, + { + "req": { + "jsonrpc": "2.0", + "method": "database_api.find_accounts", + "params": { + "accounts": [ + "gtg" + ] + }, + "id": 1 + }, + "res": { + "jsonrpc": "2.0", + "result": { + "accounts": [ + { + "id": 14007, + "name": "gtg", + "owner": { + "weight_threshold": 1, + "account_auths": [], + "key_auths": [ + [ + "STM5RLQ1Jh8Kf56go3xpzoodg4vRsgCeWhANXoEXrYH7bLEwSVyjh", + 1 + ], + [ + "STM6LLegbAgLAy28EHrffBVuANFWcFgmqRMW13wBmTExqFE9SCkg4", + 1 + ] + ] + }, + "active": { + "weight_threshold": 1, + "account_auths": [], + "key_auths": [ + [ + "STM4vuEE8F2xyJhwiNCnHxjUVLNXxdFXtVxgghBq5LVLt49zLKLRX", + 1 + ], + [ + "STM6LLegbAgLAy28EHrffBVuANFWcFgmqRMW13wBmTExqFE9SCkg4", + 1 + ] + ] + }, + "posting": { + "weight_threshold": 1, + "account_auths": [], + "key_auths": [ + [ + "STM5tp5hWbGLL1R3tMVsgYdYxLPyAQFdKoYFbT2hcWUmrU42p1MQC", + 1 + ], + [ + "STM6LLegbAgLAy28EHrffBVuANFWcFgmqRMW13wBmTExqFE9SCkg4", + 1 + ] + ] + }, + "memo_key": "STM4uD3dfLvbz7Tkd7of4K9VYGnkgrY5BHSQt52vE52CBL5qBfKHN", + "json_metadata": "{\"profile\":{\"witness_description\": \"Gandalf the Grey, building Hive, improving Hive infrastructure.\",\"profile_image\":\"https://grey.house/img/grey_4.jpg\",\"name\":\"Gandalf the Grey\",\"about\":\"IT Wizard, Hive Witness\",\"location\":\"Hive\",\"version\":2}}", + "posting_json_metadata": "", + "proxy": "", + "previous_owner_update": "2016-07-14T23:05:30", + "last_owner_update": "2016-07-21T21:48:03", + "last_account_update": "2016-07-21T21:48:06", + "created": "2016-06-30T17:22:21", + "mined": true, + "recovery_account": "steem", + "last_account_recovery": "2016-07-21T21:48:06", + "reset_account": "null", + "comment_count": 0, + "lifetime_vote_count": 0, + "post_count": 57, + "can_vote": true, + "voting_manabar": { + "current_mana": 18469160006473, + "last_update_time": 1474663833 + }, + "downvote_manabar": { + "current_mana": 4617290001618, + "last_update_time": 1474663833 + }, + "balance": { + "amount": "0", + "precision": 3, + "nai": "@@000000021" + }, + "savings_balance": { + "amount": "0", + "precision": 3, + "nai": "@@000000021" + }, + "hbd_balance": { + "amount": "3465", + "precision": 3, + "nai": "@@000000013" + }, + "hbd_seconds": "0", + "hbd_seconds_last_update": "2016-09-09T17:18:09", + "hbd_last_interest_payment": "2016-09-09T17:18:09", + "savings_hbd_balance": { + "amount": "0", + "precision": 3, + "nai": "@@000000013" + }, + "savings_hbd_seconds": "0", + "savings_hbd_seconds_last_update": "1970-01-01T00:00:00", + "savings_hbd_last_interest_payment": "1970-01-01T00:00:00", + "savings_withdraw_requests": 0, + "reward_hbd_balance": { + "amount": "194", + "precision": 3, + "nai": "@@000000013" + }, + "reward_hive_balance": { + "amount": "0", + "precision": 3, + "nai": "@@000000021" + }, + "reward_vesting_balance": { + "amount": "2617000164", + "precision": 6, + "nai": "@@000000037" + }, + "reward_vesting_hive": { + "amount": "872", + "precision": 3, + "nai": "@@000000021" + }, + "vesting_shares": { + "amount": "18469160006473", + "precision": 6, + "nai": "@@000000037" + }, + "delegated_vesting_shares": { + "amount": "0", + "precision": 6, + "nai": "@@000000037" + }, + "received_vesting_shares": { + "amount": "0", + "precision": 6, + "nai": "@@000000037" + }, + "vesting_withdraw_rate": { + "amount": "0", + "precision": 6, + "nai": "@@000000037" + }, + "post_voting_power": { + "amount": "18469160006473", + "precision": 6, + "nai": "@@000000037" + }, + "next_vesting_withdrawal": "1969-12-31T23:59:59", + "withdrawn": 0, + "to_withdraw": 0, + "withdraw_routes": 0, + "pending_transfers": 0, + "curation_rewards": 20403, + "posting_rewards": 1973628, + "proxied_vsf_votes": [ + 30412408791348, + 438966760068, + 0, + 0 + ], + "witnesses_voted_for": 20, + "last_post": "2016-11-14T20:57:27", + "last_root_post": "2016-10-10T20:55:45", + "last_post_edit": "2016-11-14T20:57:27", + "last_vote_time": "2016-09-15T19:46:21", + "post_bandwidth": 10000, + "pending_claimed_accounts": 0, + "open_recurrent_transfers": 0, + "is_smt": false, + "delayed_votes": [], + "governance_vote_expiration_ts": "2017-09-14T10:54:48" + } + ] + }, + "id": 1 + } + }, + { + "req": { + "jsonrpc": "2.0", + "method": "database_api.find_accounts", + "params": { + "accounts": [ + "gtg" + ] + }, + "id": 1 + }, + "res": { + "jsonrpc": "2.0", + "result": { + "accounts": [ + { + "id": 14007, + "name": "gtg", + "owner": { + "weight_threshold": 1, + "account_auths": [], + "key_auths": [ + [ + "STM5RLQ1Jh8Kf56go3xpzoodg4vRsgCeWhANXoEXrYH7bLEwSVyjh", + 1 + ], + [ + "STM6LLegbAgLAy28EHrffBVuANFWcFgmqRMW13wBmTExqFE9SCkg4", + 1 + ] + ] + }, + "active": { + "weight_threshold": 1, + "account_auths": [], + "key_auths": [ + [ + "STM4vuEE8F2xyJhwiNCnHxjUVLNXxdFXtVxgghBq5LVLt49zLKLRX", + 1 + ], + [ + "STM6LLegbAgLAy28EHrffBVuANFWcFgmqRMW13wBmTExqFE9SCkg4", + 1 + ] + ] + }, + "posting": { + "weight_threshold": 1, + "account_auths": [], + "key_auths": [ + [ + "STM5tp5hWbGLL1R3tMVsgYdYxLPyAQFdKoYFbT2hcWUmrU42p1MQC", + 1 + ], + [ + "STM6LLegbAgLAy28EHrffBVuANFWcFgmqRMW13wBmTExqFE9SCkg4", + 1 + ] + ] + }, + "memo_key": "STM4uD3dfLvbz7Tkd7of4K9VYGnkgrY5BHSQt52vE52CBL5qBfKHN", + "json_metadata": "{\"profile\":{\"witness_description\": \"Gandalf the Grey, building Hive, improving Hive infrastructure.\",\"profile_image\":\"https://grey.house/img/grey_4.jpg\",\"name\":\"Gandalf the Grey\",\"about\":\"IT Wizard, Hive Witness\",\"location\":\"Hive\",\"version\":2}}", + "posting_json_metadata": "", + "proxy": "", + "previous_owner_update": "2016-07-14T23:05:30", + "last_owner_update": "2016-07-21T21:48:03", + "last_account_update": "2016-07-21T21:48:06", + "created": "2016-06-30T17:22:21", + "mined": true, + "recovery_account": "steem", + "last_account_recovery": "2016-07-21T21:48:06", + "reset_account": "null", + "comment_count": 0, + "lifetime_vote_count": 0, + "post_count": 57, + "can_vote": true, + "voting_manabar": { + "current_mana": 18469160006473, + "last_update_time": 1474663833 + }, + "downvote_manabar": { + "current_mana": 4617290001618, + "last_update_time": 1474663833 + }, + "balance": { + "amount": "0", + "precision": 3, + "nai": "@@000000021" + }, + "savings_balance": { + "amount": "0", + "precision": 3, + "nai": "@@000000021" + }, + "hbd_balance": { + "amount": "3465", + "precision": 3, + "nai": "@@000000013" + }, + "hbd_seconds": "0", + "hbd_seconds_last_update": "2016-09-09T17:18:09", + "hbd_last_interest_payment": "2016-09-09T17:18:09", + "savings_hbd_balance": { + "amount": "0", + "precision": 3, + "nai": "@@000000013" + }, + "savings_hbd_seconds": "0", + "savings_hbd_seconds_last_update": "1970-01-01T00:00:00", + "savings_hbd_last_interest_payment": "1970-01-01T00:00:00", + "savings_withdraw_requests": 0, + "reward_hbd_balance": { + "amount": "194", + "precision": 3, + "nai": "@@000000013" + }, + "reward_hive_balance": { + "amount": "0", + "precision": 3, + "nai": "@@000000021" + }, + "reward_vesting_balance": { + "amount": "2617000164", + "precision": 6, + "nai": "@@000000037" + }, + "reward_vesting_hive": { + "amount": "872", + "precision": 3, + "nai": "@@000000021" + }, + "vesting_shares": { + "amount": "18469160006473", + "precision": 6, + "nai": "@@000000037" + }, + "delegated_vesting_shares": { + "amount": "0", + "precision": 6, + "nai": "@@000000037" + }, + "received_vesting_shares": { + "amount": "0", + "precision": 6, + "nai": "@@000000037" + }, + "vesting_withdraw_rate": { + "amount": "0", + "precision": 6, + "nai": "@@000000037" + }, + "post_voting_power": { + "amount": "18469160006473", + "precision": 6, + "nai": "@@000000037" + }, + "next_vesting_withdrawal": "1969-12-31T23:59:59", + "withdrawn": 0, + "to_withdraw": 0, + "withdraw_routes": 0, + "pending_transfers": 0, + "curation_rewards": 20403, + "posting_rewards": 1973628, + "proxied_vsf_votes": [ + 30412408791348, + 438966760068, + 0, + 0 + ], + "witnesses_voted_for": 20, + "last_post": "2016-11-14T20:57:27", + "last_root_post": "2016-10-10T20:55:45", + "last_post_edit": "2016-11-14T20:57:27", + "last_vote_time": "2016-09-15T19:46:21", + "post_bandwidth": 10000, + "pending_claimed_accounts": 0, + "open_recurrent_transfers": 0, + "is_smt": false, + "delayed_votes": [], + "governance_vote_expiration_ts": "2017-09-14T10:54:48" + } + ] + }, + "id": 1 + } + }, + { + "req": { + "jsonrpc": "2.0", + "method": "database_api.find_accounts", + "params": { + "accounts": [ + "gtg", + "blocktrades" + ] + }, + "id": 1 + }, + "res": { + "id": 1, + "jsonrpc": "2.0", + "result": { + "accounts": [ + { + "active": { + "account_auths": [], + "key_auths": [ + [ + "STM8NWQYG4BvjGNu8zqqV9fbR7aSCZHcxkVib41PYnpGmPRe6BHVG", + 1 + ] + ], + "weight_threshold": 1 + }, + "balance": { + "amount": "225", + "nai": "@@000000021", + "precision": 3 + }, + "can_vote": true, + "comment_count": 0, + "created": "2016-06-30T17:22:21", + "curation_rewards": 447198711, + "delayed_votes": [], + "delegated_vesting_shares": { + "amount": "0", + "nai": "@@000000037", + "precision": 6 + }, + "downvote_manabar": { + "current_mana": 734567683888036, + "last_update_time": 1752833250 + }, + "governance_vote_expiration_ts": "2026-06-26T16:55:21", + "hbd_balance": { + "amount": "369", + "nai": "@@000000013", + "precision": 3 + }, + "hbd_last_interest_payment": "2021-06-13T21:34:42", + "hbd_seconds": "26576708016", + "hbd_seconds_last_update": "2021-06-30T11:10:30", + "id": 14007, + "is_smt": false, + "json_metadata": "{\"profile\":{\"witness_description\": \"Gandalf the Grey, building Hive, improving Hive infrastructure.\",\"profile_image\":\"https://grey.house/img/grey_4.jpg\",\"name\":\"Gandalf the Grey\",\"about\":\"IT Wizard, Hive Witness\",\"location\":\"Hive\",\"version\":2}}", + "last_account_recovery": "2016-07-21T21:48:06", + "last_account_update": "2024-10-24T14:19:24", + "last_owner_update": "2017-03-21T18:37:42", + "last_post": "2025-07-17T19:56:33", + "last_post_edit": "2025-07-17T19:56:33", + "last_root_post": "2025-05-14T20:05:27", + "last_vote_time": "2025-07-18T07:32:45", + "lifetime_vote_count": 0, + "memo_key": "STM4uD3dfLvbz7Tkd7of4K9VYGnkgrY5BHSQt52vE52CBL5qBfKHN", + "mined": true, + "name": "gtg", + "next_vesting_withdrawal": "1969-12-31T23:59:59", + "open_recurrent_transfers": 0, + "owner": { + "account_auths": [], + "key_auths": [ + [ + "STM5RLQ1Jh8Kf56go3xpzoodg4vRsgCeWhANXoEXrYH7bLEwSVyjh", + 1 + ] + ], + "weight_threshold": 1 + }, + "pending_claimed_accounts": 67453, + "pending_transfers": 0, + "post_bandwidth": 10000, + "post_count": 7116, + "post_voting_power": { + "amount": "2938270735552146", + "nai": "@@000000037", + "precision": 6 + }, + "posting": { + "account_auths": [ + [ + "voterbee", + 1 + ] + ], + "key_auths": [ + [ + "STM5tp5hWbGLL1R3tMVsgYdYxLPyAQFdKoYFbT2hcWUmrU42p1MQC", + 1 + ] + ], + "weight_threshold": 1 + }, + "posting_json_metadata": "{\"profile\":{\"witness_description\":\"Gandalf the Grey, Building Hive.\",\"about\":\"IT Wizard, Hive Witness\",\"profile_image\":\"https://grey.house/img/grey_4.jpg\",\"name\":\"Gandalf the Grey\",\"location\":\"Hive\",\"version\":2}}", + "posting_rewards": 22416805, + "previous_owner_update": "2016-07-21T21:48:03", + "proxied_vsf_votes": [ + 6318682367545766, + 67728573881044, + 0, + 0 + ], + "proxy": "", + "received_vesting_shares": { + "amount": "106902000000", + "nai": "@@000000037", + "precision": 6 + }, + "recovery_account": "roelandp", + "reset_account": "null", + "reward_hbd_balance": { + "amount": "0", + "nai": "@@000000013", + "precision": 3 + }, + "reward_hive_balance": { + "amount": "0", + "nai": "@@000000021", + "precision": 3 + }, + "reward_vesting_balance": { + "amount": "0", + "nai": "@@000000037", + "precision": 6 + }, + "reward_vesting_hive": { + "amount": "0", + "nai": "@@000000021", + "precision": 3 + }, + "savings_balance": { + "amount": "0", + "nai": "@@000000021", + "precision": 3 + }, + "savings_hbd_balance": { + "amount": "0", + "nai": "@@000000013", + "precision": 3 + }, + "savings_hbd_last_interest_payment": "2025-07-09T09:55:15", + "savings_hbd_seconds": "0", + "savings_hbd_seconds_last_update": "2025-07-09T09:55:15", + "savings_withdraw_requests": 0, + "to_withdraw": 0, + "vesting_shares": { + "amount": "2938163833552146", + "nai": "@@000000037", + "precision": 6 + }, + "vesting_withdraw_rate": { + "amount": "0", + "nai": "@@000000037", + "precision": 6 + }, + "voting_manabar": { + "current_mana": 2884842115563337, + "last_update_time": 1752833250 + }, + "withdraw_routes": 0, + "withdrawn": 0, + "witnesses_voted_for": 29 + }, + { + "active": { + "account_auths": [], + "key_auths": [ + [ + "STM5vgGoHBrUuDCspAPYi3dLwSyistyrz61NWkZNUAXAifZJaDLPF", + 1 + ] + ], + "weight_threshold": 1 + }, + "balance": { + "amount": "590482780", + "nai": "@@000000021", + "precision": 3 + }, + "can_vote": true, + "comment_count": 0, + "created": "2016-03-30T00:04:36", + "curation_rewards": 3622110236, + "delayed_votes": [], + "delegated_vesting_shares": { + "amount": "6909522651976083", + "nai": "@@000000037", + "precision": 6 + }, + "downvote_manabar": { + "current_mana": 3890531413053150, + "last_update_time": 1752833244 + }, + "governance_vote_expiration_ts": "2026-07-03T18:05:30", + "hbd_balance": { + "amount": "45986", + "nai": "@@000000013", + "precision": 3 + }, + "hbd_last_interest_payment": "2021-06-10T03:21:45", + "hbd_seconds": "4013278129191", + "hbd_seconds_last_update": "2021-06-30T13:51:27", + "id": 440, + "is_smt": false, + "json_metadata": "{\"profile\":{\"profile_image\":\"https://s18.postimg.org/be2c25f2h/blocktrades_icon.png\"}}", + "last_account_recovery": "1970-01-01T00:00:00", + "last_account_update": "2022-03-20T20:16:48", + "last_owner_update": "2016-07-14T13:02:06", + "last_post": "2025-07-15T00:52:36", + "last_post_edit": "2025-07-15T00:52:36", + "last_root_post": "2025-07-07T22:39:36", + "last_vote_time": "2025-07-18T09:45:09", + "lifetime_vote_count": 0, + "memo_key": "STM7EAUbNf1CdTrMbydPoBTRMG4afXCoAErBJYevhgne6zEP6rVBT", + "mined": true, + "name": "blocktrades", + "next_vesting_withdrawal": "1969-12-31T23:59:59", + "open_recurrent_transfers": 0, + "owner": { + "account_auths": [], + "key_auths": [ + [ + "STM7WdrxF6iuSiHUB4maoLGXXBKXbqAJ9AZbzACX1MPK2AkuCh23S", + 1 + ] + ], + "weight_threshold": 1 + }, + "pending_claimed_accounts": 470490, + "pending_transfers": 0, + "post_bandwidth": 10000, + "post_count": 4897, + "post_voting_power": { + "amount": "15562125652212602", + "nai": "@@000000037", + "precision": 6 + }, + "posting": { + "account_auths": [ + [ + "downvote-tool", + 1 + ], + [ + "steemauto", + 1 + ] + ], + "key_auths": [ + [ + "STM8UVQ7xATRUYNJkbrctSqo7FAexKoJqHAUjHWXLs2oGtS3MDCUV", + 1 + ] + ], + "weight_threshold": 1 + }, + "posting_json_metadata": "{\"profile\":{\"profile_image\":\"https://s18.postimg.org/be2c25f2h/blocktrades_icon.png\",\"about\":\"Exchange cryptocurrency fast and easy\",\"website\":\"https://blocktrades.us\",\"version\":2},\"did\":\"did:3:kjzl6cwe1jw147kr5qe9lkaqr83j33wzt64c29sa0oviewxjpuihrbabc2658qj\"}", + "posting_rewards": 128565922, + "previous_owner_update": "1970-01-01T00:00:00", + "proxied_vsf_votes": [ + "23811737300422857", + 0, + 0, + 0 + ], + "proxy": "", + "received_vesting_shares": { + "amount": "93229078992219", + "nai": "@@000000037", + "precision": 6 + }, + "recovery_account": "steem", + "reset_account": "null", + "reward_hbd_balance": { + "amount": "38517", + "nai": "@@000000013", + "precision": 3 + }, + "reward_hive_balance": { + "amount": "0", + "nai": "@@000000021", + "precision": 3 + }, + "reward_vesting_balance": { + "amount": "33459136064202", + "nai": "@@000000037", + "precision": 6 + }, + "reward_vesting_hive": { + "amount": "20076514", + "nai": "@@000000021", + "precision": 3 + }, + "savings_balance": { + "amount": "52795", + "nai": "@@000000021", + "precision": 3 + }, + "savings_hbd_balance": { + "amount": "130076015", + "nai": "@@000000013", + "precision": 3 + }, + "savings_hbd_last_interest_payment": "2025-07-05T06:05:48", + "savings_hbd_seconds": "0", + "savings_hbd_seconds_last_update": "2025-07-05T06:05:48", + "savings_withdraw_requests": 0, + "to_withdraw": 0, + "vesting_shares": { + "amount": "22378419225196466", + "nai": "@@000000037", + "precision": 6 + }, + "vesting_withdraw_rate": { + "amount": "0", + "nai": "@@000000037", + "precision": 6 + }, + "voting_manabar": { + "current_mana": 8597185580130367, + "last_update_time": 1752833244 + }, + "withdraw_routes": 3, + "withdrawn": 0, + "witnesses_voted_for": 27 + } + ] + } + } + } +] \ No newline at end of file diff --git a/__tests__/assets/api-call-logs/database_api_find_witnesses.json b/__tests__/assets/api-call-logs/database_api_find_witnesses.json new file mode 100644 index 0000000..1f4b557 --- /dev/null +++ b/__tests__/assets/api-call-logs/database_api_find_witnesses.json @@ -0,0 +1,175 @@ +[ + { + "req": { + "jsonrpc": "2.0", + "method": "database_api.find_witnesses", + "params": { + "owners": [ + "gtg", + "blocktrades" + ] + }, + "id": 1 + }, + "res": { + "id": 1, + "jsonrpc": "2.0", + "result": { + "witnesses": [ + { + "available_witness_account_subsidies": 2074405, + "created": "2016-06-30T17:22:18", + "hardfork_time_vote": "2022-10-24T12:00:00", + "hardfork_version_vote": "1.27.0", + "hbd_exchange_rate": { + "base": { + "amount": "257", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + "id": 9493, + "last_aslot": 98087356, + "last_confirmed_block_num": 97837194, + "last_hbd_exchange_update": "2025-07-21T10:41:42", + "last_work": "0000000048bf77f525731f28db7c1aa9ad853a475ccc78e71ea952a7782e5459", + "owner": "gtg", + "pow_worker": 0, + "props": { + "account_creation_fee": { + "amount": "3000", + "nai": "@@000000021", + "precision": 3 + }, + "account_subsidy_budget": 797, + "account_subsidy_decay": 347321, + "hbd_interest_rate": 1000, + "maximum_block_size": 65536 + }, + "running_version": "1.27.11", + "signing_key": "STM8PFEEhF9g3PMZu9mu9vso56bzP6i4aMYM73aWL8CkcKi4LEGLR", + "total_missed": 988, + "url": "https://gtg.openhive.network", + "virtual_last_update": "979505544365428371674234720", + "virtual_position": "51472121875816974750553820863478338819", + "virtual_scheduled_time": "979507497029019599401149403", + "votes": "147905786917209621" + }, + { + "available_witness_account_subsidies": 2924797, + "created": "2016-03-30T00:04:33", + "hardfork_time_vote": "2022-10-24T12:00:00", + "hardfork_version_vote": "1.27.0", + "hbd_exchange_rate": { + "base": { + "amount": "258", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + "id": 437, + "last_aslot": 98087348, + "last_confirmed_block_num": 97837186, + "last_hbd_exchange_update": "2025-07-21T11:12:00", + "last_work": "0000000df71896f1756d6a3456905da575407b4917d922042f72e076f586a2b4", + "owner": "blocktrades", + "pow_worker": 0, + "props": { + "account_creation_fee": { + "amount": "3000", + "nai": "@@000000021", + "precision": 3 + }, + "account_subsidy_budget": 797, + "account_subsidy_decay": 347321, + "hbd_interest_rate": 1200, + "maximum_block_size": 65536 + }, + "running_version": "1.27.11", + "signing_key": "STM74tqTQG9K52rUN1YwaD4uiGE1qyvz3NqdcrqX9af6jydtNkT9Y", + "total_missed": 3728, + "url": "https://blocktrades.us", + "virtual_last_update": "979505544365428371674234720", + "virtual_position": "49901447424579651697224724781791347991", + "virtual_scheduled_time": "979507569443824706952652143", + "votes": "143392433607435720" + } + ] + } + } + }, + { + "req": { + "jsonrpc": "2.0", + "method": "database_api.find_witnesses", + "params": { + "owners": [ + "gtg" + ] + }, + "id": 1 + }, + "res": { + "id": 1, + "jsonrpc": "2.0", + "result": { + "witnesses": [ + { + "available_witness_account_subsidies": 1377021, + "created": "2016-06-30T17:22:18", + "hardfork_time_vote": "2025-02-08T13:00:00", + "hardfork_version_vote": "1.28.0", + "hbd_exchange_rate": { + "base": { + "amount": "241", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + "id": 9493, + "last_aslot": 97972476, + "last_confirmed_block_num": 97506932, + "last_hbd_exchange_update": "2025-07-17T11:41:39", + "last_work": "0000000048bf77f525731f28db7c1aa9ad853a475ccc78e71ea952a7782e5459", + "owner": "gtg", + "pow_worker": 0, + "props": { + "account_creation_fee": { + "amount": "3000", + "nai": "@@000000021", + "precision": 3 + }, + "account_subsidy_budget": 797, + "account_subsidy_decay": 347321, + "hbd_interest_rate": 1000, + "maximum_block_size": 65536 + }, + "running_version": "1.28.0", + "signing_key": "STM6LLegbAgLAy28EHrffBVuANFWcFgmqRMW13wBmTExqFE9SCkg4", + "total_missed": 8608, + "url": "https://gtg.openhive.network", + "virtual_last_update": "976912495575489581911509823", + "virtual_position": "6247395889179736241420680092396656593", + "virtual_scheduled_time": "976914764013601056742029734", + "votes": "147253288217144739" + } + ] + } + } + } +] \ No newline at end of file diff --git a/__tests__/assets/api-call-logs/database_api_get_dynamic_global_properties.json b/__tests__/assets/api-call-logs/database_api_get_dynamic_global_properties.json new file mode 100644 index 0000000..e049cf6 --- /dev/null +++ b/__tests__/assets/api-call-logs/database_api_get_dynamic_global_properties.json @@ -0,0 +1,992 @@ +[ + { + "req": { + "jsonrpc": "2.0", + "method": "database_api.get_dynamic_global_properties", + "params": {}, + "id": 1 + }, + "res": { + "id": 1, + "jsonrpc": "2.0", + "result": { + "available_account_subsidies": 36853823, + "content_reward_percent": 6500, + "current_aslot": 97942186, + "current_hbd_supply": { + "amount": "34865644294", + "nai": "@@000000013", + "precision": 3 + }, + "current_remove_threshold": 200, + "current_supply": { + "amount": "479079425004", + "nai": "@@000000021", + "precision": 3 + }, + "current_witness": "ocd-witness", + "delegation_return_period": 432000, + "dhf_interval_ledger": { + "amount": "29400", + "nai": "@@000000013", + "precision": 3 + }, + "downvote_pool_percent": 2500, + "early_voting_seconds": 86400, + "hbd_interest_rate": 1500, + "hbd_print_rate": 10000, + "hbd_start_percent": 2000, + "hbd_stop_percent": 2000, + "head_block_id": "05cf62ab3f2151a60e601ed86bdb43137949873d", + "head_block_number": 97477291, + "id": 0, + "init_hbd_supply": { + "amount": "0", + "nai": "@@000000013", + "precision": 3 + }, + "last_budget_time": "2025-07-16T10:07:51", + "last_irreversible_block_num": 97477291, + "max_consecutive_recurrent_transfer_failures": 10, + "max_open_recurrent_transfers": 255, + "max_recurrent_transfer_end_date": 730, + "maximum_block_size": 2097152, + "mid_voting_seconds": 172800, + "min_recurrent_transfers_recurrence": 24, + "next_daily_maintenance_time": "2025-07-17T02:07:45", + "next_maintenance_time": "2025-07-16T11:07:51", + "num_pow_witnesses": 172, + "participation_count": 127, + "pending_rewarded_vesting_hive": { + "amount": "1102477777", + "nai": "@@000000021", + "precision": 3 + }, + "pending_rewarded_vesting_shares": { + "amount": "1938619142331887", + "nai": "@@000000037", + "precision": 6 + }, + "proposal_fund_percent": 1000, + "recent_slots_filled": "340282366920783720958463934897405820927", + "reverse_auction_seconds": 0, + "time": "2025-07-16T10:29:18", + "total_pow": 514415, + "total_reward_fund_hive": { + "amount": "0", + "nai": "@@000000021", + "precision": 3 + }, + "total_reward_shares2": "0", + "total_vesting_fund_hive": { + "amount": "186431971795", + "nai": "@@000000021", + "precision": 3 + }, + "total_vesting_shares": { + "amount": "311147778100419527", + "nai": "@@000000037", + "precision": 6 + }, + "vesting_reward_percent": 1500, + "virtual_supply": { + "amount": "625573728760", + "nai": "@@000000021", + "precision": 3 + }, + "vote_power_reserve_rate": 10 + } + } + }, + { + "req": { + "jsonrpc": "2.0", + "method": "database_api.get_dynamic_global_properties", + "params": {}, + "id": 1 + }, + "res": { + "id": 1, + "jsonrpc": "2.0", + "result": { + "available_account_subsidies": 36853823, + "content_reward_percent": 6500, + "current_aslot": 97942186, + "current_hbd_supply": { + "amount": "34865644294", + "nai": "@@000000013", + "precision": 3 + }, + "current_remove_threshold": 200, + "current_supply": { + "amount": "479079425004", + "nai": "@@000000021", + "precision": 3 + }, + "current_witness": "ocd-witness", + "delegation_return_period": 432000, + "dhf_interval_ledger": { + "amount": "29400", + "nai": "@@000000013", + "precision": 3 + }, + "downvote_pool_percent": 2500, + "early_voting_seconds": 86400, + "hbd_interest_rate": 1500, + "hbd_print_rate": 10000, + "hbd_start_percent": 2000, + "hbd_stop_percent": 2000, + "head_block_id": "05cf62ab3f2151a60e601ed86bdb43137949873d", + "head_block_number": 97477292, + "id": 0, + "init_hbd_supply": { + "amount": "0", + "nai": "@@000000013", + "precision": 3 + }, + "last_budget_time": "2025-07-16T10:07:51", + "last_irreversible_block_num": 97477291, + "max_consecutive_recurrent_transfer_failures": 10, + "max_open_recurrent_transfers": 255, + "max_recurrent_transfer_end_date": 730, + "maximum_block_size": 2097152, + "mid_voting_seconds": 172800, + "min_recurrent_transfers_recurrence": 24, + "next_daily_maintenance_time": "2025-07-17T02:07:45", + "next_maintenance_time": "2025-07-16T11:07:51", + "num_pow_witnesses": 172, + "participation_count": 127, + "pending_rewarded_vesting_hive": { + "amount": "1102477777", + "nai": "@@000000021", + "precision": 3 + }, + "pending_rewarded_vesting_shares": { + "amount": "1938619142331887", + "nai": "@@000000037", + "precision": 6 + }, + "proposal_fund_percent": 1000, + "recent_slots_filled": "340282366920783720958463934897405820927", + "reverse_auction_seconds": 0, + "time": "2025-07-16T10:29:18", + "total_pow": 514415, + "total_reward_fund_hive": { + "amount": "0", + "nai": "@@000000021", + "precision": 3 + }, + "total_reward_shares2": "0", + "total_vesting_fund_hive": { + "amount": "186431971795", + "nai": "@@000000021", + "precision": 3 + }, + "total_vesting_shares": { + "amount": "311147778100419527", + "nai": "@@000000037", + "precision": 6 + }, + "vesting_reward_percent": 1500, + "virtual_supply": { + "amount": "625573728760", + "nai": "@@000000021", + "precision": 3 + }, + "vote_power_reserve_rate": 10 + } + } + }, + { + "req": { + "jsonrpc": "2.0", + "method": "database_api.get_dynamic_global_properties", + "params": {}, + "id": 1 + }, + "res": { + "id": 1, + "jsonrpc": "2.0", + "result": { + "available_account_subsidies": 36853823, + "content_reward_percent": 6500, + "current_aslot": 97942186, + "current_hbd_supply": { + "amount": "34865644294", + "nai": "@@000000013", + "precision": 3 + }, + "current_remove_threshold": 200, + "current_supply": { + "amount": "479079425004", + "nai": "@@000000021", + "precision": 3 + }, + "current_witness": "ocd-witness", + "delegation_return_period": 432000, + "dhf_interval_ledger": { + "amount": "29400", + "nai": "@@000000013", + "precision": 3 + }, + "downvote_pool_percent": 2500, + "early_voting_seconds": 86400, + "hbd_interest_rate": 1500, + "hbd_print_rate": 10000, + "hbd_start_percent": 2000, + "hbd_stop_percent": 2000, + "head_block_id": "05cf62ab3f2151a60e601ed86bdb43137949873d", + "head_block_number": 97477293, + "id": 0, + "init_hbd_supply": { + "amount": "0", + "nai": "@@000000013", + "precision": 3 + }, + "last_budget_time": "2025-07-16T10:07:51", + "last_irreversible_block_num": 97477291, + "max_consecutive_recurrent_transfer_failures": 10, + "max_open_recurrent_transfers": 255, + "max_recurrent_transfer_end_date": 730, + "maximum_block_size": 2097152, + "mid_voting_seconds": 172800, + "min_recurrent_transfers_recurrence": 24, + "next_daily_maintenance_time": "2025-07-17T02:07:45", + "next_maintenance_time": "2025-07-16T11:07:51", + "num_pow_witnesses": 172, + "participation_count": 127, + "pending_rewarded_vesting_hive": { + "amount": "1102477777", + "nai": "@@000000021", + "precision": 3 + }, + "pending_rewarded_vesting_shares": { + "amount": "1938619142331887", + "nai": "@@000000037", + "precision": 6 + }, + "proposal_fund_percent": 1000, + "recent_slots_filled": "340282366920783720958463934897405820927", + "reverse_auction_seconds": 0, + "time": "2025-07-16T10:29:18", + "total_pow": 514415, + "total_reward_fund_hive": { + "amount": "0", + "nai": "@@000000021", + "precision": 3 + }, + "total_reward_shares2": "0", + "total_vesting_fund_hive": { + "amount": "186431971795", + "nai": "@@000000021", + "precision": 3 + }, + "total_vesting_shares": { + "amount": "311147778100419527", + "nai": "@@000000037", + "precision": 6 + }, + "vesting_reward_percent": 1500, + "virtual_supply": { + "amount": "625573728760", + "nai": "@@000000021", + "precision": 3 + }, + "vote_power_reserve_rate": 10 + } + } + }, + { + "req": { + "jsonrpc": "2.0", + "method": "database_api.get_dynamic_global_properties", + "params": {}, + "id": 1 + }, + "res": { + "id": 1, + "jsonrpc": "2.0", + "result": { + "available_account_subsidies": 36853823, + "content_reward_percent": 6500, + "current_aslot": 97942186, + "current_hbd_supply": { + "amount": "34865644294", + "nai": "@@000000013", + "precision": 3 + }, + "current_remove_threshold": 200, + "current_supply": { + "amount": "479079425004", + "nai": "@@000000021", + "precision": 3 + }, + "current_witness": "ocd-witness", + "delegation_return_period": 432000, + "dhf_interval_ledger": { + "amount": "29400", + "nai": "@@000000013", + "precision": 3 + }, + "downvote_pool_percent": 2500, + "early_voting_seconds": 86400, + "hbd_interest_rate": 1500, + "hbd_print_rate": 10000, + "hbd_start_percent": 2000, + "hbd_stop_percent": 2000, + "head_block_id": "05cf62ab3f2151a60e601ed86bdb43137949873d", + "head_block_number": 97477294, + "id": 0, + "init_hbd_supply": { + "amount": "0", + "nai": "@@000000013", + "precision": 3 + }, + "last_budget_time": "2025-07-16T10:07:51", + "last_irreversible_block_num": 97477291, + "max_consecutive_recurrent_transfer_failures": 10, + "max_open_recurrent_transfers": 255, + "max_recurrent_transfer_end_date": 730, + "maximum_block_size": 2097152, + "mid_voting_seconds": 172800, + "min_recurrent_transfers_recurrence": 24, + "next_daily_maintenance_time": "2025-07-17T02:07:45", + "next_maintenance_time": "2025-07-16T11:07:51", + "num_pow_witnesses": 172, + "participation_count": 127, + "pending_rewarded_vesting_hive": { + "amount": "1102477777", + "nai": "@@000000021", + "precision": 3 + }, + "pending_rewarded_vesting_shares": { + "amount": "1938619142331887", + "nai": "@@000000037", + "precision": 6 + }, + "proposal_fund_percent": 1000, + "recent_slots_filled": "340282366920783720958463934897405820927", + "reverse_auction_seconds": 0, + "time": "2025-07-16T10:29:18", + "total_pow": 514415, + "total_reward_fund_hive": { + "amount": "0", + "nai": "@@000000021", + "precision": 3 + }, + "total_reward_shares2": "0", + "total_vesting_fund_hive": { + "amount": "186431971795", + "nai": "@@000000021", + "precision": 3 + }, + "total_vesting_shares": { + "amount": "311147778100419527", + "nai": "@@000000037", + "precision": 6 + }, + "vesting_reward_percent": 1500, + "virtual_supply": { + "amount": "625573728760", + "nai": "@@000000021", + "precision": 3 + }, + "vote_power_reserve_rate": 10 + } + } + }, + { + "req": { + "jsonrpc": "2.0", + "method": "database_api.get_dynamic_global_properties", + "params": {}, + "id": 1 + }, + "res": { + "id": 1, + "jsonrpc": "2.0", + "result": { + "available_account_subsidies": 36853823, + "content_reward_percent": 6500, + "current_aslot": 97942186, + "current_hbd_supply": { + "amount": "34865644294", + "nai": "@@000000013", + "precision": 3 + }, + "current_remove_threshold": 200, + "current_supply": { + "amount": "479079425004", + "nai": "@@000000021", + "precision": 3 + }, + "current_witness": "ocd-witness", + "delegation_return_period": 432000, + "dhf_interval_ledger": { + "amount": "29400", + "nai": "@@000000013", + "precision": 3 + }, + "downvote_pool_percent": 2500, + "early_voting_seconds": 86400, + "hbd_interest_rate": 1500, + "hbd_print_rate": 10000, + "hbd_start_percent": 2000, + "hbd_stop_percent": 2000, + "head_block_id": "05cf62ab3f2151a60e601ed86bdb43137949873d", + "head_block_number": 97477295, + "id": 0, + "init_hbd_supply": { + "amount": "0", + "nai": "@@000000013", + "precision": 3 + }, + "last_budget_time": "2025-07-16T10:07:51", + "last_irreversible_block_num": 97477291, + "max_consecutive_recurrent_transfer_failures": 10, + "max_open_recurrent_transfers": 255, + "max_recurrent_transfer_end_date": 730, + "maximum_block_size": 2097152, + "mid_voting_seconds": 172800, + "min_recurrent_transfers_recurrence": 24, + "next_daily_maintenance_time": "2025-07-17T02:07:45", + "next_maintenance_time": "2025-07-16T11:07:51", + "num_pow_witnesses": 172, + "participation_count": 127, + "pending_rewarded_vesting_hive": { + "amount": "1102477777", + "nai": "@@000000021", + "precision": 3 + }, + "pending_rewarded_vesting_shares": { + "amount": "1938619142331887", + "nai": "@@000000037", + "precision": 6 + }, + "proposal_fund_percent": 1000, + "recent_slots_filled": "340282366920783720958463934897405820927", + "reverse_auction_seconds": 0, + "time": "2025-07-16T10:29:18", + "total_pow": 514415, + "total_reward_fund_hive": { + "amount": "0", + "nai": "@@000000021", + "precision": 3 + }, + "total_reward_shares2": "0", + "total_vesting_fund_hive": { + "amount": "186431971795", + "nai": "@@000000021", + "precision": 3 + }, + "total_vesting_shares": { + "amount": "311147778100419527", + "nai": "@@000000037", + "precision": 6 + }, + "vesting_reward_percent": 1500, + "virtual_supply": { + "amount": "625573728760", + "nai": "@@000000021", + "precision": 3 + }, + "vote_power_reserve_rate": 10 + } + } + }, + { + "req": { + "jsonrpc": "2.0", + "method": "database_api.get_dynamic_global_properties", + "params": {}, + "id": 1 + }, + "res": { + "id": 1, + "jsonrpc": "2.0", + "result": { + "available_account_subsidies": 36853823, + "content_reward_percent": 6500, + "current_aslot": 97942186, + "current_hbd_supply": { + "amount": "34865644294", + "nai": "@@000000013", + "precision": 3 + }, + "current_remove_threshold": 200, + "current_supply": { + "amount": "479079425004", + "nai": "@@000000021", + "precision": 3 + }, + "current_witness": "ocd-witness", + "delegation_return_period": 432000, + "dhf_interval_ledger": { + "amount": "29400", + "nai": "@@000000013", + "precision": 3 + }, + "downvote_pool_percent": 2500, + "early_voting_seconds": 86400, + "hbd_interest_rate": 1500, + "hbd_print_rate": 10000, + "hbd_start_percent": 2000, + "hbd_stop_percent": 2000, + "head_block_id": "05cf62ab3f2151a60e601ed86bdb43137949873d", + "head_block_number": 97477296, + "id": 0, + "init_hbd_supply": { + "amount": "0", + "nai": "@@000000013", + "precision": 3 + }, + "last_budget_time": "2025-07-16T10:07:51", + "last_irreversible_block_num": 97477291, + "max_consecutive_recurrent_transfer_failures": 10, + "max_open_recurrent_transfers": 255, + "max_recurrent_transfer_end_date": 730, + "maximum_block_size": 2097152, + "mid_voting_seconds": 172800, + "min_recurrent_transfers_recurrence": 24, + "next_daily_maintenance_time": "2025-07-17T02:07:45", + "next_maintenance_time": "2025-07-16T11:07:51", + "num_pow_witnesses": 172, + "participation_count": 127, + "pending_rewarded_vesting_hive": { + "amount": "1102477777", + "nai": "@@000000021", + "precision": 3 + }, + "pending_rewarded_vesting_shares": { + "amount": "1938619142331887", + "nai": "@@000000037", + "precision": 6 + }, + "proposal_fund_percent": 1000, + "recent_slots_filled": "340282366920783720958463934897405820927", + "reverse_auction_seconds": 0, + "time": "2025-07-16T10:29:18", + "total_pow": 514415, + "total_reward_fund_hive": { + "amount": "0", + "nai": "@@000000021", + "precision": 3 + }, + "total_reward_shares2": "0", + "total_vesting_fund_hive": { + "amount": "186431971795", + "nai": "@@000000021", + "precision": 3 + }, + "total_vesting_shares": { + "amount": "311147778100419527", + "nai": "@@000000037", + "precision": 6 + }, + "vesting_reward_percent": 1500, + "virtual_supply": { + "amount": "625573728760", + "nai": "@@000000021", + "precision": 3 + }, + "vote_power_reserve_rate": 10 + } + } + }, + { + "req": { + "jsonrpc": "2.0", + "method": "database_api.get_dynamic_global_properties", + "params": {}, + "id": 1 + }, + "res": { + "id": 1, + "jsonrpc": "2.0", + "result": { + "available_account_subsidies": 36853823, + "content_reward_percent": 6500, + "current_aslot": 97942186, + "current_hbd_supply": { + "amount": "34865644294", + "nai": "@@000000013", + "precision": 3 + }, + "current_remove_threshold": 200, + "current_supply": { + "amount": "479079425004", + "nai": "@@000000021", + "precision": 3 + }, + "current_witness": "ocd-witness", + "delegation_return_period": 432000, + "dhf_interval_ledger": { + "amount": "29400", + "nai": "@@000000013", + "precision": 3 + }, + "downvote_pool_percent": 2500, + "early_voting_seconds": 86400, + "hbd_interest_rate": 1500, + "hbd_print_rate": 10000, + "hbd_start_percent": 2000, + "hbd_stop_percent": 2000, + "head_block_id": "05cf62ab3f2151a60e601ed86bdb43137949873d", + "head_block_number": 97477297, + "id": 0, + "init_hbd_supply": { + "amount": "0", + "nai": "@@000000013", + "precision": 3 + }, + "last_budget_time": "2025-07-16T10:07:51", + "last_irreversible_block_num": 97477291, + "max_consecutive_recurrent_transfer_failures": 10, + "max_open_recurrent_transfers": 255, + "max_recurrent_transfer_end_date": 730, + "maximum_block_size": 2097152, + "mid_voting_seconds": 172800, + "min_recurrent_transfers_recurrence": 24, + "next_daily_maintenance_time": "2025-07-17T02:07:45", + "next_maintenance_time": "2025-07-16T11:07:51", + "num_pow_witnesses": 172, + "participation_count": 127, + "pending_rewarded_vesting_hive": { + "amount": "1102477777", + "nai": "@@000000021", + "precision": 3 + }, + "pending_rewarded_vesting_shares": { + "amount": "1938619142331887", + "nai": "@@000000037", + "precision": 6 + }, + "proposal_fund_percent": 1000, + "recent_slots_filled": "340282366920783720958463934897405820927", + "reverse_auction_seconds": 0, + "time": "2025-07-16T10:29:18", + "total_pow": 514415, + "total_reward_fund_hive": { + "amount": "0", + "nai": "@@000000021", + "precision": 3 + }, + "total_reward_shares2": "0", + "total_vesting_fund_hive": { + "amount": "186431971795", + "nai": "@@000000021", + "precision": 3 + }, + "total_vesting_shares": { + "amount": "311147778100419527", + "nai": "@@000000037", + "precision": 6 + }, + "vesting_reward_percent": 1500, + "virtual_supply": { + "amount": "625573728760", + "nai": "@@000000021", + "precision": 3 + }, + "vote_power_reserve_rate": 10 + } + } + }, + { + "req": { + "jsonrpc": "2.0", + "method": "database_api.get_dynamic_global_properties", + "params": {}, + "id": 1 + }, + "res": { + "id": 1, + "jsonrpc": "2.0", + "result": { + "available_account_subsidies": 36853823, + "content_reward_percent": 6500, + "current_aslot": 97942186, + "current_hbd_supply": { + "amount": "34865644294", + "nai": "@@000000013", + "precision": 3 + }, + "current_remove_threshold": 200, + "current_supply": { + "amount": "479079425004", + "nai": "@@000000021", + "precision": 3 + }, + "current_witness": "ocd-witness", + "delegation_return_period": 432000, + "dhf_interval_ledger": { + "amount": "29400", + "nai": "@@000000013", + "precision": 3 + }, + "downvote_pool_percent": 2500, + "early_voting_seconds": 86400, + "hbd_interest_rate": 1500, + "hbd_print_rate": 10000, + "hbd_start_percent": 2000, + "hbd_stop_percent": 2000, + "head_block_id": "05cf62ab3f2151a60e601ed86bdb43137949873d", + "head_block_number": 97477298, + "id": 0, + "init_hbd_supply": { + "amount": "0", + "nai": "@@000000013", + "precision": 3 + }, + "last_budget_time": "2025-07-16T10:07:51", + "last_irreversible_block_num": 97477291, + "max_consecutive_recurrent_transfer_failures": 10, + "max_open_recurrent_transfers": 255, + "max_recurrent_transfer_end_date": 730, + "maximum_block_size": 2097152, + "mid_voting_seconds": 172800, + "min_recurrent_transfers_recurrence": 24, + "next_daily_maintenance_time": "2025-07-17T02:07:45", + "next_maintenance_time": "2025-07-16T11:07:51", + "num_pow_witnesses": 172, + "participation_count": 127, + "pending_rewarded_vesting_hive": { + "amount": "1102477777", + "nai": "@@000000021", + "precision": 3 + }, + "pending_rewarded_vesting_shares": { + "amount": "1938619142331887", + "nai": "@@000000037", + "precision": 6 + }, + "proposal_fund_percent": 1000, + "recent_slots_filled": "340282366920783720958463934897405820927", + "reverse_auction_seconds": 0, + "time": "2025-07-16T10:29:18", + "total_pow": 514415, + "total_reward_fund_hive": { + "amount": "0", + "nai": "@@000000021", + "precision": 3 + }, + "total_reward_shares2": "0", + "total_vesting_fund_hive": { + "amount": "186431971795", + "nai": "@@000000021", + "precision": 3 + }, + "total_vesting_shares": { + "amount": "311147778100419527", + "nai": "@@000000037", + "precision": 6 + }, + "vesting_reward_percent": 1500, + "virtual_supply": { + "amount": "625573728760", + "nai": "@@000000021", + "precision": 3 + }, + "vote_power_reserve_rate": 10 + } + } + }, + { + "req": { + "jsonrpc": "2.0", + "method": "database_api.get_dynamic_global_properties", + "params": {}, + "id": 1 + }, + "res": { + "id": 1, + "jsonrpc": "2.0", + "result": { + "available_account_subsidies": 36853823, + "content_reward_percent": 6500, + "current_aslot": 97942186, + "current_hbd_supply": { + "amount": "34865644294", + "nai": "@@000000013", + "precision": 3 + }, + "current_remove_threshold": 200, + "current_supply": { + "amount": "479079425004", + "nai": "@@000000021", + "precision": 3 + }, + "current_witness": "ocd-witness", + "delegation_return_period": 432000, + "dhf_interval_ledger": { + "amount": "29400", + "nai": "@@000000013", + "precision": 3 + }, + "downvote_pool_percent": 2500, + "early_voting_seconds": 86400, + "hbd_interest_rate": 1500, + "hbd_print_rate": 10000, + "hbd_start_percent": 2000, + "hbd_stop_percent": 2000, + "head_block_id": "05cf62ab3f2151a60e601ed86bdb43137949873d", + "head_block_number": 97477299, + "id": 0, + "init_hbd_supply": { + "amount": "0", + "nai": "@@000000013", + "precision": 3 + }, + "last_budget_time": "2025-07-16T10:07:51", + "last_irreversible_block_num": 97477291, + "max_consecutive_recurrent_transfer_failures": 10, + "max_open_recurrent_transfers": 255, + "max_recurrent_transfer_end_date": 730, + "maximum_block_size": 2097152, + "mid_voting_seconds": 172800, + "min_recurrent_transfers_recurrence": 24, + "next_daily_maintenance_time": "2025-07-17T02:07:45", + "next_maintenance_time": "2025-07-16T11:07:51", + "num_pow_witnesses": 172, + "participation_count": 127, + "pending_rewarded_vesting_hive": { + "amount": "1102477777", + "nai": "@@000000021", + "precision": 3 + }, + "pending_rewarded_vesting_shares": { + "amount": "1938619142331887", + "nai": "@@000000037", + "precision": 6 + }, + "proposal_fund_percent": 1000, + "recent_slots_filled": "340282366920783720958463934897405820927", + "reverse_auction_seconds": 0, + "time": "2025-07-16T10:29:18", + "total_pow": 514415, + "total_reward_fund_hive": { + "amount": "0", + "nai": "@@000000021", + "precision": 3 + }, + "total_reward_shares2": "0", + "total_vesting_fund_hive": { + "amount": "186431971795", + "nai": "@@000000021", + "precision": 3 + }, + "total_vesting_shares": { + "amount": "311147778100419527", + "nai": "@@000000037", + "precision": 6 + }, + "vesting_reward_percent": 1500, + "virtual_supply": { + "amount": "625573728760", + "nai": "@@000000021", + "precision": 3 + }, + "vote_power_reserve_rate": 10 + } + } + }, + { + "req": { + "jsonrpc": "2.0", + "method": "database_api.get_dynamic_global_properties", + "params": {}, + "id": 1 + }, + "res": { + "id": 1, + "jsonrpc": "2.0", + "result": { + "available_account_subsidies": 36853823, + "content_reward_percent": 6500, + "current_aslot": 97942186, + "current_hbd_supply": { + "amount": "34865644294", + "nai": "@@000000013", + "precision": 3 + }, + "current_remove_threshold": 200, + "current_supply": { + "amount": "479079425004", + "nai": "@@000000021", + "precision": 3 + }, + "current_witness": "ocd-witness", + "delegation_return_period": 432000, + "dhf_interval_ledger": { + "amount": "29400", + "nai": "@@000000013", + "precision": 3 + }, + "downvote_pool_percent": 2500, + "early_voting_seconds": 86400, + "hbd_interest_rate": 1500, + "hbd_print_rate": 10000, + "hbd_start_percent": 2000, + "hbd_stop_percent": 2000, + "head_block_id": "05cf62ab3f2151a60e601ed86bdb43137949873d", + "head_block_number": 97477300, + "id": 0, + "init_hbd_supply": { + "amount": "0", + "nai": "@@000000013", + "precision": 3 + }, + "last_budget_time": "2025-07-16T10:07:51", + "last_irreversible_block_num": 97477291, + "max_consecutive_recurrent_transfer_failures": 10, + "max_open_recurrent_transfers": 255, + "max_recurrent_transfer_end_date": 730, + "maximum_block_size": 2097152, + "mid_voting_seconds": 172800, + "min_recurrent_transfers_recurrence": 24, + "next_daily_maintenance_time": "2025-07-17T02:07:45", + "next_maintenance_time": "2025-07-16T11:07:51", + "num_pow_witnesses": 172, + "participation_count": 127, + "pending_rewarded_vesting_hive": { + "amount": "1102477777", + "nai": "@@000000021", + "precision": 3 + }, + "pending_rewarded_vesting_shares": { + "amount": "1938619142331887", + "nai": "@@000000037", + "precision": 6 + }, + "proposal_fund_percent": 1000, + "recent_slots_filled": "340282366920783720958463934897405820927", + "reverse_auction_seconds": 0, + "time": "2025-07-16T10:29:18", + "total_pow": 514415, + "total_reward_fund_hive": { + "amount": "0", + "nai": "@@000000021", + "precision": 3 + }, + "total_reward_shares2": "0", + "total_vesting_fund_hive": { + "amount": "186431971795", + "nai": "@@000000021", + "precision": 3 + }, + "total_vesting_shares": { + "amount": "311147778100419527", + "nai": "@@000000037", + "precision": 6 + }, + "vesting_reward_percent": 1500, + "virtual_supply": { + "amount": "625573728760", + "nai": "@@000000021", + "precision": 3 + }, + "vote_power_reserve_rate": 10 + } + } + } +] \ No newline at end of file diff --git a/__tests__/assets/api-call-logs/database_api_get_feed_history.json b/__tests__/assets/api-call-logs/database_api_get_feed_history.json new file mode 100644 index 0000000..d9a6ad1 --- /dev/null +++ b/__tests__/assets/api-call-logs/database_api_get_feed_history.json @@ -0,0 +1,1075 @@ +[ + { + "req": { + "jsonrpc": "2.0", + "method": "database_api.get_feed_history", + "params": {}, + "id": 1 + }, + "res": { + "id": 1, + "jsonrpc": "2.0", + "result": { + "current_max_history": { + "base": { + "amount": "241", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + "current_median_history": { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + "current_min_history": { + "base": { + "amount": "234", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + "id": 0, + "market_median_history": { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + "price_history": [ + { + "base": { + "amount": "236", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "237", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "235", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "235", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "234", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "234", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "236", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "237", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "237", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "237", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "236", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "236", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "237", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "237", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "239", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "239", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "239", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "239", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "237", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "237", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "237", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "235", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "235", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "235", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "235", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "237", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "239", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "239", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "239", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "240", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "241", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "240", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "240", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "239", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "237", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "238", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "239", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "239", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "239", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "239", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "2000", + "nai": "@@000000021", + "precision": 3 + } + }, + { + "base": { + "amount": "280", + "nai": "@@000000013", + "precision": 3 + }, + "quote": { + "amount": "1000", + "nai": "@@000000021", + "precision": 3 + } + } + ] + } + } + } +] \ No newline at end of file diff --git a/__tests__/assets/api-call-logs/rc_api_find_rc_accounts.json b/__tests__/assets/api-call-logs/rc_api_find_rc_accounts.json new file mode 100644 index 0000000..74baa30 --- /dev/null +++ b/__tests__/assets/api-call-logs/rc_api_find_rc_accounts.json @@ -0,0 +1,104 @@ +[ + { + "req": { + "jsonrpc": "2.0", + "method": "rc_api.find_rc_accounts", + "params": { + "accounts": [ + "gtg", + "blocktrades", + "thebeedevs" + ] + }, + "id": 1 + }, + "res": { + "id": 1, + "jsonrpc": "2.0", + "result": { + "rc_accounts": [ + { + "account": "gtg", + "delegated_rc": 130000000000, + "max_rc": 2942324145307497, + "max_rc_creation_adjustment": { + "amount": "2020748973", + "nai": "@@000000037", + "precision": 6 + }, + "rc_manabar": { + "current_mana": 161024584599674, + "last_update_time": 1753097298 + }, + "received_delegated_rc": 10174616133 + }, + { + "account": "blocktrades", + "delegated_rc": 16760000000, + "max_rc": "15564167323386971", + "max_rc_creation_adjustment": { + "amount": "2020748973", + "nai": "@@000000037", + "precision": 6 + }, + "rc_manabar": { + "current_mana": "15564167323386971", + "last_update_time": 1753097352 + }, + "received_delegated_rc": 0 + }, + { + "account": "thebeedevs", + "delegated_rc": 0, + "max_rc": 3851240315396, + "max_rc_creation_adjustment": { + "amount": "5279676360", + "nai": "@@000000037", + "precision": 6 + }, + "rc_manabar": { + "current_mana": 3851154925254, + "last_update_time": 1753095357 + }, + "received_delegated_rc": 0 + } + ] + } + } + }, + { + "req": { + "jsonrpc": "2.0", + "method": "rc_api.find_rc_accounts", + "params": { + "accounts": [ + "gtg" + ] + }, + "id": 1 + }, + "res": { + "id": 1, + "jsonrpc": "2.0", + "result": { + "rc_accounts": [ + { + "account": "gtg", + "delegated_rc": 130000000000, + "max_rc": 2935684458790312, + "max_rc_creation_adjustment": { + "amount": "2020748973", + "nai": "@@000000037", + "precision": 6 + }, + "rc_manabar": { + "current_mana": 2152098568737624, + "last_update_time": 1752663375 + }, + "received_delegated_rc": 10174616133 + } + ] + } + } + } +] \ No newline at end of file -- GitLab From f75a341d7957be0b6ad66c987a5a429f03303433 Mon Sep 17 00:00:00 2001 From: fwaszkiewicz Date: Wed, 16 Jul 2025 14:24:25 +0200 Subject: [PATCH 06/11] Implement realistic scenarios tests using live mock data --- __tests__/assets/jest-helper.ts | 41 +- .../mock_realistic_scenarios_live_data.ts | 492 ++++++++++++++++++ package.json | 2 +- playwright.config.ts | 6 + 4 files changed, 535 insertions(+), 6 deletions(-) create mode 100644 __tests__/detailed/mock_realistic_scenarios_live_data.ts diff --git a/__tests__/assets/jest-helper.ts b/__tests__/assets/jest-helper.ts index df1dea0..3b5305e 100644 --- a/__tests__/assets/jest-helper.ts +++ b/__tests__/assets/jest-helper.ts @@ -4,6 +4,8 @@ import { ConsoleMessage, Page, test as base, expect } from "@playwright/test"; import "./globals"; import { IWorkerBee } from "../../dist/bundle"; import type { IWorkerBeeGlobals, TEnvType } from "./globals"; +import { resetMockCallIndexes } from "./mock/api-mock"; +import { resetCallIndexes } from "./mock/jsonRpcMock"; type TWorkerBeeTestCallable = (globals: IWorkerBeeGlobals, ...args: Args) => (R | Promise); @@ -29,6 +31,12 @@ export interface IWorkerBeeFixtureMethods { }; createWorkerBeeTest: >( + callback: (bot: IWorkerBee, resolve: (retVal?: T) => void, reject: (reason?: any) => void) => void, + dynamic?: boolean, + isMockEnvironment?: boolean + ) => Promise; + + createMockWorkerBeeTest: >( callback: (bot: IWorkerBee, resolve: (retVal?: T) => void, reject: (reason?: any) => void) => void, dynamic?: boolean ) => Promise; @@ -42,18 +50,27 @@ interface IWorkerBeeWorker { const envTestFor = ( page: Page, - globalFunction: (env: TEnvType) => Promise + globalFunction: (env: TEnvType) => Promise, + isMockEnvironment: boolean = false ): IWorkerBeeTest["workerbeeTest"] => { const runner = async(checkEqual: boolean, fn: TWorkerBeeTestCallable, ...args: Args): Promise => { let nodeData = await fn(await (globalFunction as (...args: any[]) => any)("node"), ...args); - const webData = await page.evaluate(async({ args: pageArgs, globalFunction: globalFn, webFn }) => { + + if (isMockEnvironment) { + // Reset mock call indexes between node and web environments + resetMockCallIndexes(); + resetCallIndexes(); + } + + const webData = await page.evaluate(async({ args: pageArgs, globalFunction: globalFn, webFn, isMockEnv }) => { /* eslint-disable no-eval */ eval(`window.webEvalFn = ${webFn};`); + eval(`window.isMockEnvironment = ${isMockEnv};`); return (window as Window & typeof globalThis & { webEvalFn: (...args: any[]) => any }).webEvalFn(await globalThis[globalFn]("web"), ...pageArgs); - }, { args, globalFunction: globalFunction.name, webFn: fn.toString() }); + }, { args, globalFunction: globalFunction.name, webFn: fn.toString(), isMockEnv: isMockEnvironment }); if(typeof nodeData === "object") // Remove prototype data from the node result to match webData nodeData = JSON.parse(JSON.stringify(nodeData)); @@ -75,12 +92,21 @@ const envTestFor = ( const createWorkerBeeTest = async >( envTestFor: IWorkerBeeTest["workerbeeTest"], callback: (bot: IWorkerBee, resolve: (retVal?: T) => void, reject: (reason?: any) => void) => void, - dynamic: boolean = false + dynamic: boolean = false, + isMockEnvironment: boolean = false ): Promise => { const testRunner = dynamic ? envTestFor.dynamic : envTestFor; return await testRunner(async ({ WorkerBee }, callbackStr) => { - const bot = new WorkerBee({ chainOptions: { apiTimeout: 0 } }); + const bot = isMockEnvironment + ? new WorkerBee({ + chainOptions: { + apiEndpoint: "http://localhost:8000", + apiTimeout: 0 + } + }) + : new WorkerBee({ chainOptions: { apiTimeout: 0 } }); + await bot.start(); const returnValue = await new Promise((resolve, reject) => { @@ -119,5 +145,10 @@ export const test = base.extend({ createWorkerBeeTest: ({ workerbeeTest }, use) => { use((callback, dynamic) => createWorkerBeeTest(workerbeeTest, callback, dynamic)); + }, + + createMockWorkerBeeTest: ({ page }, use) => { + const mockEnvTestFor = envTestFor(page, createTestFor, true); + use((callback, dynamic) => createWorkerBeeTest(mockEnvTestFor, callback, dynamic, true)); } }); diff --git a/__tests__/detailed/mock_realistic_scenarios_live_data.ts b/__tests__/detailed/mock_realistic_scenarios_live_data.ts new file mode 100644 index 0000000..faafb0d --- /dev/null +++ b/__tests__/detailed/mock_realistic_scenarios_live_data.ts @@ -0,0 +1,492 @@ +/* eslint-disable no-console */ +import { ChromiumBrowser, chromium, expect } from "playwright/test"; +import { test } from "../assets/jest-helper"; + +import { JsonRpcMock, resetMockCallIndexes } from "../assets/mock/api-mock"; +import { resetCallIndexes } from "../assets/mock/jsonRpcMock"; +import { createServer } from "../assets/mock/proxy-mock-server"; + +let browser: ChromiumBrowser; + +let closeServer: () => Promise; + +test.describe("Realistic Scenarios with Live Data", () => { + test.beforeAll(async () => { + browser = await chromium.launch({ + headless: true + }); + + closeServer = await createServer(new JsonRpcMock(), 8000); + }); + + test.beforeEach(async ({ page }) => { + await page.goto("http://localhost:8080/__tests__/assets/test.html", { + waitUntil: "load", + }); + + resetMockCallIndexes(); + resetCallIndexes(); + }); + + test("3.1 - Should be able to create real-time social dashboard", async ({ createMockWorkerBeeTest }) => { + const result = await createMockWorkerBeeTest((bot, resolve, reject) => { + let vote: { text: string, accountName: string, manabar: string } | undefined; + let post: { text: string, accountName: string, manabar: string } | undefined; + let comment: { text: string, accountName: string, manabar: string } | undefined; + + bot.observe.onPosts("gtg") + .or.onComments("gtg") + .or.onVotes("gtg") + .provideAccounts("gtg") + .provideManabarData(/* RC */ 2, "gtg") + .subscribe({ + next(data) { + data.posts.gtg?.forEach(({ operation }) => { + post = { + text: `Post: ${operation.author} - ${operation.title}`, + accountName: JSON.stringify(data.accounts.gtg?.name), + manabar: JSON.stringify(data.manabarData.gtg?.[2]?.currentMana) + }; + }); + + data.comments.gtg?.forEach(({ operation }) => { + comment = { + text: `Comment: ${operation.author} -> ${operation.parent_author}`, + accountName: JSON.stringify(data.accounts.gtg?.name), + manabar: JSON.stringify(data.manabarData.gtg?.[2]?.currentMana) + }; + }); + + data.votes.gtg?.forEach(({ operation }) => { + vote = { + text: `Vote: ${operation.voter} - ${operation.author}`, + accountName: JSON.stringify(data.accounts.gtg?.name), + manabar: JSON.stringify(data.manabarData.gtg?.[2]?.currentMana) + }; + }); + + if (post !== undefined && vote !== undefined && comment !== undefined) + resolve([post, vote, comment]); + }, + error: (err) => { + console.error(err); + reject(err); + } + }); + }); + + expect(result).toEqual([ + { + accountName: "\"gtg\"", + manabar: "{\"low\":2125861720,\"high\":501074,\"unsigned\":true}", + text: "Post: gtg - SkyTeam Airline Alliance - Official partner of HiveFest", + }, + { + accountName: "\"gtg\"", + manabar: "{\"low\":1965705338,\"high\":37491,\"unsigned\":true}", + text: "Vote: gtg - hbd.funder", + }, + { + accountName: "\"gtg\"", + manabar: "{\"low\":2125861720,\"high\":501074,\"unsigned\":true}", + text: "Comment: gtg -> purepinay", + } + ]); + }); + + test("3.2 - Should be able to create account health monitor", async ({ createMockWorkerBeeTest }) => { + const result = await createMockWorkerBeeTest((bot, resolve, reject) => { + let manabarData: string | undefined; + + bot.observe.onAccountsBalanceChange(false, "gtg") + .or.onAccountsMetadataChange("gtg") + .or.onAccountsManabarPercent(0, 100, "gtg") + .provideAccounts("gtg") + .subscribe({ + next(data) { + manabarData = `Reached ${data.manabarData.gtg?.[0]?.percent}% of manabar`; + + if ( + manabarData !== undefined && + // eslint-disable-next-line max-len + JSON.stringify(data.accounts.gtg?.jsonMetadata) === JSON.stringify({profile:{witness_description:"Gandalf the Grey, building Hive, improving Hive infrastructure.", profile_image:"https://grey.house/img/grey_4.jpg", name:"Gandalf the Grey", about:"IT Wizard, Hive Witness", location:"Hive", version:2}}) && + data.accounts.gtg?.balance.HBD.savings.amount === "3468" + ) + resolve([manabarData, data.accounts.gtg?.jsonMetadata, data.accounts.gtg?.balance.HBD.savings.amount]); + }, + error: (err) => { + console.error(err); + reject(err); + } + }); + }); + + expect(result).toEqual([ + "Reached 100% of manabar", + { + profile: { + about: "IT Wizard, Hive Witness", + location: "Hive", + name: "Gandalf the Grey", + profile_image: "https://grey.house/img/grey_4.jpg", + version: 2, + witness_description: "Gandalf the Grey, building Hive, improving Hive infrastructure.", + }, + }, + "3468" // HBD savings balance + ]); + }); + + test("3.3 - Should be able to create market alert system", async ({ createMockWorkerBeeTest }) => { + const result = await createMockWorkerBeeTest((bot, resolve, reject) => { + bot.observe.onFeedPriceChange(95) + .or.onFeedPriceNoChange(1) + .or.onWitnessesMissedBlocks(5, "gtg") + .provideFeedPriceData() + .subscribe({ + next(data) { + let percentChange = 0; + + const priceHistoryArray = Array.from(data.feedPrice.priceHistory); + + const price1 = Number.parseInt(priceHistoryArray[0].base!.amount) / Number.parseInt(priceHistoryArray[0].quote!.amount); + const price2 = Number.parseInt(priceHistoryArray[1].base!.amount) / Number.parseInt(priceHistoryArray[1].quote!.amount); + + percentChange = Math.abs(price1 - price2) / price2 * 100; + + resolve(percentChange); + }, + error: (err) => { + console.error(err); + reject(err); + } + }); + }); + + expect(result).toEqual(134.30962343096238); + }); + + test("3.5 - Should be able to create investment portfolio monitor", async ({ createMockWorkerBeeTest }) => { + const result = await createMockWorkerBeeTest((bot, resolve, reject) => { + const marketOperations: string[] = []; + + bot.observe.onAccountsBalanceChange(true, "gtg", "blocktrades") + .or.onWhaleAlert(bot.chain!.hiveCoins(1000)) + .or.onExchangeTransfer() + .provideAccounts("gtg", "blocktrades") + .subscribe({ + next(data) { + data.exchangeTransferOperations.forEach(({ operation }) => { + marketOperations.push(`Exchange transfer: ${operation.from} -> ${operation.to} (${operation.amount.amount})`); + }); + + data.whaleOperations.forEach(({ operation }) => { + marketOperations.push(`Whale alert: ${operation.from} -> ${operation.to} (${operation.amount.amount})`); + }); + + if (marketOperations.length >= 2) + resolve(marketOperations); + }, + error: (err) => { + console.error(err); + reject(err); + } + }); + }); + + expect(result).toEqual([ + "Exchange transfer: mxchive -> inhivepool (23890)", + "Exchange transfer: bdhivesteem -> gtg (1000)", + "Whale alert: mxchive -> inhivepool (23890)", + "Whale alert: blocktrades -> gtg (10000000)" + ]); + }); + + test("3.6 - Should be able to create content aggregation service", async ({ createMockWorkerBeeTest }) => { + const result = await createMockWorkerBeeTest((bot, resolve, reject) => { + const contentOperations: string[] = []; + + bot.observe.onPosts("mtyszczak") + .or.onPosts("fwaszkiewicz") + .or.onReblog("thebeedevs") + .subscribe({ + next(data) { + data.posts.mtyszczak?.forEach(({ operation }) => { + contentOperations.push(`Post: ${operation.author} - ${operation.title}`); + }); + + data.posts.fwaszkiewicz?.forEach(({ operation }) => { + contentOperations.push(`Post: ${operation.author} - ${operation.title}`); + }); + + data.reblogs.thebeedevs?.forEach(({ operation }) => { + contentOperations.push(`Reblog: ${operation.account} -> ${operation.author}/${operation.permlink}`); + }); + + if (contentOperations.length >= 3) + resolve(contentOperations); + }, + error: (err) => { + console.error(err); + reject(err); + } + }); + }); + + expect(result).toEqual([ + "Post: mtyszczak - Write on Hive, Read Everywhere!", + "Post: fwaszkiewicz - Hi To Hive! 🐝", + "Reblog: thebeedevs -> fwaszkiewicz/hi-to-hive", + ]); + }); + + test("3.7 - Should be able to create engagement optimization bot", async ({ createMockWorkerBeeTest }) => { + const result = await createMockWorkerBeeTest((bot, resolve, reject) => { + const content: string[] = []; + + bot.observe.onAccountsManabarPercent(/* UPVOTE */ 0, 90, "gtg") + .or.onPosts("fwaszkiewicz") + .or.onComments("fwaszkiewicz") + .provideManabarData(/* UPVOTE */ 0, "gtg") + .subscribe({ + next(data) { + data.posts.fwaszkiewicz?.forEach(({ operation }) => { + content.push(`Post: ${operation.author} - ${operation.title}`); + }); + + data.comments.fwaszkiewicz?.forEach(({ operation }) => { + content.push(`Comment: ${operation.author} -> ${operation.parent_author}`); + }); + + if (data.manabarData.gtg![0]!.percent >= 90 && content.length >= 2) + resolve(`Reached 90% of manabar for upvote: ${data.manabarData.gtg![0]!.percent}, available content: ${content}`); + }, + error: (err) => { + console.error(err); + reject(err); + } + }); + }); + + expect(result).toEqual("Reached 90% of manabar for upvote: 100, available content: Post: fwaszkiewicz - Hi To Hive! 🐝,Comment: fwaszkiewicz -> mtyszczak"); + }); + + test("4.1 - Should be able to perform complete account analysis", async ({ createMockWorkerBeeTest }) => { + const result = await createMockWorkerBeeTest((bot, resolve, reject) => { + const content: string[] = []; + + bot.observe.onBlock() + .provideAccounts("gtg") + .provideRcAccounts("gtg") + .provideManabarData(/* RC */2, "gtg") + .provideManabarData(/* UPVOTE */0, "gtg") + .provideBlockData() + .provideFeedPriceData() + .subscribe({ + next(data) { + content.push(`Account: ${data.accounts.gtg?.name}, Balance: ${data.accounts.gtg?.balance.HBD.savings.amount}`); + content.push(`RC mana: ${data.rcAccounts.gtg?.rcManabar.currentMana}`); + content.push(`UPVOTE mana: ${data.manabarData.gtg?.[0]?.currentMana}`); + content.push(`Block number: ${data.block.number}`); + content.push(`Feed price: ${Array.from(data.feedPrice.priceHistory)[0].base!.amount}/${Array.from(data.feedPrice.priceHistory)[0].quote!.amount}`); + + if (content.length >= 5) + resolve(content); + }, + error: (err) => { + console.error(err); + reject(err); + } + }); + }); + + expect(result).toEqual([ + "Account: gtg, Balance: 0", + "RC mana: 161024584599674", + "UPVOTE mana: 2897631713028020", + "Block number: 97477291", + "Feed price: 280/1000" + ]); + }); + + test("4.2 - Should be able to perform multi-account comparison", async ({ createMockWorkerBeeTest }) => { + const result = await createMockWorkerBeeTest((bot, resolve, reject) => { + const content: string[] = []; + + bot.observe.onBlock() + .provideAccounts("gtg", "blocktrades", "thebeedevs") + .provideManabarData(/* RC */2, "gtg", "blocktrades", "thebeedevs") + .provideWitnesses("gtg", "blocktrades") + .subscribe({ + next(data) { + content.push(`Account: ${data.accounts.gtg?.name}, Balance: ${data.accounts.gtg?.balance.HBD.savings.amount}`); + content.push(`RC mana: ${data.manabarData.gtg?.[2]?.currentMana}`); + content.push(`Witnesses missed blocks: ${data.witnesses.gtg?.totalMissedBlocks}`); + + content.push(`Account: ${data.accounts.blocktrades?.name}, Balance: ${data.accounts.blocktrades?.balance.HBD.savings.amount}`); + content.push(`RC mana: ${data.manabarData.blocktrades?.[2]?.currentMana}`); + content.push(`Witnesses missed blocks: ${data.witnesses.blocktrades?.totalMissedBlocks}`); + + content.push(`Account: ${data.accounts.thebeedevs?.name}, Balance: ${data.accounts.thebeedevs?.balance.HBD.savings.amount}`); + content.push(`RC mana: ${data.manabarData.thebeedevs?.[2]?.currentMana}`); + + if (content.length >= 8) + resolve(content); + }, + error: (err) => { + console.error(err); + reject(err); + } + }); + }); + + expect(result).toEqual([ + "Account: gtg, Balance: 0", + "RC mana: 161024584599674", + "Witnesses missed blocks: 988", + "Account: blocktrades, Balance: 130076015", + "RC mana: 15564167323386971", + "Witnesses missed blocks: 3728", + "Account: thebeedevs, Balance: 215216", + "RC mana: 3851154925254" + ]); + }); + + test("4.3 - Should be able to create comprehensive market analysis", async ({ createMockWorkerBeeTest }) => { + const result = await createMockWorkerBeeTest((bot, resolve, reject) => { + const content: string[] = []; + + bot.observe.onBlock() + .or.onInternalMarketOperation() + .or.onExchangeTransfer() + .provideBlockData() + .provideFeedPriceData() + .provideAccounts("gtg", "blocktrades") + .subscribe({ + next(data) { + data.internalMarketOperations.forEach(({ operation }) => { + content.push(`Internal market operation: owner: ${operation.owner}, order id: ${operation.orderId}, block : ${data.block.number}`); + }); + + data.exchangeTransferOperations.forEach(({ operation }) => { + content.push(`Exchange transfer: ${operation.from} -> ${operation.to} (${operation.amount.amount}), block: ${data.block.number}`); + }); + + if (content.length >= 2) + resolve(content); + }, + error: (err) => { + console.error(err); + reject(err); + } + }); + }); + + expect(result).toEqual([ + "Internal market operation: owner: honeybot, order id: 1485200410, block : 97477294", + "Exchange transfer: mxchive -> inhivepool (23890), block: 97477294", + "Exchange transfer: bdhivesteem -> gtg (1000), block: 97477294" + ]); + }); + + test("4.4 - Should be able to create social network analysis", async ({ createMockWorkerBeeTest }) => { + const result = await createMockWorkerBeeTest((bot, resolve, reject) => { + const content: string[] = []; + + bot.observe.onFollow("gtg") + .or.onFollow("blocktrades") + .or.onReblog("gtg") + .or.onMention("gtg") + .provideAccounts("gtg", "blocktrades") + .provideManabarData(/* RC */ 2, "gtg", "blocktrades") + .subscribe({ + next(data) { + data.follows.gtg?.forEach(({ operation }) => { + content.push(`Follow: ${operation.follower} -> ${operation.following}, (${data.accounts.gtg?.name})`); + }); + + data.follows.blocktrades?.forEach(({ operation }) => { + content.push(`Follow: ${operation.follower} -> ${operation.following}, (${data.accounts.blocktrades?.name})`); + }); + + data.reblogs.gtg?.forEach(({ operation }) => { + content.push(`Reblog: ${operation.account} -> ${operation.author}/${operation.permlink} (${data.accounts.gtg?.name})`); + }); + + data.mentioned.gtg?.forEach((operation) => { + content.push(`Mention: ${operation.author} -> ${operation.permlink} (${data.accounts.gtg?.name})`); + }); + + if (content.length >= 4) + resolve(content); + }, + error: (err) => { + console.error(err); + reject(err); + } + }); + }); + + expect(result).toEqual([ + "Follow: gtg -> thebeedevs, (gtg)", + "Follow: blocktrades -> thebeedevs, (blocktrades)", + "Reblog: gtg -> fwaszkiewicz/hi-to-hive (gtg)", + "Mention: mtyszczak -> write-on-hive-read-everywhere (gtg)", + "Mention: fwaszkiewicz -> hi-to-hive (gtg)" + ]); + }); + + test("4.5 - Should be able to create content performance dashboard", async ({ createMockWorkerBeeTest }) => { + const result = await createMockWorkerBeeTest((bot, resolve, reject) => { + const content: string[] = []; + + bot.observe.onPosts("gtg") + .or.onComments("gtg") + .or.onVotes("gtg") + .or.onReblog("gtg") + .provideAccounts("gtg") + .provideManabarData(/* UPVOTE */ 0, "gtg") + .provideBlockData() + .subscribe({ + next(data) { + data.posts.gtg?.forEach(({ operation }) => { + content.push(`Post: ${operation.author} - ${operation.title} (${data.accounts.gtg?.name}) (${data.manabarData.gtg?.[0]?.currentMana})`); + }); + + data.comments.gtg?.forEach(({ operation }) => { + // eslint-disable-next-line max-len + content.push(`Comment: ${operation.author} -> ${operation.parent_author} (${data.accounts.gtg?.name}) (${data.manabarData.gtg?.[0]?.currentMana})`); + }); + + data.votes.gtg?.forEach(({ operation }) => { + content.push(`Vote: ${operation.voter} - ${operation.author} (${data.accounts.gtg?.name}) (${data.manabarData.gtg?.[0]?.currentMana})`); + }); + + data.reblogs.gtg?.forEach(({ operation }) => { + // eslint-disable-next-line max-len + content.push(`Reblog: ${operation.account} -> ${operation.author}/${operation.permlink} (${data.accounts.gtg?.name}) (${data.manabarData.gtg?.[0]?.currentMana})`); + }); + + if (content.length >= 4) + resolve(content); + }, + error: (err) => { + console.error(err); + reject(err); + } + }); + }); + + expect(result).toEqual([ + "Vote: gtg - hbd.funder (gtg) (2897631713028020)", + "Comment: gtg -> purepinay (gtg) (18469160006473)", + "Reblog: gtg -> fwaszkiewicz/hi-to-hive (gtg) (18469160006473)", + "Post: gtg - SkyTeam Airline Alliance - Official partner of HiveFest (gtg) (18469160006473)" + ]); + }); + + test.afterAll(async () => { + await browser.close(); + await closeServer(); + }); +}); diff --git a/package.json b/package.json index 1ccbefe..ac0d689 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "build": "tsc", "postbuild": "rollup -c && tsx ./npm-common-config/ts-common/terser.ts && size-limit", "pretest": "playwright install chromium", - "test": "unset CI && playwright test --workers 4 --max-failures 1 --project=workerbee_testsuite" + "test": "unset CI && playwright test --workers 4 --max-failures 1 --project=workerbee_testsuite --project=workerbee_testsuite_mock" }, "size-limit": [ { diff --git a/playwright.config.ts b/playwright.config.ts index 29b508f..42194ce 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -11,6 +11,12 @@ export default defineConfig({ { name: "workerbee_testsuite", testDir: "./__tests__/" + }, + { + name: "workerbee_testsuite_mock", + testDir: "./__tests__/", + testMatch: "mock*", + fullyParallel: false } ], // Run your local dev server before starting the tests -- GitLab From 1db298dc26d86eae6faafe16a5867a660b78df32 Mon Sep 17 00:00:00 2001 From: fwaszkiewicz Date: Thu, 17 Jul 2025 14:12:03 +0200 Subject: [PATCH 07/11] Fix division by 0 in FeedPriceChangeFilter Used number type instead of bigint to preserve floating point values. --- .../filters/feed-price-change-percent-filter.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/chain-observers/filters/feed-price-change-percent-filter.ts b/src/chain-observers/filters/feed-price-change-percent-filter.ts index 38740c6..14b2844 100644 --- a/src/chain-observers/filters/feed-price-change-percent-filter.ts +++ b/src/chain-observers/filters/feed-price-change-percent-filter.ts @@ -31,16 +31,17 @@ export class FeedPriceChangeFilter extends FilterBase { if (history.length < 2) return false; - const price1 = BigInt(history[0].base!.amount) / BigInt(history[0].quote!.amount); - const price2 = BigInt(history[1].base!.amount) / BigInt(history[1].quote!.amount); + const price1 = Number.parseInt(history[0].base!.amount) / Number.parseInt(history[0].quote!.amount); + const price2 = Number.parseInt(history[1].base!.amount) / Number.parseInt(history[1].quote!.amount); - let percentChange = (price1 - price2) * BigInt(100) / price2; + // Avoid division by zero + if (price2 === 0) + return false; - if (percentChange < 0) - percentChange = -percentChange; + const percentChange = Math.abs(price1 - price2) / price2 * 100; this.previousUpdateTimestamp = lastFeedPriceRetrievalTimestamp; - return Number(percentChange.toString()) >= this.feedPriceChangePercentMin; + return percentChange >= this.feedPriceChangePercentMin; } } -- GitLab From f22becc4552bcf138289b814f1f6d363bbd9b276 Mon Sep 17 00:00:00 2001 From: fwaszkiewicz Date: Tue, 22 Jul 2025 12:01:11 +0200 Subject: [PATCH 08/11] Fix multiple mentions alerting per one post --- src/chain-observers/providers/mention-provider.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/chain-observers/providers/mention-provider.ts b/src/chain-observers/providers/mention-provider.ts index c08d6f8..36910d6 100644 --- a/src/chain-observers/providers/mention-provider.ts +++ b/src/chain-observers/providers/mention-provider.ts @@ -36,17 +36,28 @@ export class MentionedAccountProvider = Ar const { operationsPerType } = await data.get(OperationClassifier); + const postMetadataSet = new Set(); + if (operationsPerType.comment_operation) for(const { operation } of operationsPerType.comment_operation) { + const postHash = `${operation.author}-${operation.permlink}`; + + if (postMetadataSet.has(postHash)) + continue; + + postMetadataSet.add(postHash); + const mentionRegex = /@([a-z0-9.-]+)/gi; let match: RegExpExecArray | null; - while ((match = mentionRegex.exec(operation.body)) !== null) { + let foundMention = false; + while ((match = mentionRegex.exec(operation.body)) !== null && !foundMention) { const mentionedAccount = match[1] as TAccountName; if (this.accounts.has(mentionedAccount)) { if (!mentioned[mentionedAccount]) mentioned[mentionedAccount] = []; mentioned[mentionedAccount].push(operation); + foundMention = true; } } } -- GitLab From 7cab5c6953b7862af4728d8e813ef7635dfa5860 Mon Sep 17 00:00:00 2001 From: fwaszkiewicz Date: Wed, 23 Jul 2025 13:06:54 +0200 Subject: [PATCH 09/11] Refactor createWorkerBeeTest fixture to simplify tests implementation --- __tests__/assets/jest-helper.ts | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/__tests__/assets/jest-helper.ts b/__tests__/assets/jest-helper.ts index 3b5305e..3b12806 100644 --- a/__tests__/assets/jest-helper.ts +++ b/__tests__/assets/jest-helper.ts @@ -1,8 +1,11 @@ /* eslint-disable no-console */ +import { IHiveChainInterface } from "@hiveio/wax"; import { ConsoleMessage, Page, test as base, expect } from "@playwright/test"; import "./globals"; import { IWorkerBee } from "../../dist/bundle"; +import { TPastQueen } from "../../src/past-queen"; +import { QueenBee } from "../../src/queen"; import type { IWorkerBeeGlobals, TEnvType } from "./globals"; import { resetMockCallIndexes } from "./mock/api-mock"; import { resetCallIndexes } from "./mock/jsonRpcMock"; @@ -31,13 +34,15 @@ export interface IWorkerBeeFixtureMethods { }; createWorkerBeeTest: >( - callback: (bot: IWorkerBee, resolve: (retVal?: T) => void, reject: (reason?: any) => void) => void, + callback: (bot: QueenBee<{}> | TPastQueen<{}>, resolve: (retVal?: T) => void, reject: (reason?: any) => void, chain?: IHiveChainInterface) => void, + pastDataFrom?: number, + pastDataTo?: number, dynamic?: boolean, isMockEnvironment?: boolean ) => Promise; createMockWorkerBeeTest: >( - callback: (bot: IWorkerBee, resolve: (retVal?: T) => void, reject: (reason?: any) => void) => void, + callback: (bot: QueenBee<{}>, resolve: (retVal?: T) => void, reject: (reason?: any) => void, chain?: IHiveChainInterface) => void, dynamic?: boolean ) => Promise; } @@ -91,14 +96,16 @@ const envTestFor = ( const createWorkerBeeTest = async >( envTestFor: IWorkerBeeTest["workerbeeTest"], - callback: (bot: IWorkerBee, resolve: (retVal?: T) => void, reject: (reason?: any) => void) => void, + callback: (bot: QueenBee<{}> | TPastQueen<{}>, resolve: (retVal?: T) => void, reject: (reason?: any) => void, chain?: IHiveChainInterface) => void, + pastDataFrom?: number, + pastDataTo?: number, dynamic: boolean = false, isMockEnvironment: boolean = false ): Promise => { const testRunner = dynamic ? envTestFor.dynamic : envTestFor; - return await testRunner(async ({ WorkerBee }, callbackStr) => { - const bot = isMockEnvironment + return await testRunner(async ({ WorkerBee }, callbackStr, pastFrom, pastTo, isMock) => { + const bot = isMock ? new WorkerBee({ chainOptions: { apiEndpoint: "http://localhost:8000", @@ -109,17 +116,24 @@ const createWorkerBeeTest = async >( await bot.start(); + let finalBot: IWorkerBee | TPastQueen<{}>; + + if (!isMock && pastFrom && pastTo) + finalBot = bot.providePastOperations(pastFrom, pastTo) as unknown as TPastQueen<{}>; + else + finalBot = bot.observe as unknown as QueenBee<{}>; + const returnValue = await new Promise((resolve, reject) => { // Reconstruct callback from string in web environment const reconstructedCallback = eval(`(${callbackStr})`); - reconstructedCallback(bot, resolve, reject); + reconstructedCallback(finalBot, resolve, reject, bot.chain); }); bot.stop(); bot.delete(); return returnValue; - }, callback.toString()); + }, callback.toString(), pastDataFrom, pastDataTo, isMockEnvironment); } export const test = base.extend({ @@ -144,11 +158,12 @@ export const test = base.extend({ }, createWorkerBeeTest: ({ workerbeeTest }, use) => { - use((callback, dynamic) => createWorkerBeeTest(workerbeeTest, callback, dynamic)); + use((callback, pastDataFrom, pastDataTo, dynamic) => createWorkerBeeTest(workerbeeTest, callback, pastDataFrom, pastDataTo, dynamic)); }, createMockWorkerBeeTest: ({ page }, use) => { const mockEnvTestFor = envTestFor(page, createTestFor, true); - use((callback, dynamic) => createWorkerBeeTest(mockEnvTestFor, callback, dynamic, true)); + // TODO: Improve types to not cast to `any` + use((callback, dynamic) => createWorkerBeeTest(mockEnvTestFor, callback as any, undefined, undefined, dynamic, true)); } }); -- GitLab From 648bcf50c51934235d0ac2fed5337b0b85440e26 Mon Sep 17 00:00:00 2001 From: fwaszkiewicz Date: Wed, 23 Jul 2025 13:07:40 +0200 Subject: [PATCH 10/11] Adjust tests implementation to new fixture interface --- __tests__/detailed/bot_providers.ts | 52 ++++++------- __tests__/detailed/individual_filter_tests.ts | 77 +++++++++---------- .../mock_realistic_scenarios_live_data.ts | 26 +++---- __tests__/detailed/realistic_scenarios.ts | 58 ++++++-------- 4 files changed, 101 insertions(+), 112 deletions(-) diff --git a/__tests__/detailed/bot_providers.ts b/__tests__/detailed/bot_providers.ts index 8f5d4fd..3aa3419 100644 --- a/__tests__/detailed/bot_providers.ts +++ b/__tests__/detailed/bot_providers.ts @@ -5,7 +5,7 @@ import { test } from "../assets/jest-helper"; test.describe("Bot Providers", () => { test("Should be able to provide witnesses", async({ createWorkerBeeTest }) => { const result = await createWorkerBeeTest((bot, resolve, reject) => { - const observer = bot.observe.onBlock().provideWitnesses("gtg"); + const observer = bot.onBlock().provideWitnesses("gtg"); observer.subscribe({ next: (data) => { @@ -18,7 +18,7 @@ test.describe("Bot Providers", () => { }, complete: () => resolve() }); - }, true); + }, undefined, undefined, true); expect(result["gtg"]).toBeDefined(); expect(result["gtg"].owner).toBe("gtg"); @@ -28,7 +28,7 @@ test.describe("Bot Providers", () => { test("Should be able to provide RC accounts", async({ createWorkerBeeTest }) => { const result = await createWorkerBeeTest((bot, resolve, reject) => { - const observer = bot.observe.onBlock().provideRcAccounts("gtg"); + const observer = bot.onBlock().provideRcAccounts("gtg"); observer.subscribe({ next: (data) => { @@ -41,7 +41,7 @@ test.describe("Bot Providers", () => { }, complete: () => resolve() }); - }, true); + }, undefined, undefined, true); expect(result["gtg"]).toBeDefined(); expect(result["gtg"].name).toBe("gtg"); @@ -50,7 +50,7 @@ test.describe("Bot Providers", () => { test("Should be able to provide feed price data", async({ createWorkerBeeTest }) => { const result = await createWorkerBeeTest((bot, resolve, reject) => { - const observer = bot.observe.onBlock().provideFeedPriceData(); + const observer = bot.onBlock().provideFeedPriceData(); observer.subscribe({ next: (data) => { @@ -63,7 +63,7 @@ test.describe("Bot Providers", () => { }, complete: () => resolve() }); - }, true); + }, undefined, undefined, true); expect(result).toHaveProperty("currentMedianHistory"); expect(result).toHaveProperty("currentMinHistory"); @@ -73,7 +73,7 @@ test.describe("Bot Providers", () => { test("Should be able to provide block header data", async({ createWorkerBeeTest }) => { const result = await createWorkerBeeTest((bot, resolve, reject) => { - const observer = bot.observe.onBlock().provideBlockHeaderData(); + const observer = bot.onBlock().provideBlockHeaderData(); observer.subscribe({ next: (data) => { @@ -86,7 +86,7 @@ test.describe("Bot Providers", () => { }, complete: () => resolve() }); - }, true); + }, undefined, undefined, true); expect(result.number).not.toBeNaN(); expect(result).toHaveProperty("timestamp"); @@ -95,7 +95,7 @@ test.describe("Bot Providers", () => { test("Should be able to provide block data", async({ createWorkerBeeTest }) => { const result = await createWorkerBeeTest((bot, resolve, reject) => { - const observer = bot.observe.onBlock().provideBlockData(); + const observer = bot.onBlock().provideBlockData(); observer.subscribe({ next: (data) => { @@ -108,7 +108,7 @@ test.describe("Bot Providers", () => { }, complete: () => resolve() }); - }, true); + }, undefined, undefined, true); expect(result.number).not.toBeNaN(); expect(result).toHaveProperty("transactions"); @@ -117,7 +117,7 @@ test.describe("Bot Providers", () => { test("Should be able to provide accounts", async({ createWorkerBeeTest }) => { const result = await createWorkerBeeTest((bot, resolve, reject) => { - const observer = bot.observe.onBlock().provideAccounts("gtg"); + const observer = bot.onBlock().provideAccounts("gtg"); observer.subscribe({ next: (data) => { @@ -130,7 +130,7 @@ test.describe("Bot Providers", () => { }, complete: () => resolve() }); - }, true); + }, undefined, undefined, true); expect(result["gtg"]).toBeDefined(); expect(result["gtg"].name).toBe("gtg"); @@ -138,7 +138,7 @@ test.describe("Bot Providers", () => { test("Should be able to provide manabar data", async({ createWorkerBeeTest }) => { const result = await createWorkerBeeTest((bot, resolve, reject) => { - const observer = bot.observe.onBlock().provideManabarData(2, "gtg"); // Upvote manabar + const observer = bot.onBlock().provideManabarData(2, "gtg"); // Upvote manabar observer.subscribe({ next: (data) => { @@ -151,7 +151,7 @@ test.describe("Bot Providers", () => { }, complete: () => resolve() }); - }, true); + }, undefined, undefined, true); expect(result["gtg"]).toBeDefined(); expect(result["gtg"][2].percent).toBeGreaterThanOrEqual(0); @@ -159,7 +159,7 @@ test.describe("Bot Providers", () => { test("Should be able to combine witnesses and accounts providers", async({ createWorkerBeeTest }) => { const result = await createWorkerBeeTest((bot, resolve, reject) => { - const observer = bot.observe.onBlock() + const observer = bot.onBlock() .provideWitnesses("gtg") .provideAccounts("gtg"); @@ -174,7 +174,7 @@ test.describe("Bot Providers", () => { }, complete: () => resolve() }); - }, true); + }, undefined, undefined, true); expect(result.witnesses["gtg"]).toBeDefined(); expect(result.witnesses["gtg"].owner).toBe("gtg"); @@ -184,7 +184,7 @@ test.describe("Bot Providers", () => { test("Should be able to combine feed price data and block header providers", async({ createWorkerBeeTest }) => { const result = await createWorkerBeeTest((bot, resolve, reject) => { - const observer = bot.observe.onBlock() + const observer = bot.onBlock() .provideFeedPriceData() .provideBlockHeaderData(); @@ -199,7 +199,7 @@ test.describe("Bot Providers", () => { }, complete: () => resolve() }); - }, true); + }, undefined, undefined, true); expect(result.feedPrice).toHaveProperty("currentMedianHistory"); expect(result.feedPrice).toHaveProperty("priceHistory"); @@ -210,7 +210,7 @@ test.describe("Bot Providers", () => { test("Should be able to combine multiple account-related providers", async({ createWorkerBeeTest }) => { const result = await createWorkerBeeTest((bot, resolve, reject) => { - const observer = bot.observe.onBlock() + const observer = bot.onBlock() .provideAccounts("gtg") .provideRcAccounts("gtg") .provideManabarData(2, "gtg"); // Upvote manabar @@ -226,7 +226,7 @@ test.describe("Bot Providers", () => { }, complete: () => resolve() }); - }, true); + }, undefined, undefined, true); expect(result.accounts["gtg"]).toBeDefined(); expect(result.accounts["gtg"].name).toBe("gtg"); @@ -239,7 +239,7 @@ test.describe("Bot Providers", () => { test("Should be able to combine block data with feed price data", async({ createWorkerBeeTest }) => { const result = await createWorkerBeeTest((bot, resolve, reject) => { - const observer = bot.observe.onBlock() + const observer = bot.onBlock() .provideBlockData() .provideFeedPriceData(); @@ -254,7 +254,7 @@ test.describe("Bot Providers", () => { }, complete: () => resolve() }); - }, true); + }, undefined, undefined, true); expect(result.block.number).not.toBeNaN(); expect(result.block).toHaveProperty("transactions"); @@ -265,7 +265,7 @@ test.describe("Bot Providers", () => { test("Should be able to combine all available providers", async({ createWorkerBeeTest }) => { const result = await createWorkerBeeTest((bot, resolve, reject) => { - const observer = bot.observe.onBlock() + const observer = bot.onBlock() .provideWitnesses("gtg") .provideAccounts("gtg") .provideRcAccounts("gtg") @@ -295,7 +295,7 @@ test.describe("Bot Providers", () => { }, complete: () => resolve() }); - }, true); + }, undefined, undefined, true); // Test witnesses provider expect(result.witnesses["gtg"]).toBeDefined(); @@ -326,7 +326,7 @@ test.describe("Bot Providers", () => { test("Should be able to combine multiple accounts for different providers", async({ createWorkerBeeTest }) => { const result = await createWorkerBeeTest((bot, resolve, reject) => { - const observer = bot.observe.onBlock() + const observer = bot.onBlock() .provideWitnesses("gtg", "steemit") .provideAccounts("gtg", "steemit", "blocktrades") .provideRcAccounts("gtg", "blocktrades"); @@ -342,7 +342,7 @@ test.describe("Bot Providers", () => { }, complete: () => resolve() }); - }, true); + }, undefined, undefined, true); // Test witnesses for multiple accounts expect(result.witnesses["gtg"]).toBeDefined(); diff --git a/__tests__/detailed/individual_filter_tests.ts b/__tests__/detailed/individual_filter_tests.ts index 972c606..ad0ae14 100644 --- a/__tests__/detailed/individual_filter_tests.ts +++ b/__tests__/detailed/individual_filter_tests.ts @@ -7,7 +7,7 @@ test.describe("WorkerBee Individual Filter Verification", () => { const result = await createWorkerBeeTest((bot, resolve, reject) => { const capturedPosts: string[] = []; - bot.providePastOperations(96549390, 96549415).onPosts("mtyszczak", "author2", "author3").subscribe({ + bot.onPosts("mtyszczak", "author2", "author3").subscribe({ next(data) { for (const author of ["mtyszczak", "author2", "author3"]) data.posts[author]?.forEach(({ operation }) => { @@ -20,7 +20,7 @@ test.describe("WorkerBee Individual Filter Verification", () => { }, complete: () => resolve(capturedPosts) }); - }); + }, 96549390, 96549415); expect(result).toEqual(["Post by mtyszczak: hi-ve-everyone"]); }); @@ -29,7 +29,7 @@ test.describe("WorkerBee Individual Filter Verification", () => { const result = await createWorkerBeeTest((bot, resolve, reject) => { const capturedPosts: Array<{ author: string; blockNumber: number }> = []; - bot.providePastOperations(97632050, 97632075).onBlock().or.onPosts("comandoyeya", "daddydog").subscribe({ + bot.onBlock().or.onPosts("comandoyeya", "daddydog").subscribe({ next(data) { for (const author of ["comandoyeya", "daddydog"]) data.posts[author]?.forEach(({ operation }) => { @@ -46,7 +46,7 @@ test.describe("WorkerBee Individual Filter Verification", () => { }, complete: () => resolve(capturedPosts) }); - }); + }, 97632050, 97632075); expect(result).toEqual([ { @@ -69,7 +69,7 @@ test.describe("WorkerBee Individual Filter Verification", () => { * Monitor an account known to create comments in this range. * Also check for comments in the same range to verify account was active */ - bot.providePastOperations(96549690, 96549715).onPosts("gtg").or.onComments("gtg").subscribe({ + bot.onPosts("gtg").or.onComments("gtg").subscribe({ next(data) { // Count posts (should be 0) data.posts["gtg"]?.forEach(() => { @@ -87,7 +87,7 @@ test.describe("WorkerBee Individual Filter Verification", () => { }, complete: () => resolve({ postsDetected, commentsDetected }) }); - }); + }, 96549690, 96549715); // Should detect comments but NOT posts expect(result.commentsDetected).toBeGreaterThan(0); @@ -106,7 +106,7 @@ test.describe("WorkerBee Individual Filter Verification", () => { * Monitor multiple accounts for posts (should not trigger for comment activity) * Also Verify these accounts were active with comments */ - bot.providePastOperations(96549690, 96549715).onPosts(...testAccounts).or.onComments(...testAccounts).subscribe({ + bot.onPosts(...testAccounts).or.onComments(...testAccounts).subscribe({ next(data) { testAccounts.forEach(account => { data.posts[account]?.forEach(() => { @@ -124,7 +124,7 @@ test.describe("WorkerBee Individual Filter Verification", () => { }, complete: () => resolve({ postResults, commentResults }) }); - }); + }, 96549690, 96549715); const totalComments = Object.values(result.commentResults).reduce((sum, count) => sum + count, 0); const totalPosts = Object.values(result.postResults).reduce((sum, count) => sum + count, 0); @@ -142,7 +142,7 @@ test.describe("WorkerBee Individual Filter Verification", () => { * Monitor for posts from a specific account * Also Verify other accounts were posting in this range */ - bot.providePastOperations(96549390, 96549415).onPosts("nonexistent-account").or.onPosts("mtyszczak").subscribe({ + bot.onPosts("nonexistent-account").or.onPosts("mtyszczak").subscribe({ next(data) { data.posts["nonexistent-account"]?.forEach(() => { monitoredAccountPosts++; @@ -158,7 +158,7 @@ test.describe("WorkerBee Individual Filter Verification", () => { }, complete: () => resolve({ monitoredAccountPosts, otherAccountPosts }) }); - }); + }, 96549390, 96549415); // Should NOT detect posts from monitored account, but should detect from other account expect(result.monitoredAccountPosts).toBe(0); @@ -171,7 +171,7 @@ test.describe("WorkerBee Individual Filter Verification", () => { try { // Test with no accounts (edge case) - bot.providePastOperations(96549390, 96549415).onPosts().subscribe({ + bot.onPosts().subscribe({ next(_data) { dataReceived = true; console.log("Data received for empty account list"); @@ -185,7 +185,7 @@ test.describe("WorkerBee Individual Filter Verification", () => { } catch { reject(new Error("Unexpected error occurred")); } - }); + }, 96549390, 96549415); expect(result).toBeFalsy(); }); @@ -194,7 +194,7 @@ test.describe("WorkerBee Individual Filter Verification", () => { const result = await createWorkerBeeTest((bot, resolve, reject) => { const capturedComments: string[] = []; - bot.providePastOperations(96549690, 96549715).onComments("gtg", "moretea", "khantaimur").subscribe({ + (bot).onComments("gtg", "moretea", "khantaimur").subscribe({ next(data) { for (const author of ["gtg", "moretea", "khantaimur"]) data.comments[author]?.forEach(({ operation }) => { @@ -207,7 +207,7 @@ test.describe("WorkerBee Individual Filter Verification", () => { }, complete: () => resolve(capturedComments) }); - }); + }, 96549690, 96549715); expect(result).toEqual([ "Comment by moretea: re-leothreads-2xpn8nyzd", @@ -220,7 +220,7 @@ test.describe("WorkerBee Individual Filter Verification", () => { const result = await createWorkerBeeTest((bot, resolve, reject) => { const capturedComments: Array<{ author: string; blockNumber: number }> = []; - bot.providePastOperations(97634334, 97634348).onBlock().or.onComments("zayyar99", "beckyroyal").subscribe({ + (bot).onBlock().or.onComments("zayyar99", "beckyroyal").subscribe({ next(data) { for (const author of ["zayyar99", "beckyroyal"]) data.comments[author]?.forEach(({ operation }) => { @@ -236,7 +236,7 @@ test.describe("WorkerBee Individual Filter Verification", () => { }, complete: () => resolve(capturedComments) }); - }); + }, 97634334, 97634348); expect(result).toEqual([ { @@ -260,7 +260,7 @@ test.describe("WorkerBee Individual Filter Verification", () => { * Monitor an account known to create posts in this range for comments (should not trigger) * Also check for posts in the same range to verify account was active with posts */ - bot.providePastOperations(96549390, 96549415).onComments("mtyszczak").or.onPosts("mtyszczak").subscribe({ + (bot).onComments("mtyszczak").or.onPosts("mtyszczak").subscribe({ next(data) { // Count comments (should be 0) data.comments["mtyszczak"]?.forEach(() => { @@ -278,7 +278,7 @@ test.describe("WorkerBee Individual Filter Verification", () => { }, complete: () => resolve({ commentsDetected, postsDetected }) }); - }); + }, 96549390, 96549415); // Should detect posts but NOT comments expect(result.postsDetected).toBeGreaterThan(0); @@ -297,7 +297,7 @@ test.describe("WorkerBee Individual Filter Verification", () => { * Monitor multiple accounts for comments (should not trigger for post activity) * Also verify these accounts were active with posts */ - bot.providePastOperations(96549390, 96549415).onComments(...testAccounts).or.onPosts(...testAccounts).subscribe({ + (bot).onComments(...testAccounts).or.onPosts(...testAccounts).subscribe({ next(data) { testAccounts.forEach(account => { data.comments[account]?.forEach(() => { @@ -315,7 +315,7 @@ test.describe("WorkerBee Individual Filter Verification", () => { }, complete: () => resolve({ commentResults, postResults }) }); - }); + }, 96549390, 96549415); const totalPosts = Object.values(result.postResults).reduce((sum, count) => sum + count, 0); const totalComments = Object.values(result.commentResults).reduce((sum, count) => sum + count, 0); @@ -333,7 +333,7 @@ test.describe("WorkerBee Individual Filter Verification", () => { * Monitor for comments from a specific account that doesn't commented * Also verify other accounts were commenting in this range */ - bot.providePastOperations(96549690, 96549715).onComments("nonexistent-commenter").or.onComments("gtg").subscribe({ + (bot).onComments("nonexistent-commenter").or.onComments("gtg").subscribe({ next(data) { data.comments["nonexistent-commenter"]?.forEach(() => { monitoredAccountComments++; @@ -349,7 +349,7 @@ test.describe("WorkerBee Individual Filter Verification", () => { }, complete: () => resolve({ monitoredAccountComments, otherAccountComments }) }); - }); + }, 96549690, 96549715); // Should NOT detect comments from monitored account, but should detect from other account expect(result.monitoredAccountComments).toBe(0); @@ -362,7 +362,7 @@ test.describe("WorkerBee Individual Filter Verification", () => { try { // Test with no accounts (edge case) - bot.providePastOperations(96549690, 96549715).onComments().subscribe({ + (bot).onComments().subscribe({ next(_data) { dataReceived = true; console.log("Data received for empty comment account list"); @@ -376,7 +376,7 @@ test.describe("WorkerBee Individual Filter Verification", () => { } catch { reject(new Error("Unexpected error occurred")); } - }); + }, 96549690, 96549715); expect(result).toBeFalsy(); }); @@ -385,8 +385,7 @@ test.describe("WorkerBee Individual Filter Verification", () => { const result = await createWorkerBeeTest((bot, resolve, reject) => { const capturedPosts: string[] = []; - bot - .providePastOperations(96549390, 96549415) + (bot) .onPosts("mtyszczak", "author2", "author3") .or.onComments("secret-art", "author2", "author3") .subscribe({ @@ -407,7 +406,7 @@ test.describe("WorkerBee Individual Filter Verification", () => { }, complete: () => resolve(capturedPosts) }); - }); + }, 96549390, 96549415); expect(result).toEqual([ "Comment by secret-art: re-jfang003-sxg1lb", @@ -422,7 +421,7 @@ test.describe("WorkerBee Individual Filter Verification", () => { const result = await createWorkerBeeTest((bot, resolve, reject) => { const capturedVotes: string[] = []; - bot.providePastOperations(96549390, 96549415).onVotes("dhedge", "winanda").subscribe({ + (bot).onVotes("dhedge", "winanda").subscribe({ next(data) { for (const voter of ["dhedge", "winanda"]) data.votes[voter]?.forEach(({ operation }) => { @@ -435,7 +434,7 @@ test.describe("WorkerBee Individual Filter Verification", () => { }, complete: () => resolve(capturedVotes) }); - }); + }, 96549390, 96549415); expect(result).toEqual([ "Vote by winanda on xlety/is-it-really-worth-creating", @@ -448,7 +447,7 @@ test.describe("WorkerBee Individual Filter Verification", () => { const result = await createWorkerBeeTest((bot, resolve, reject) => { const capturedVotes: Array<{ voter: string; blockNumber: number }> = []; - bot.providePastOperations(96549390, 96549404).onBlock().or.onVotes("noctury", "the-burn").subscribe({ + (bot).onBlock().or.onVotes("noctury", "the-burn").subscribe({ next(data) { for (const voter of ["noctury", "the-burn"]) data.votes[voter]?.forEach(({ operation }) => { @@ -464,7 +463,7 @@ test.describe("WorkerBee Individual Filter Verification", () => { }, complete: () => resolve(capturedVotes) }); - }); + }, 96549390, 96549404); expect(result).toEqual([ { @@ -487,7 +486,7 @@ test.describe("WorkerBee Individual Filter Verification", () => { * Monitor an account known to create posts/comments but does not vote in this range * Also Check for posts to verify account was active */ - bot.providePastOperations(96549390, 96549415).onVotes("mtyszczak").or.onPosts("mtyszczak").or.onComments("mtyszczak").subscribe({ + (bot).onVotes("mtyszczak").or.onPosts("mtyszczak").or.onComments("mtyszczak").subscribe({ next(data) { // Count votes (should be 0) data.votes["mtyszczak"]?.forEach(() => { @@ -509,7 +508,7 @@ test.describe("WorkerBee Individual Filter Verification", () => { }, complete: () => resolve({ votesDetected, commentOperationsDetected }) }); - }); + }, 96549390, 96549415); // Should detect posts/comments but no votes from this account in this range expect(result.commentOperationsDetected).toBeGreaterThan(0); @@ -525,7 +524,7 @@ test.describe("WorkerBee Individual Filter Verification", () => { * Monitor for votes from a specific account that doesn't vote much * Also Verify other accounts were voting in this range */ - bot.providePastOperations(96549390, 96549415).onVotes("nonexistent-voter").or.onVotes("noctury").subscribe({ + (bot).onVotes("nonexistent-voter").or.onVotes("noctury").subscribe({ next(data) { data.votes["nonexistent-voter"]?.forEach(() => { monitoredAccountVotes++; @@ -541,7 +540,7 @@ test.describe("WorkerBee Individual Filter Verification", () => { }, complete: () => resolve({ monitoredAccountVotes, otherAccountVotes }) }); - }); + }, 96549390, 96549415); // Should NOT detect votes from monitored account, but should detect from other account expect(result.monitoredAccountVotes).toBe(0); @@ -554,7 +553,7 @@ test.describe("WorkerBee Individual Filter Verification", () => { try { // Test with no accounts (edge case) - bot.providePastOperations(96549390, 96549415).onVotes().subscribe({ + (bot).onVotes().subscribe({ next(_data) { dataReceived = true; console.log("Data received for empty votes account list"); @@ -568,7 +567,7 @@ test.describe("WorkerBee Individual Filter Verification", () => { } catch { reject(new Error("Unexpected error occurred")); } - }); + }, 96549390, 96549415); expect(result).toBeFalsy(); }); @@ -577,7 +576,7 @@ test.describe("WorkerBee Individual Filter Verification", () => { const result = await createWorkerBeeTest((bot, resolve, reject) => { const capturedPosts: string[] = []; - bot.providePastOperations(96549390, 96549415) + (bot) .onPosts("mtyszczak").or.or.or.or.or.onComments("secret-art") .subscribe({ next(data) { @@ -598,7 +597,7 @@ test.describe("WorkerBee Individual Filter Verification", () => { }, complete: () => resolve(capturedPosts) }); - }); + }, 96549390, 96549415); expect(result).toEqual([ "Comment by secret-art: re-jfang003-sxg1lb", diff --git a/__tests__/detailed/mock_realistic_scenarios_live_data.ts b/__tests__/detailed/mock_realistic_scenarios_live_data.ts index faafb0d..ceac108 100644 --- a/__tests__/detailed/mock_realistic_scenarios_live_data.ts +++ b/__tests__/detailed/mock_realistic_scenarios_live_data.ts @@ -34,7 +34,7 @@ test.describe("Realistic Scenarios with Live Data", () => { let post: { text: string, accountName: string, manabar: string } | undefined; let comment: { text: string, accountName: string, manabar: string } | undefined; - bot.observe.onPosts("gtg") + bot.onPosts("gtg") .or.onComments("gtg") .or.onVotes("gtg") .provideAccounts("gtg") @@ -98,7 +98,7 @@ test.describe("Realistic Scenarios with Live Data", () => { const result = await createMockWorkerBeeTest((bot, resolve, reject) => { let manabarData: string | undefined; - bot.observe.onAccountsBalanceChange(false, "gtg") + bot.onAccountsBalanceChange(false, "gtg") .or.onAccountsMetadataChange("gtg") .or.onAccountsManabarPercent(0, 100, "gtg") .provideAccounts("gtg") @@ -139,7 +139,7 @@ test.describe("Realistic Scenarios with Live Data", () => { test("3.3 - Should be able to create market alert system", async ({ createMockWorkerBeeTest }) => { const result = await createMockWorkerBeeTest((bot, resolve, reject) => { - bot.observe.onFeedPriceChange(95) + bot.onFeedPriceChange(95) .or.onFeedPriceNoChange(1) .or.onWitnessesMissedBlocks(5, "gtg") .provideFeedPriceData() @@ -167,11 +167,11 @@ test.describe("Realistic Scenarios with Live Data", () => { }); test("3.5 - Should be able to create investment portfolio monitor", async ({ createMockWorkerBeeTest }) => { - const result = await createMockWorkerBeeTest((bot, resolve, reject) => { + const result = await createMockWorkerBeeTest((bot, resolve, reject, chain) => { const marketOperations: string[] = []; - bot.observe.onAccountsBalanceChange(true, "gtg", "blocktrades") - .or.onWhaleAlert(bot.chain!.hiveCoins(1000)) + bot.onAccountsBalanceChange(true, "gtg", "blocktrades") + .or.onWhaleAlert(chain!.hiveCoins(1000)) .or.onExchangeTransfer() .provideAccounts("gtg", "blocktrades") .subscribe({ @@ -206,7 +206,7 @@ test.describe("Realistic Scenarios with Live Data", () => { const result = await createMockWorkerBeeTest((bot, resolve, reject) => { const contentOperations: string[] = []; - bot.observe.onPosts("mtyszczak") + bot.onPosts("mtyszczak") .or.onPosts("fwaszkiewicz") .or.onReblog("thebeedevs") .subscribe({ @@ -244,7 +244,7 @@ test.describe("Realistic Scenarios with Live Data", () => { const result = await createMockWorkerBeeTest((bot, resolve, reject) => { const content: string[] = []; - bot.observe.onAccountsManabarPercent(/* UPVOTE */ 0, 90, "gtg") + bot.onAccountsManabarPercent(/* UPVOTE */ 0, 90, "gtg") .or.onPosts("fwaszkiewicz") .or.onComments("fwaszkiewicz") .provideManabarData(/* UPVOTE */ 0, "gtg") @@ -275,7 +275,7 @@ test.describe("Realistic Scenarios with Live Data", () => { const result = await createMockWorkerBeeTest((bot, resolve, reject) => { const content: string[] = []; - bot.observe.onBlock() + bot.onBlock() .provideAccounts("gtg") .provideRcAccounts("gtg") .provideManabarData(/* RC */2, "gtg") @@ -313,7 +313,7 @@ test.describe("Realistic Scenarios with Live Data", () => { const result = await createMockWorkerBeeTest((bot, resolve, reject) => { const content: string[] = []; - bot.observe.onBlock() + bot.onBlock() .provideAccounts("gtg", "blocktrades", "thebeedevs") .provideManabarData(/* RC */2, "gtg", "blocktrades", "thebeedevs") .provideWitnesses("gtg", "blocktrades") @@ -356,7 +356,7 @@ test.describe("Realistic Scenarios with Live Data", () => { const result = await createMockWorkerBeeTest((bot, resolve, reject) => { const content: string[] = []; - bot.observe.onBlock() + bot.onBlock() .or.onInternalMarketOperation() .or.onExchangeTransfer() .provideBlockData() @@ -393,7 +393,7 @@ test.describe("Realistic Scenarios with Live Data", () => { const result = await createMockWorkerBeeTest((bot, resolve, reject) => { const content: string[] = []; - bot.observe.onFollow("gtg") + bot.onFollow("gtg") .or.onFollow("blocktrades") .or.onReblog("gtg") .or.onMention("gtg") @@ -440,7 +440,7 @@ test.describe("Realistic Scenarios with Live Data", () => { const result = await createMockWorkerBeeTest((bot, resolve, reject) => { const content: string[] = []; - bot.observe.onPosts("gtg") + bot.onPosts("gtg") .or.onComments("gtg") .or.onVotes("gtg") .or.onReblog("gtg") diff --git a/__tests__/detailed/realistic_scenarios.ts b/__tests__/detailed/realistic_scenarios.ts index 0e860fe..42c711b 100644 --- a/__tests__/detailed/realistic_scenarios.ts +++ b/__tests__/detailed/realistic_scenarios.ts @@ -8,7 +8,7 @@ test.describe("Bot Realistic Scenarios", () => { const result = await createWorkerBeeTest((bot, resolve, reject) => { const content: string[] = []; - bot.providePastOperations(96549390, 96549415).onPosts("mtyszczak").or.onPosts("nickdongsik").or.onComments("brando28").subscribe({ + bot.onPosts("mtyszczak").or.onPosts("nickdongsik").or.onComments("brando28").subscribe({ next(data) { for (const author in data.posts) data.posts[author].forEach(({ operation }) => content.push(`${operation.author} - ${operation.permlink}`)); @@ -22,7 +22,7 @@ test.describe("Bot Realistic Scenarios", () => { }, complete: () => resolve(content) }); - }, true); + }, 96549390, 96549415, true); expect(result).toEqual([ "brando28 - re-bitcoinman-ovjhawi6", @@ -35,7 +35,7 @@ test.describe("Bot Realistic Scenarios", () => { const result = await createWorkerBeeTest((bot, resolve, reject) => { const content: string[] = []; - bot.providePastOperations(97146285, 97146300).onVotes("e-sport-gamer").or.onFollow("fwaszkiewicz").or.onReblog("maxinpower").subscribe({ + bot.onVotes("e-sport-gamer").or.onFollow("fwaszkiewicz").or.onReblog("maxinpower").subscribe({ next(data) { for (const author in data.votes) data.votes[author].forEach(({ operation }) => content.push(`Vote: ${operation.voter} - ${operation.permlink}`)); @@ -52,7 +52,7 @@ test.describe("Bot Realistic Scenarios", () => { }, complete: () => resolve(content) }); - }, true); + }, 97146285, 97146300, true); expect(result).toEqual([ "Vote: e-sport-gamer - city-pingeons", @@ -63,12 +63,11 @@ test.describe("Bot Realistic Scenarios", () => { }); test("1.3 - Should be able to create financial activity monitor", async({ createWorkerBeeTest }) => { - const result = await createWorkerBeeTest((bot, resolve, reject) => { + const result = await createWorkerBeeTest((bot, resolve, reject, chain) => { const content: string[] = []; bot - .providePastOperations(97347575, 97347585) - .onWhaleAlert(bot.chain!.hiveCoins(50)) + .onWhaleAlert(chain!.hiveCoins(50)) .or.onInternalMarketOperation() .or.onExchangeTransfer() .subscribe({ @@ -91,7 +90,7 @@ test.describe("Bot Realistic Scenarios", () => { }, complete: () => resolve(content) }); - }, true); + }, 97347575, 97347585, true); expect(result).toEqual([ "Internal Market Operation: honeybot - 243293707", @@ -105,7 +104,7 @@ test.describe("Bot Realistic Scenarios", () => { const result = await createWorkerBeeTest((bot, resolve, reject) => { const content: string[] = []; - bot.providePastOperations(97639665, 97639695).onMention("thebeedevs").or.onPosts("thebeedevs").or.onReblog("thebeedevs").subscribe({ + bot.onMention("thebeedevs").or.onPosts("thebeedevs").or.onReblog("thebeedevs").subscribe({ next(data) { data.posts.thebeedevs?.forEach(({ operation }) => { content.push(`Post: ${operation.author} - ${operation.permlink}`); @@ -125,7 +124,7 @@ test.describe("Bot Realistic Scenarios", () => { }, complete: () => resolve(content) }); - }, true); + }, 97639665, 97639695, true); expect(result).toEqual([ "Post: thebeedevs - hivesense-why-nothing-worked-at-first-and-what-we-did-about-it", @@ -139,7 +138,6 @@ test.describe("Bot Realistic Scenarios", () => { const content: string[] = []; bot - .providePastOperations(97664614, 97664618) .onCustomOperation("follow") .or.onCustomOperation("reblog") .or.onNewAccount().subscribe({ @@ -162,7 +160,7 @@ test.describe("Bot Realistic Scenarios", () => { }, complete: () => resolve(content) }); - }, true); + }, 97664614, 97664618, true); expect(result).toEqual([ "Follow: [\"reblog\",{\"account\":\"cribbio\",\"author\":\"donasycafe\",\"permlink\":\"feliz-4o-aniversario-mi-historia\"}]", @@ -177,7 +175,6 @@ test.describe("Bot Realistic Scenarios", () => { const content: string[] = []; bot - .providePastOperations(97547200, 97547250) .onPosts("thebeedevs") .or.onComments("thebeedevs") .or.onMention("thebeedevs") @@ -211,7 +208,7 @@ test.describe("Bot Realistic Scenarios", () => { }, complete: () => resolve(content) }); - }, true); + }, 97547200, 97547250, true); expect(result).toEqual([ "Post: thebeedevs - meet-workerbee-the-easy-way-to-build-smart-blockchain-bots", @@ -222,12 +219,11 @@ test.describe("Bot Realistic Scenarios", () => { }); test("1.7 - Should be able to create market movement detector", async({ createWorkerBeeTest }) => { - const result = await createWorkerBeeTest((bot, resolve, reject) => { + const result = await createWorkerBeeTest((bot, resolve, reject, chain) => { const content: string[] = []; bot - .providePastOperations(97347545, 97347555) - .or.onWhaleAlert(bot.chain!.hiveCoins(10000)) + .or.onWhaleAlert(chain!.hiveCoins(10000)) .or.onInternalMarketOperation() .or.onExchangeTransfer() .subscribe({ @@ -250,7 +246,7 @@ test.describe("Bot Realistic Scenarios", () => { }, complete: () => resolve(content) }); - }, true); + }, 97347545, 97347555, true); expect(result).toEqual([ "Whale Alert: huobi-pro -> huobi-withdrawal - 1598290", @@ -265,7 +261,6 @@ test.describe("Bot Realistic Scenarios", () => { const content: string[] = []; bot - .providePastOperations(97547200, 97547250) .onVotes("thebeedevs") .or.onPosts("thebeedevs") .subscribe({ @@ -284,7 +279,7 @@ test.describe("Bot Realistic Scenarios", () => { }, complete: () => resolve(content) }); - }, true); + }, 97547200, 97547250, true); expect(result).toEqual([ "Post: thebeedevs - meet-workerbee-the-easy-way-to-build-smart-blockchain-bots", @@ -293,12 +288,11 @@ test.describe("Bot Realistic Scenarios", () => { }); test("2.2 - Should be able to create market trend analyzer", async({ createWorkerBeeTest }) => { - const result = await createWorkerBeeTest((bot, resolve, reject) => { + const result = await createWorkerBeeTest((bot, resolve, reject, chain) => { const content: string[] = []; bot - .providePastOperations(97347545, 97347555) - .onWhaleAlert(bot.chain!.hiveCoins(10000)) + .onWhaleAlert(chain!.hiveCoins(10000)) .or.onInternalMarketOperation() .subscribe({ next(data) { @@ -316,7 +310,7 @@ test.describe("Bot Realistic Scenarios", () => { }, complete: () => resolve(content) }); - }, true); + }, 97347545, 97347555, true); expect(result).toEqual([ "Whale Alert: huobi-pro -> huobi-withdrawal - 1598290", @@ -330,7 +324,6 @@ test.describe("Bot Realistic Scenarios", () => { const content: string[] = []; bot - .providePastOperations(97664610, 97664620) .onNewAccount() .or.onFollow("thebeedevs") .or.onCustomOperation("follow") @@ -354,7 +347,7 @@ test.describe("Bot Realistic Scenarios", () => { }, complete: () => resolve(content) }); - }, true); + }, 97664610, 97664620, true); expect(result).toEqual([ "Custom Follow: [\"follow\",{\"follower\":\"dehai\",\"following\":\"rubenjr\",\"what\":[\"blog\"]}]", @@ -371,7 +364,6 @@ test.describe("Bot Realistic Scenarios", () => { const content: string[] = []; bot - .providePastOperations(97547200, 97547250) .onPosts("thebeedevs") .or.onComments("thebeedevs") .or.onVotes("thebeedevs") @@ -395,7 +387,7 @@ test.describe("Bot Realistic Scenarios", () => { }, complete: () => resolve(content) }); - }, true); + }, 97547200, 97547250, true); expect(result).toEqual([ "Post: thebeedevs - meet-workerbee-the-easy-way-to-build-smart-blockchain-bots", @@ -404,12 +396,11 @@ test.describe("Bot Realistic Scenarios", () => { }); test("2.5 - Should be able to create economic activity tracker", async({ createWorkerBeeTest }) => { - const result = await createWorkerBeeTest((bot, resolve, reject) => { + const result = await createWorkerBeeTest((bot, resolve, reject, chain) => { const content: string[] = []; bot - .providePastOperations(97347575, 97347585) - .onWhaleAlert(bot.chain!.hiveCoins(1000)) + .onWhaleAlert(chain!.hiveCoins(1000)) .or.onExchangeTransfer() .or.onInternalMarketOperation() .subscribe({ @@ -432,7 +423,7 @@ test.describe("Bot Realistic Scenarios", () => { }, complete: () => resolve(content) }); - }, true); + }, 97347575, 97347585, true); expect(result).toEqual([ "Whale: honey-swap -> hive-engine - 403", @@ -449,7 +440,6 @@ test.describe("Bot Realistic Scenarios", () => { const content: string[] = []; bot - .providePastOperations(97547200, 97547250) .onPosts("thebeedevs") .or.onVotes("thebeedevs") .or.onFollow("thebeedevs") @@ -478,7 +468,7 @@ test.describe("Bot Realistic Scenarios", () => { }, complete: () => resolve(content) }); - }, true); + }, 97547200, 97547250, true); expect(result).toEqual([ "Post: thebeedevs - meet-workerbee-the-easy-way-to-build-smart-blockchain-bots", -- GitLab From 8b3ae7dbabb332cfceb58493342f4ed84d211871 Mon Sep 17 00:00:00 2001 From: fwaszkiewicz Date: Tue, 5 Aug 2025 14:05:04 +0200 Subject: [PATCH 11/11] Replace Long with bigint according to wax changes --- __tests__/assets/jest-helper.ts | 4 +++- __tests__/detailed/bot_events.ts | 2 +- .../mock_realistic_scenarios_live_data.ts | 18 ++++++++++++------ package.json | 3 +-- pnpm-lock.yaml | 19 +++++-------------- .../classifiers/account-classifier.ts | 5 ++--- .../content-metadata-classifier.ts | 5 ++--- .../collectors/common/manabar-collector.ts | 6 +++--- .../collectors/jsonrpc/account-collector.ts | 7 +++---- .../jsonrpc/content-metadata-collector.ts | 9 ++++----- .../jsonrpc/rc-account-collector.ts | 5 ++--- 11 files changed, 38 insertions(+), 45 deletions(-) diff --git a/__tests__/assets/jest-helper.ts b/__tests__/assets/jest-helper.ts index 3b12806..94d17d3 100644 --- a/__tests__/assets/jest-helper.ts +++ b/__tests__/assets/jest-helper.ts @@ -78,7 +78,9 @@ const envTestFor = ( }, { args, globalFunction: globalFunction.name, webFn: fn.toString(), isMockEnv: isMockEnvironment }); if(typeof nodeData === "object") // Remove prototype data from the node result to match webData - nodeData = JSON.parse(JSON.stringify(nodeData)); + nodeData = JSON.parse(JSON.stringify(nodeData, (_key, value) => + typeof value === "bigint" ? value.toString() : value + )); if(checkEqual) expect(webData as any).toStrictEqual(nodeData); diff --git a/__tests__/detailed/bot_events.ts b/__tests__/detailed/bot_events.ts index c2b01e1..db1da00 100644 --- a/__tests__/detailed/bot_events.ts +++ b/__tests__/detailed/bot_events.ts @@ -259,7 +259,7 @@ test.describe("WorkerBee Bot events test", () => { for(const account in data.commentsMetadata) for(const permlink in data.commentsMetadata[account]) { - rshares = data.commentsMetadata[account][permlink].netRshares.toNumber(); + rshares = Number(data.commentsMetadata[account][permlink].netRshares); console.info(`Retrieved comment payout of @${account}: ${rshares} rshares for ${permlink}`); } diff --git a/__tests__/detailed/mock_realistic_scenarios_live_data.ts b/__tests__/detailed/mock_realistic_scenarios_live_data.ts index ceac108..6bf5d01 100644 --- a/__tests__/detailed/mock_realistic_scenarios_live_data.ts +++ b/__tests__/detailed/mock_realistic_scenarios_live_data.ts @@ -45,7 +45,9 @@ test.describe("Realistic Scenarios with Live Data", () => { post = { text: `Post: ${operation.author} - ${operation.title}`, accountName: JSON.stringify(data.accounts.gtg?.name), - manabar: JSON.stringify(data.manabarData.gtg?.[2]?.currentMana) + manabar: JSON.stringify(data.manabarData.gtg?.[2]?.currentMana, (_key, value) => + typeof value === "bigint" ? value.toString() : value + ) }; }); @@ -53,7 +55,9 @@ test.describe("Realistic Scenarios with Live Data", () => { comment = { text: `Comment: ${operation.author} -> ${operation.parent_author}`, accountName: JSON.stringify(data.accounts.gtg?.name), - manabar: JSON.stringify(data.manabarData.gtg?.[2]?.currentMana) + manabar: JSON.stringify(data.manabarData.gtg?.[2]?.currentMana, (_key, value) => + typeof value === "bigint" ? value.toString() : value + ) }; }); @@ -61,7 +65,9 @@ test.describe("Realistic Scenarios with Live Data", () => { vote = { text: `Vote: ${operation.voter} - ${operation.author}`, accountName: JSON.stringify(data.accounts.gtg?.name), - manabar: JSON.stringify(data.manabarData.gtg?.[2]?.currentMana) + manabar: JSON.stringify(data.manabarData.gtg?.[2]?.currentMana, (_key, value) => + typeof value === "bigint" ? value.toString() : value + ) }; }); @@ -78,17 +84,17 @@ test.describe("Realistic Scenarios with Live Data", () => { expect(result).toEqual([ { accountName: "\"gtg\"", - manabar: "{\"low\":2125861720,\"high\":501074,\"unsigned\":true}", + manabar: "\"2152098568737624\"", text: "Post: gtg - SkyTeam Airline Alliance - Official partner of HiveFest", }, { accountName: "\"gtg\"", - manabar: "{\"low\":1965705338,\"high\":37491,\"unsigned\":true}", + manabar: "\"161024584599674\"", text: "Vote: gtg - hbd.funder", }, { accountName: "\"gtg\"", - manabar: "{\"low\":2125861720,\"high\":501074,\"unsigned\":true}", + manabar: "\"2152098568737624\"", text: "Comment: gtg -> purepinay", } ]); diff --git a/package.json b/package.json index ac0d689..258d6da 100644 --- a/package.json +++ b/package.json @@ -85,8 +85,7 @@ "typescript": "catalog:typescript-toolset" }, "dependencies": { - "@hiveio/wax": "1.27.6-rc10-stable.250718075612", - "long": "^5.3.1" + "@hiveio/wax": "1.27.6-rc10-stable.250804212246" }, "repository": { "type": "git", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index edf0430..23d2b21 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -72,11 +72,8 @@ importers: .: dependencies: '@hiveio/wax': - specifier: 1.27.6-rc10-stable.250718075612 - version: 1.27.6-rc10-stable.250718075612 - long: - specifier: ^5.3.1 - version: 5.3.1 + specifier: 1.27.6-rc10-stable.250804212246 + version: 1.27.6-rc10-stable.250804212246 devDependencies: '@eslint/compat': specifier: ^1.2.7 @@ -408,8 +405,8 @@ packages: resolution: {integrity: sha1-0v2gSYFhN5MLQzBHIYikUyksu/k=, tarball: https://gitlab.syncad.com/api/v4/projects/198/packages/npm/@hiveio/beekeeper/-/@hiveio/beekeeper-1.27.11.tgz} engines: {node: ^20.11 || >= 21.2} - '@hiveio/wax@1.27.6-rc10-stable.250718075612': - resolution: {integrity: sha1-TYKUMQ158pF6HL+KoE1ze7dYQ/M=, tarball: https://gitlab.syncad.com/api/v4/projects/419/packages/npm/@hiveio/wax/-/@hiveio/wax-1.27.6-rc10-stable.250718075612.tgz} + '@hiveio/wax@1.27.6-rc10-stable.250804212246': + resolution: {integrity: sha1-qZYJ4ot0Lgy3C0fbeS1WFoxmFEY=, tarball: https://gitlab.syncad.com/api/v4/projects/419/packages/npm/@hiveio/wax/-/@hiveio/wax-1.27.6-rc10-stable.250804212246.tgz} engines: {node: ^20.11 || >= 21.2} '@humanfs/core@0.19.1': @@ -2020,9 +2017,6 @@ packages: resolution: {integrity: sha512-niTvB4gqvtof056rRIrTZvjNYE4rCUzO6X/X+kYjd7WFxXeJ0NwEFnRxX6ehkvv3jTwrXnNdtAak5XYZuIyPFw==} engines: {node: '>=18'} - long@5.3.1: - resolution: {integrity: sha512-ka87Jz3gcx/I7Hal94xaN2tZEOPoUOEVftkQqZx2EeQRN7LGdfLlI3FvZ+7WDplm+vK2Urx9ULrvSowtdCieng==} - lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} @@ -3208,10 +3202,9 @@ snapshots: '@hiveio/beekeeper@1.27.11': {} - '@hiveio/wax@1.27.6-rc10-stable.250718075612': + '@hiveio/wax@1.27.6-rc10-stable.250804212246': dependencies: events: 3.3.0 - long: 5.3.1 '@humanfs/core@0.19.1': {} @@ -5152,8 +5145,6 @@ snapshots: strip-ansi: 7.1.0 wrap-ansi: 9.0.0 - long@5.3.1: {} - lru-cache@10.4.3: {} lru-cache@7.18.3: {} diff --git a/src/chain-observers/classifiers/account-classifier.ts b/src/chain-observers/classifiers/account-classifier.ts index 1154365..6780678 100644 --- a/src/chain-observers/classifiers/account-classifier.ts +++ b/src/chain-observers/classifiers/account-classifier.ts @@ -1,5 +1,4 @@ import type { asset } from "@hiveio/wax"; -import Long from "long"; import { CollectorClassifierBase, TRegisterEvaluationContext } from "./collector-classifier-base"; export interface IHiveAssetDetailedBalance { @@ -9,12 +8,12 @@ export interface IHiveAssetDetailedBalance { } export interface IManabarData { - currentMana: Long; + currentMana: bigint; lastUpdateTime: Date; }; export interface IMaxManabarData extends IManabarData { - max: Long; + max: bigint; } export interface IHiveAssetWithSavingsDetailedBalance extends IHiveAssetDetailedBalance { diff --git a/src/chain-observers/classifiers/content-metadata-classifier.ts b/src/chain-observers/classifiers/content-metadata-classifier.ts index 136501b..4ff5fbd 100644 --- a/src/chain-observers/classifiers/content-metadata-classifier.ts +++ b/src/chain-observers/classifiers/content-metadata-classifier.ts @@ -1,5 +1,4 @@ import type { asset, comment, TAccountName } from "@hiveio/wax"; -import Long from "long"; import { CollectorClassifierBase } from "./collector-classifier-base"; export interface IHiveContentMetadata { @@ -50,7 +49,7 @@ export interface IHiveContentMetadata { * relative to other content paying out at the same time. * @example 150255792948762 */ - netRshares: Long; + netRshares: bigint; /** * The total number of individual upvotes this content has received. @@ -114,7 +113,7 @@ export interface IHiveContentMetadata { * This will be 0 if the post hasn't paid out yet. * @example 0 */ - authorRewards: Long; + authorRewards: bigint; } export type TContentMetadataAuthorData = Record; diff --git a/src/chain-observers/collectors/common/manabar-collector.ts b/src/chain-observers/collectors/common/manabar-collector.ts index ed3fa10..b0ca5cb 100644 --- a/src/chain-observers/collectors/common/manabar-collector.ts +++ b/src/chain-observers/collectors/common/manabar-collector.ts @@ -134,10 +134,10 @@ export class ManabarCollector extends CollectorBase { let max = accounts.accounts[account].upvoteManabar.max; - if(max.divide(ONE_HUNDRED_PERCENT).greaterThan(ONE_HUNDRED_PERCENT)) - max = max.divide(ONE_HUNDRED_PERCENT).multiply(dgpo.downvotePoolPercent); + if((max / BigInt(ONE_HUNDRED_PERCENT)) > BigInt(ONE_HUNDRED_PERCENT)) + max = (max / BigInt(ONE_HUNDRED_PERCENT)) * BigInt(dgpo.downvotePoolPercent); else - max = max.multiply(dgpo.downvotePoolPercent).divide(ONE_HUNDRED_PERCENT); + max = max * BigInt(dgpo.downvotePoolPercent) / BigInt(ONE_HUNDRED_PERCENT); const calculatedManabarData = this.worker.chain!.calculateCurrentManabarValue( time, diff --git a/src/chain-observers/collectors/jsonrpc/account-collector.ts b/src/chain-observers/collectors/jsonrpc/account-collector.ts index 246ad5c..c7168c1 100644 --- a/src/chain-observers/collectors/jsonrpc/account-collector.ts +++ b/src/chain-observers/collectors/jsonrpc/account-collector.ts @@ -1,4 +1,3 @@ -import Long from "long"; import { AccountClassifier } from "../../classifiers"; import { IAccount } from "../../classifiers/account-classifier"; import { TCollectorEvaluationContext } from "../../factories/data-evaluation-context"; @@ -51,12 +50,12 @@ export class AccountCollector extends CollectorBase { accounts[account.name] = { name: account.name, upvoteManabar: { - currentMana: Long.fromValue(account.voting_manabar.current_mana), - max: Long.fromValue(account.post_voting_power.amount), + currentMana: BigInt(account.voting_manabar.current_mana), + max: BigInt(account.post_voting_power.amount), lastUpdateTime: new Date(account.voting_manabar.last_update_time * 1000) }, downvoteManabar: { - currentMana: Long.fromValue(account.downvote_manabar.current_mana), + currentMana: BigInt(account.downvote_manabar.current_mana), lastUpdateTime: new Date(account.downvote_manabar.last_update_time * 1000) }, recoveryAccount: account.recovery_account, diff --git a/src/chain-observers/collectors/jsonrpc/content-metadata-collector.ts b/src/chain-observers/collectors/jsonrpc/content-metadata-collector.ts index 9327f32..54ac598 100644 --- a/src/chain-observers/collectors/jsonrpc/content-metadata-collector.ts +++ b/src/chain-observers/collectors/jsonrpc/content-metadata-collector.ts @@ -1,5 +1,4 @@ import { TAccountName, dateFromString } from "@hiveio/wax"; -import Long from "long"; import { WorkerBeeError } from "../../../errors"; import { BucketAggregateQueue } from "../../../types/queue"; import { nullDate } from "../../../utils/time"; @@ -63,9 +62,9 @@ export class ContentMetadataCollector extends CollectorBase { rcAccounts[rcAccount.account] = { name: rcAccount.account, rcManabar: { - currentMana: Long.fromValue(rcAccount.rc_manabar.current_mana), - max: Long.fromValue(rcAccount.max_rc), + currentMana: BigInt(rcAccount.rc_manabar.current_mana), + max: BigInt(rcAccount.max_rc), lastUpdateTime: new Date(rcAccount.rc_manabar.last_update_time * 1000) } }; -- GitLab