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 0000000000000000000000000000000000000000..3b8918a98688340a1d83bfd988673a4f3871e45f
--- /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  \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  \n\n## ๐ Check Out the Components!\n\n### Witness\n\n```html\n\n```\n\n  \n\n### Post\n\n```html\n\n```\n\n  \n\n### Comments\n\n```html\n\n```\n\n  \n\n### Posts by Tag\n\n```html\n\n```\n\n  \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  \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  \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  \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\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\n\nBut wait, there's more! Let's try breaking the signature in the same transaction... ๐คซ\n\n\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\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\n\nBut wait, there's more! Let's try breaking the signature in the same transaction... ๐คซ\n\n\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\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\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\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 0000000000000000000000000000000000000000..4f818eaf9dea275d704db366863e930984e81d66
--- /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 0000000000000000000000000000000000000000..1f4b557f8f6180bb2f01c0685dd672715d21066b
--- /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 0000000000000000000000000000000000000000..e049cf6a989c6f5323bddb42cdf0a0021577f5d1
--- /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 0000000000000000000000000000000000000000..d9a6ad199e86799def4e3b717ed4fa718f5cc964
--- /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 0000000000000000000000000000000000000000..74baa302aa0f37a9e20f495a037fa52d9ca700fe
--- /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
diff --git a/__tests__/assets/jest-helper.ts b/__tests__/assets/jest-helper.ts
index 37a4160d64d56d87f88a3f05fa712c9f72499ba8..94d17d3e3863eb2ecce5cd5fa5a4b4aa3ba6a02c 100644
--- a/__tests__/assets/jest-helper.ts
+++ b/__tests__/assets/jest-helper.ts
@@ -1,12 +1,22 @@
-import { Page, test as base, expect } from "@playwright/test";
+/* 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";
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
@@ -24,28 +34,53 @@ export interface IWorkerBeeTest {
};
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: QueenBee<{}>, resolve: (retVal?: T) => void, reject: (reason?: any) => void, chain?: IHiveChainInterface) => void,
dynamic?: boolean
) => Promise;
}
+export interface IWorkerBeeTest extends IWorkerBeeFixtureMethods, IWorkerBeeTestPlaywright {}
+
+interface IWorkerBeeWorker {
+ forEachWorker: void;
+}
+
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));
+ nodeData = JSON.parse(JSON.stringify(nodeData, (_key, value) =>
+ typeof value === "bigint" ? value.toString() : value
+ ));
if(checkEqual)
expect(webData as any).toStrictEqual(nodeData);
@@ -63,34 +98,74 @@ const envTestFor = (
const createWorkerBeeTest = async >(
envTestFor: IWorkerBeeTest["workerbeeTest"],
- callback: (bot: IWorkerBee, resolve: (retVal?: T) => void, reject: (reason?: any) => void) => void,
- dynamic: boolean = false
+ 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 = new WorkerBee({ chainOptions: { apiTimeout: 0 } });
+ return await testRunner(async ({ WorkerBee }, callbackStr, pastFrom, pastTo, isMock) => {
+ const bot = isMock
+ ? new WorkerBee({
+ chainOptions: {
+ apiEndpoint: "http://localhost:8000",
+ apiTimeout: 0
+ }
+ })
+ : new WorkerBee({ chainOptions: { apiTimeout: 0 } });
+
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({
+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));
},
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);
+ // TODO: Improve types to not cast to `any`
+ use((callback, dynamic) => createWorkerBeeTest(mockEnvTestFor, callback as any, undefined, undefined, dynamic, true));
}
});
diff --git a/__tests__/detailed/bot_events.ts b/__tests__/detailed/bot_events.ts
index 9a6267d1d22de7076051103c1597aa8c715574e7..db1da0024113abb76924ce71d80156c017830ab6 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();
@@ -276,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}`);
}
@@ -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 2b5ae25ffc7319a95a642c131fcfb37a7fc69e2c..3aa34196445f740498f4070276e1e2180ba612bd 100644
--- a/__tests__/detailed/bot_providers.ts
+++ b/__tests__/detailed/bot_providers.ts
@@ -1,28 +1,11 @@
/* 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");
+ const observer = bot.onBlock().provideWitnesses("gtg");
observer.subscribe({
next: (data) => {
@@ -35,7 +18,7 @@ test.describe("Bot Providers", () => {
},
complete: () => resolve()
});
- }, true);
+ }, undefined, undefined, true);
expect(result["gtg"]).toBeDefined();
expect(result["gtg"].owner).toBe("gtg");
@@ -45,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) => {
@@ -58,7 +41,7 @@ test.describe("Bot Providers", () => {
},
complete: () => resolve()
});
- }, true);
+ }, undefined, undefined, true);
expect(result["gtg"]).toBeDefined();
expect(result["gtg"].name).toBe("gtg");
@@ -67,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) => {
@@ -80,7 +63,7 @@ test.describe("Bot Providers", () => {
},
complete: () => resolve()
});
- }, true);
+ }, undefined, undefined, true);
expect(result).toHaveProperty("currentMedianHistory");
expect(result).toHaveProperty("currentMinHistory");
@@ -90,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) => {
@@ -103,7 +86,7 @@ test.describe("Bot Providers", () => {
},
complete: () => resolve()
});
- }, true);
+ }, undefined, undefined, true);
expect(result.number).not.toBeNaN();
expect(result).toHaveProperty("timestamp");
@@ -112,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) => {
@@ -125,7 +108,7 @@ test.describe("Bot Providers", () => {
},
complete: () => resolve()
});
- }, true);
+ }, undefined, undefined, true);
expect(result.number).not.toBeNaN();
expect(result).toHaveProperty("transactions");
@@ -134,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) => {
@@ -147,7 +130,7 @@ test.describe("Bot Providers", () => {
},
complete: () => resolve()
});
- }, true);
+ }, undefined, undefined, true);
expect(result["gtg"]).toBeDefined();
expect(result["gtg"].name).toBe("gtg");
@@ -155,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) => {
@@ -168,7 +151,7 @@ test.describe("Bot Providers", () => {
},
complete: () => resolve()
});
- }, true);
+ }, undefined, undefined, true);
expect(result["gtg"]).toBeDefined();
expect(result["gtg"][2].percent).toBeGreaterThanOrEqual(0);
@@ -176,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");
@@ -191,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");
@@ -201,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();
@@ -216,7 +199,7 @@ test.describe("Bot Providers", () => {
},
complete: () => resolve()
});
- }, true);
+ }, undefined, undefined, true);
expect(result.feedPrice).toHaveProperty("currentMedianHistory");
expect(result.feedPrice).toHaveProperty("priceHistory");
@@ -227,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
@@ -243,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");
@@ -256,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();
@@ -271,7 +254,7 @@ test.describe("Bot Providers", () => {
},
complete: () => resolve()
});
- }, true);
+ }, undefined, undefined, true);
expect(result.block.number).not.toBeNaN();
expect(result.block).toHaveProperty("transactions");
@@ -282,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")
@@ -312,7 +295,7 @@ test.describe("Bot Providers", () => {
},
complete: () => resolve()
});
- }, true);
+ }, undefined, undefined, true);
// Test witnesses provider
expect(result.witnesses["gtg"]).toBeDefined();
@@ -343,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");
@@ -359,7 +342,7 @@ test.describe("Bot Providers", () => {
},
complete: () => resolve()
});
- }, true);
+ }, undefined, undefined, true);
// Test witnesses for multiple accounts
expect(result.witnesses["gtg"]).toBeDefined();
@@ -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/__tests__/detailed/complex_scenarios_test_plan.md b/__tests__/detailed/complex_scenarios_test_plan.md
index 3fcaf41aca0fdea4d78d08bb4480207b23135d8b..cafcef7426d16427e48e1fb119241c84c0249736 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
diff --git a/__tests__/detailed/individual_filter_tests.ts b/__tests__/detailed/individual_filter_tests.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ad0ae148e1fd05e69092a992766200a4a7ed5a47
--- /dev/null
+++ b/__tests__/detailed/individual_filter_tests.ts
@@ -0,0 +1,610 @@
+/* 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.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)
+ });
+ }, 96549390, 96549415);
+
+ 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.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)
+ });
+ }, 97632050, 97632075);
+
+ 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.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 })
+ });
+ }, 96549690, 96549715);
+
+ // 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.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 })
+ });
+ }, 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);
+
+ 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.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 })
+ });
+ }, 96549390, 96549415);
+
+ // 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.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"));
+ }
+ }, 96549390, 96549415);
+
+ 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).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)
+ });
+ }, 96549690, 96549715);
+
+ 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).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)
+ });
+ }, 97634334, 97634348);
+
+ 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).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 })
+ });
+ }, 96549390, 96549415);
+
+ // 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).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 })
+ });
+ }, 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);
+
+ 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).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 })
+ });
+ }, 96549690, 96549715);
+
+ // 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).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"));
+ }
+ }, 96549690, 96549715);
+
+ 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)
+ .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)
+ });
+ }, 96549390, 96549415);
+
+ 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).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)
+ });
+ }, 96549390, 96549415);
+
+ 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).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)
+ });
+ }, 96549390, 96549404);
+
+ 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).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 })
+ });
+ }, 96549390, 96549415);
+
+ // 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).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 })
+ });
+ }, 96549390, 96549415);
+
+ // 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).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"));
+ }
+ }, 96549390, 96549415);
+
+ expect(result).toBeFalsy();
+ });
+
+ test("Multiple 'or' filters should work correctly", async({ createWorkerBeeTest }) => {
+ const result = await createWorkerBeeTest((bot, resolve, reject) => {
+ const capturedPosts: string[] = [];
+
+ (bot)
+ .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)
+ });
+ }, 96549390, 96549415);
+
+ 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__/detailed/mock_realistic_scenarios_live_data.ts b/__tests__/detailed/mock_realistic_scenarios_live_data.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6bf5d01694054e524455735cdb3ed81bc0d608e7
--- /dev/null
+++ b/__tests__/detailed/mock_realistic_scenarios_live_data.ts
@@ -0,0 +1,498 @@
+/* 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.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, (_key, value) =>
+ typeof value === "bigint" ? value.toString() : value
+ )
+ };
+ });
+
+ 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, (_key, value) =>
+ typeof value === "bigint" ? value.toString() : value
+ )
+ };
+ });
+
+ 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, (_key, value) =>
+ typeof value === "bigint" ? value.toString() : value
+ )
+ };
+ });
+
+ if (post !== undefined && vote !== undefined && comment !== undefined)
+ resolve([post, vote, comment]);
+ },
+ error: (err) => {
+ console.error(err);
+ reject(err);
+ }
+ });
+ });
+
+ expect(result).toEqual([
+ {
+ accountName: "\"gtg\"",
+ manabar: "\"2152098568737624\"",
+ text: "Post: gtg - SkyTeam Airline Alliance - Official partner of HiveFest",
+ },
+ {
+ accountName: "\"gtg\"",
+ manabar: "\"161024584599674\"",
+ text: "Vote: gtg - hbd.funder",
+ },
+ {
+ accountName: "\"gtg\"",
+ manabar: "\"2152098568737624\"",
+ 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.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.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, chain) => {
+ const marketOperations: string[] = [];
+
+ bot.onAccountsBalanceChange(true, "gtg", "blocktrades")
+ .or.onWhaleAlert(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.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.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.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.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.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.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.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/__tests__/detailed/realistic_scenarios.ts b/__tests__/detailed/realistic_scenarios.ts
new file mode 100644
index 0000000000000000000000000000000000000000..42c711b0f82eefff6b1ec7b71312fcb847f5d907
--- /dev/null
+++ b/__tests__/detailed/realistic_scenarios.ts
@@ -0,0 +1,479 @@
+/* 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.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)
+ });
+ }, 96549390, 96549415, 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.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)
+ });
+ }, 97146285, 97146300, 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, chain) => {
+ const content: string[] = [];
+
+ bot
+ .onWhaleAlert(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)
+ });
+ }, 97347575, 97347585, 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.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)
+ });
+ }, 97639665, 97639695, 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
+ .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)
+ });
+ }, 97664614, 97664618, 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
+ .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)
+ });
+ }, 97547200, 97547250, 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, chain) => {
+ const content: string[] = [];
+
+ bot
+ .or.onWhaleAlert(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)
+ });
+ }, 97347545, 97347555, 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
+ .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)
+ });
+ }, 97547200, 97547250, 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, chain) => {
+ const content: string[] = [];
+
+ bot
+ .onWhaleAlert(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)
+ });
+ }, 97347545, 97347555, 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
+ .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)
+ });
+ }, 97664610, 97664620, 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
+ .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)
+ });
+ }, 97547200, 97547250, 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, chain) => {
+ const content: string[] = [];
+
+ bot
+ .onWhaleAlert(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)
+ });
+ }, 97347575, 97347585, 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
+ .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)
+ });
+ }, 97547200, 97547250, 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 938ab185f0bf869a67f9858362bc5c040838c3e2..4ce95b870f34d1ecb79aecbade8933f7cd96716e 100644
--- a/__tests__/index.spec.ts
+++ b/__tests__/index.spec.ts
@@ -2,3 +2,5 @@
import "./detailed/bot_providers";
import "./detailed/bot_events";
+import "./detailed/individual_filter_tests";
+import "./detailed/realistic_scenarios";
diff --git a/package.json b/package.json
index 20e1c0e1e9d3829c74c7f10b8ebc8f6c9ed3ba8e..258d6dae1ab9ea845f55b96cfdafbb82b3f9ec5e 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 --project=workerbee_testsuite_mock"
},
"size-limit": [
{
@@ -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/playwright.config.ts b/playwright.config.ts
index a7a71a6a4f7e46d299285f0c9aa095045fe01142..42194cef6b9f48711b8b724a5174e918759520f9 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" } ]
@@ -10,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
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index edf04304beec066a5fb9bd327814ed16fa6549f3..23d2b21d7221c4cf681cc8cf9e7c64a274712016 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 1154365dd0dbbffc60921beb56a02cdf1e3be146..67806780ee46b8d901532b64aaaedfbb165c0466 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 136501ba4865ceab83e801999dc1b87d1b9334ba..4ff5fbdfe9d8fd8fc904276fced81ead3deb9bba 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 ed3fa10342e42cfa7cea017dc71192e5f057bfd3..b0ca5cb4ce5ab47e4c14b7abd37988767c6768cb 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 246ad5cf2a3b4c018b40ef92d76fb2fc718e7f96..c7168c136cbd46b48bb72a459a831c7f68679074 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 9327f32c8aafaa9b276a36982df88ceae83f51f5..54ac598a137f6cd9d9b21045050ca82862bb11bb 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)
}
};
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 38740c63f9d37ccaf496a6df0bcf40d9a63fc6cc..14b28446d6cc9743343583b93077a58d0e4c46a0 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;
}
}
diff --git a/src/chain-observers/providers/mention-provider.ts b/src/chain-observers/providers/mention-provider.ts
index c08d6f822e1a4fb79b3ecd59e8b311440469daa0..36910d6dcc35285c81765c1dd9263434b2d94568 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;
}
}
}