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..3b5305e4332585bfbde8f00cb379f08e448c3a87 100644
--- a/__tests__/assets/jest-helper.ts
+++ b/__tests__/assets/jest-helper.ts
@@ -1,12 +1,19 @@
-import { Page, test as base, expect } from "@playwright/test";
+/* eslint-disable no-console */
+import { ConsoleMessage, Page, test as base, expect } from "@playwright/test";
import "./globals";
import { IWorkerBee } from "../../dist/bundle";
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,25 +31,46 @@ export interface IWorkerBeeTest {
};
createWorkerBeeTest: >(
+ callback: (bot: IWorkerBee, resolve: (retVal?: T) => void, reject: (reason?: any) => void) => void,
+ dynamic?: boolean,
+ isMockEnvironment?: boolean
+ ) => Promise;
+
+ createMockWorkerBeeTest: >(
callback: (bot: IWorkerBee, resolve: (retVal?: T) => void, reject: (reason?: any) => void) => void,
dynamic?: boolean
) => Promise;
}
+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));
@@ -64,12 +92,21 @@ const envTestFor = (
const createWorkerBeeTest = async >(
envTestFor: IWorkerBeeTest["workerbeeTest"],
callback: (bot: IWorkerBee, resolve: (retVal?: T) => void, reject: (reason?: any) => void) => void,
- dynamic: boolean = false
+ dynamic: boolean = false,
+ isMockEnvironment: boolean = false
): Promise => {
const testRunner = dynamic ? envTestFor.dynamic : envTestFor;
return await testRunner(async ({ WorkerBee }, callbackStr) => {
- const bot = new WorkerBee({ chainOptions: { apiTimeout: 0 } });
+ const bot = isMockEnvironment
+ ? new WorkerBee({
+ chainOptions: {
+ apiEndpoint: "http://localhost:8000",
+ apiTimeout: 0
+ }
+ })
+ : new WorkerBee({ chainOptions: { apiTimeout: 0 } });
+
await bot.start();
const returnValue = await new Promise((resolve, reject) => {
@@ -85,12 +122,33 @@ const createWorkerBeeTest = async >(
}, callback.toString());
}
-export const test = base.extend({
+export const test = base.extend({
+ forEachTest: [async ({ page }, use, ) => {
+ page.on("console", (msg: ConsoleMessage) => {
+ console.log(">>", msg.type(), msg.text());
+ });
+
+ await page.goto("http://localhost:8080/__tests__/assets/test.html", { waitUntil: "load" });
+
+ await use();
+ }, { auto: true }],
+
+ forEachWorker: [async ({ browser }, use) => {
+ await use();
+
+ await browser.close();
+ }, { scope: "worker", auto: true }],
+
workerbeeTest: ({ page }, use) => {
use(envTestFor(page, createTestFor));
},
createWorkerBeeTest: ({ workerbeeTest }, use) => {
use((callback, dynamic) => createWorkerBeeTest(workerbeeTest, callback, dynamic));
+ },
+
+ createMockWorkerBeeTest: ({ page }, use) => {
+ const mockEnvTestFor = envTestFor(page, createTestFor, true);
+ use((callback, dynamic) => createWorkerBeeTest(mockEnvTestFor, callback, dynamic, true));
}
});
diff --git a/__tests__/detailed/bot_events.ts b/__tests__/detailed/bot_events.ts
index 9a6267d1d22de7076051103c1597aa8c715574e7..c2b01e134e80e977744ec067764e8ef80c3a2ae9 100644
--- a/__tests__/detailed/bot_events.ts
+++ b/__tests__/detailed/bot_events.ts
@@ -1,31 +1,14 @@
/* eslint-disable no-console */
import { expect } from "@playwright/test";
-import { ChromiumBrowser, ConsoleMessage, chromium } from "playwright";
import type { IStartConfiguration } from "../../src/bot";
import { test } from "../assets/jest-helper";
-let browser!: ChromiumBrowser;
-
const HIVE_BLOCK_INTERVAL = 3000;
test.describe("WorkerBee Bot events test", () => {
- test.beforeAll(async() => {
- browser = await chromium.launch({
- headless: true
- });
- });
-
- test.beforeEach(async({ page }) => {
- page.on("console", (msg: ConsoleMessage) => {
- console.log(">>", msg.type(), msg.text());
- });
-
- await page.goto("http://localhost:8080/__tests__/assets/test.html", { waitUntil: "load" });
- });
-
test("Should have a destroyable global module", async({ workerbeeTest }) => {
await workerbeeTest(({ WorkerBee }) => {
const bot = new WorkerBee();
@@ -1122,8 +1105,4 @@ test.describe("WorkerBee Bot events test", () => {
// This might not trigger in test environment, so we just check it doesn't throw
expect(typeof result).toBe("boolean");
});
-
- test.afterAll(async() => {
- await browser.close();
- });
});
diff --git a/__tests__/detailed/bot_providers.ts b/__tests__/detailed/bot_providers.ts
index 2b5ae25ffc7319a95a642c131fcfb37a7fc69e2c..8f5d4fd742280bf4bceabab361eac932c4f09e7a 100644
--- a/__tests__/detailed/bot_providers.ts
+++ b/__tests__/detailed/bot_providers.ts
@@ -1,25 +1,8 @@
/* eslint-disable no-console */
-import { ChromiumBrowser, ConsoleMessage, chromium } from "playwright";
import { expect } from "playwright/test";
import { test } from "../assets/jest-helper";
-let browser!: ChromiumBrowser;
-
test.describe("Bot Providers", () => {
- test.beforeAll(async() => {
- browser = await chromium.launch({
- headless: true
- });
- });
-
- test.beforeEach(async({ page }) => {
- page.on("console", (msg: ConsoleMessage) => {
- console.log(">>", msg.type(), msg.text());
- });
-
- await page.goto("http://localhost:8080/__tests__/assets/test.html", { waitUntil: "load" });
- });
-
test("Should be able to provide witnesses", async({ createWorkerBeeTest }) => {
const result = await createWorkerBeeTest((bot, resolve, reject) => {
const observer = bot.observe.onBlock().provideWitnesses("gtg");
@@ -381,8 +364,4 @@ test.describe("Bot Providers", () => {
expect(result.rcAccounts["gtg"].name).toBe("gtg");
expect(result.rcAccounts["blocktrades"].name).toBe("blocktrades");
});
-
- test.afterAll(async() => {
- await browser.close();
- });
});
diff --git a/__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..972c606c6c039d63f4309531864d651cbce484b2
--- /dev/null
+++ b/__tests__/detailed/individual_filter_tests.ts
@@ -0,0 +1,611 @@
+/* eslint-disable no-console */
+import { expect } from "@playwright/test";
+import { test } from "../assets/jest-helper";
+
+test.describe("WorkerBee Individual Filter Verification", () => {
+ test("1.1 - Should trigger when any specified account creates post - multiple accounts", async({ createWorkerBeeTest }) => {
+ const result = await createWorkerBeeTest((bot, resolve, reject) => {
+ const capturedPosts: string[] = [];
+
+ bot.providePastOperations(96549390, 96549415).onPosts("mtyszczak", "author2", "author3").subscribe({
+ next(data) {
+ for (const author of ["mtyszczak", "author2", "author3"])
+ data.posts[author]?.forEach(({ operation }) => {
+ capturedPosts.push(`Post by ${operation.author}: ${operation.permlink}`);
+ });
+ },
+ error(err) {
+ console.error(err);
+ reject(err);
+ },
+ complete: () => resolve(capturedPosts)
+ });
+ });
+
+ expect(result).toEqual(["Post by mtyszczak: hi-ve-everyone"]);
+ });
+
+ test("1.1 - Should trigger for simultaneous posts from multiple accounts in same block", async({ createWorkerBeeTest }) => {
+ const result = await createWorkerBeeTest((bot, resolve, reject) => {
+ const capturedPosts: Array<{ author: string; blockNumber: number }> = [];
+
+ bot.providePastOperations(97632050, 97632075).onBlock().or.onPosts("comandoyeya", "daddydog").subscribe({
+ next(data) {
+ for (const author of ["comandoyeya", "daddydog"])
+ data.posts[author]?.forEach(({ operation }) => {
+ capturedPosts.push({
+ author: operation.author,
+ blockNumber: data.block.number
+ });
+ });
+
+ },
+ error(err) {
+ console.error(err);
+ reject(err);
+ },
+ complete: () => resolve(capturedPosts)
+ });
+ });
+
+ expect(result).toEqual([
+ {
+ author: "comandoyeya",
+ blockNumber: 97632067
+ },
+ {
+ author: "daddydog",
+ blockNumber: 97632067
+ }
+ ]);
+ });
+
+ test("1.2 - Should NOT trigger when account creates comment instead of post", async({ createWorkerBeeTest }) => {
+ const result = await createWorkerBeeTest((bot, resolve, reject) => {
+ let postsDetected = 0;
+ let commentsDetected = 0;
+
+ /*
+ * Monitor an account known to create comments in this range.
+ * Also check for comments in the same range to verify account was active
+ */
+ bot.providePastOperations(96549690, 96549715).onPosts("gtg").or.onComments("gtg").subscribe({
+ next(data) {
+ // Count posts (should be 0)
+ data.posts["gtg"]?.forEach(() => {
+ postsDetected++;
+ });
+
+ // Count comments (should be > 0)
+ data.comments["gtg"]?.forEach(() => {
+ commentsDetected++;
+ });
+ },
+ error(err) {
+ console.error(err);
+ reject(err);
+ },
+ complete: () => resolve({ postsDetected, commentsDetected })
+ });
+ });
+
+ // Should detect comments but NOT posts
+ expect(result.commentsDetected).toBeGreaterThan(0);
+ expect(result.postsDetected).toBe(0);
+ });
+
+ test("1.2 - Should NOT trigger when monitored accounts create comments instead of posts", async({ createWorkerBeeTest }) => {
+ const result = await createWorkerBeeTest<{ postResults: Record; commentResults: Record }>((bot, resolve, reject) => {
+ const postResults: Record = {};
+ const commentResults: Record = {};
+
+ // Test accounts known to comment in this range
+ const testAccounts = ["gtg", "moretea", "khantaimur"];
+
+ /*
+ * Monitor multiple accounts for posts (should not trigger for comment activity)
+ * Also Verify these accounts were active with comments
+ */
+ bot.providePastOperations(96549690, 96549715).onPosts(...testAccounts).or.onComments(...testAccounts).subscribe({
+ next(data) {
+ testAccounts.forEach(account => {
+ data.posts[account]?.forEach(() => {
+ postResults[account] = (postResults[account] || 0) + 1;
+ });
+
+ data.comments[account]?.forEach(() => {
+ commentResults[account] = (commentResults[account] || 0) + 1;
+ });
+ });
+ },
+ error(err) {
+ console.error(err);
+ reject(err);
+ },
+ complete: () => resolve({ postResults, commentResults })
+ });
+ });
+
+ const totalComments = Object.values(result.commentResults).reduce((sum, count) => sum + count, 0);
+ const totalPosts = Object.values(result.postResults).reduce((sum, count) => sum + count, 0);
+
+ expect(totalComments).toBeGreaterThan(0);
+ expect(totalPosts).toBe(0);
+ });
+
+ test("1.2 - Should NOT trigger when different account creates post", async({ createWorkerBeeTest }) => {
+ const result = await createWorkerBeeTest<{ monitoredAccountPosts: number; otherAccountPosts: number }>((bot, resolve, reject) => {
+ let monitoredAccountPosts = 0;
+ let otherAccountPosts = 0;
+
+ /*
+ * Monitor for posts from a specific account
+ * Also Verify other accounts were posting in this range
+ */
+ bot.providePastOperations(96549390, 96549415).onPosts("nonexistent-account").or.onPosts("mtyszczak").subscribe({
+ next(data) {
+ data.posts["nonexistent-account"]?.forEach(() => {
+ monitoredAccountPosts++;
+ });
+
+ data.posts["mtyszczak"]?.forEach(() => {
+ otherAccountPosts++;
+ });
+ },
+ error(err) {
+ console.error(err);
+ reject(err);
+ },
+ complete: () => resolve({ monitoredAccountPosts, otherAccountPosts })
+ });
+ });
+
+ // Should NOT detect posts from monitored account, but should detect from other account
+ expect(result.monitoredAccountPosts).toBe(0);
+ expect(result.otherAccountPosts).toBeGreaterThan(0);
+ });
+
+ test("1.2 - Should handle empty account list", async({ createWorkerBeeTest }) => {
+ const result = await createWorkerBeeTest((bot, resolve, reject) => {
+ let dataReceived = false;
+
+ try {
+ // Test with no accounts (edge case)
+ bot.providePastOperations(96549390, 96549415).onPosts().subscribe({
+ next(_data) {
+ dataReceived = true;
+ console.log("Data received for empty account list");
+ },
+ error(err) {
+ console.error("Error with empty account list:", err);
+ reject(err);
+ },
+ complete: () => resolve(dataReceived)
+ });
+ } catch {
+ reject(new Error("Unexpected error occurred"));
+ }
+ });
+
+ expect(result).toBeFalsy();
+ });
+
+ test("2.1 - Should trigger when any specified account creates comment - multiple accounts", async({ createWorkerBeeTest }) => {
+ const result = await createWorkerBeeTest((bot, resolve, reject) => {
+ const capturedComments: string[] = [];
+
+ bot.providePastOperations(96549690, 96549715).onComments("gtg", "moretea", "khantaimur").subscribe({
+ next(data) {
+ for (const author of ["gtg", "moretea", "khantaimur"])
+ data.comments[author]?.forEach(({ operation }) => {
+ capturedComments.push(`Comment by ${operation.author}: ${operation.permlink}`);
+ });
+ },
+ error(err) {
+ console.error(err);
+ reject(err);
+ },
+ complete: () => resolve(capturedComments)
+ });
+ });
+
+ expect(result).toEqual([
+ "Comment by moretea: re-leothreads-2xpn8nyzd",
+ "Comment by khantaimur: re-vkcmjbdble",
+ "Comment by gtg: re-mtyszczak-1749229740753"
+ ]);
+ });
+
+ test("2.1 - Should trigger for simultaneous comments from multiple accounts in same block", async({ createWorkerBeeTest }) => {
+ const result = await createWorkerBeeTest((bot, resolve, reject) => {
+ const capturedComments: Array<{ author: string; blockNumber: number }> = [];
+
+ bot.providePastOperations(97634334, 97634348).onBlock().or.onComments("zayyar99", "beckyroyal").subscribe({
+ next(data) {
+ for (const author of ["zayyar99", "beckyroyal"])
+ data.comments[author]?.forEach(({ operation }) => {
+ capturedComments.push({
+ author: operation.author,
+ blockNumber: data.block.number
+ });
+ });
+ },
+ error(err) {
+ console.error(err);
+ reject(err);
+ },
+ complete: () => resolve(capturedComments)
+ });
+ });
+
+ expect(result).toEqual([
+ {
+ author: "zayyar99",
+ blockNumber: 97634338
+ },
+ {
+ author: "beckyroyal",
+ blockNumber: 97634338
+ }
+ ]);
+ });
+
+ test("2.2 - Should NOT trigger when account creates post instead of comment", async({ createWorkerBeeTest }) => {
+ const result = await createWorkerBeeTest((bot, resolve, reject) => {
+ let commentsDetected = 0;
+ let postsDetected = 0;
+
+
+ /*
+ * Monitor an account known to create posts in this range for comments (should not trigger)
+ * Also check for posts in the same range to verify account was active with posts
+ */
+ bot.providePastOperations(96549390, 96549415).onComments("mtyszczak").or.onPosts("mtyszczak").subscribe({
+ next(data) {
+ // Count comments (should be 0)
+ data.comments["mtyszczak"]?.forEach(() => {
+ commentsDetected++;
+ });
+
+ // Count posts (should be > 0)
+ data.posts["mtyszczak"]?.forEach(() => {
+ postsDetected++;
+ });
+ },
+ error(err) {
+ console.error(err);
+ reject(err);
+ },
+ complete: () => resolve({ commentsDetected, postsDetected })
+ });
+ });
+
+ // Should detect posts but NOT comments
+ expect(result.postsDetected).toBeGreaterThan(0);
+ expect(result.commentsDetected).toBe(0);
+ });
+
+ test("2.2 - Should NOT trigger when monitored accounts create posts instead of comments", async({ createWorkerBeeTest }) => {
+ const result = await createWorkerBeeTest<{ commentResults: Record; postResults: Record }>((bot, resolve, reject) => {
+ const commentResults: Record = {};
+ const postResults: Record = {};
+
+ // Test accounts known to post in this range
+ const testAccounts = ["mtyszczak", "nickdongsik", "techstyle"];
+
+ /*
+ * Monitor multiple accounts for comments (should not trigger for post activity)
+ * Also verify these accounts were active with posts
+ */
+ bot.providePastOperations(96549390, 96549415).onComments(...testAccounts).or.onPosts(...testAccounts).subscribe({
+ next(data) {
+ testAccounts.forEach(account => {
+ data.comments[account]?.forEach(() => {
+ commentResults[account] = (commentResults[account] || 0) + 1;
+ });
+
+ data.posts[account]?.forEach(() => {
+ postResults[account] = (postResults[account] || 0) + 1;
+ });
+ });
+ },
+ error(err) {
+ console.error(err);
+ reject(err);
+ },
+ complete: () => resolve({ commentResults, postResults })
+ });
+ });
+
+ const totalPosts = Object.values(result.postResults).reduce((sum, count) => sum + count, 0);
+ const totalComments = Object.values(result.commentResults).reduce((sum, count) => sum + count, 0);
+
+ expect(totalPosts).toBeGreaterThan(0);
+ expect(totalComments).toBe(0);
+ });
+
+ test("2.2 - Should NOT trigger when different account creates comment", async({ createWorkerBeeTest }) => {
+ const result = await createWorkerBeeTest((bot, resolve, reject) => {
+ let monitoredAccountComments = 0;
+ let otherAccountComments = 0;
+
+ /*
+ * Monitor for comments from a specific account that doesn't commented
+ * Also verify other accounts were commenting in this range
+ */
+ bot.providePastOperations(96549690, 96549715).onComments("nonexistent-commenter").or.onComments("gtg").subscribe({
+ next(data) {
+ data.comments["nonexistent-commenter"]?.forEach(() => {
+ monitoredAccountComments++;
+ });
+
+ data.comments["gtg"]?.forEach(() => {
+ otherAccountComments++;
+ });
+ },
+ error(err) {
+ console.error(err);
+ reject(err);
+ },
+ complete: () => resolve({ monitoredAccountComments, otherAccountComments })
+ });
+ });
+
+ // Should NOT detect comments from monitored account, but should detect from other account
+ expect(result.monitoredAccountComments).toBe(0);
+ expect(result.otherAccountComments).toBeGreaterThan(0);
+ });
+
+ test("2.2 - Should handle empty account list for comments", async({ createWorkerBeeTest }) => {
+ const result = await createWorkerBeeTest((bot, resolve, reject) => {
+ let dataReceived = false;
+
+ try {
+ // Test with no accounts (edge case)
+ bot.providePastOperations(96549690, 96549715).onComments().subscribe({
+ next(_data) {
+ dataReceived = true;
+ console.log("Data received for empty comment account list");
+ },
+ error(err) {
+ console.error("Error with empty comment account list:", err);
+ reject(err);
+ },
+ complete: () => resolve(dataReceived)
+ });
+ } catch {
+ reject(new Error("Unexpected error occurred"));
+ }
+ });
+
+ expect(result).toBeFalsy();
+ });
+
+ test("2.3 - Should trigger when any specified account creates post or comment", async({ createWorkerBeeTest }) => {
+ const result = await createWorkerBeeTest((bot, resolve, reject) => {
+ const capturedPosts: string[] = [];
+
+ bot
+ .providePastOperations(96549390, 96549415)
+ .onPosts("mtyszczak", "author2", "author3")
+ .or.onComments("secret-art", "author2", "author3")
+ .subscribe({
+ next(data) {
+ for (const author of ["mtyszczak", "secret-art", "author2", "author3"]) {
+ data.comments[author]?.forEach(({ operation }) => {
+ capturedPosts.push(`Comment by ${operation.author}: ${operation.permlink}`);
+ });
+
+ data.posts[author]?.forEach(({ operation }) => {
+ capturedPosts.push(`Post by ${operation.author}: ${operation.permlink}`);
+ });
+ }
+ },
+ error(err) {
+ console.error(err);
+ reject(err);
+ },
+ complete: () => resolve(capturedPosts)
+ });
+ });
+
+ expect(result).toEqual([
+ "Comment by secret-art: re-jfang003-sxg1lb",
+ "Comment by secret-art: re-aussieninja-sxg1lm",
+ "Post by mtyszczak: hi-ve-everyone",
+ "Comment by secret-art: re-aussieninja-sxg1m5",
+ "Comment by secret-art: re-jfang003-sxg1mg"
+ ]);
+ });
+
+ test("3.1 - Should trigger when any specified account votes - multiple accounts", async({ createWorkerBeeTest }) => {
+ const result = await createWorkerBeeTest((bot, resolve, reject) => {
+ const capturedVotes: string[] = [];
+
+ bot.providePastOperations(96549390, 96549415).onVotes("dhedge", "winanda").subscribe({
+ next(data) {
+ for (const voter of ["dhedge", "winanda"])
+ data.votes[voter]?.forEach(({ operation }) => {
+ capturedVotes.push(`Vote by ${operation.voter} on ${operation.author}/${operation.permlink}`);
+ });
+ },
+ error(err) {
+ console.error(err);
+ reject(err);
+ },
+ complete: () => resolve(capturedVotes)
+ });
+ });
+
+ expect(result).toEqual([
+ "Vote by winanda on xlety/is-it-really-worth-creating",
+ "Vote by dhedge on gpache/i-went-to-a-doctors-office-my-vision-is-improving-eng-esp",
+ "Vote by dhedge on helicreamarket/sorpresa-al-horno-esp-eng"
+ ]);
+ });
+
+ test("3.1 - Should trigger for simultaneous votes from multiple accounts in same block", async({ createWorkerBeeTest }) => {
+ const result = await createWorkerBeeTest((bot, resolve, reject) => {
+ const capturedVotes: Array<{ voter: string; blockNumber: number }> = [];
+
+ bot.providePastOperations(96549390, 96549404).onBlock().or.onVotes("noctury", "the-burn").subscribe({
+ next(data) {
+ for (const voter of ["noctury", "the-burn"])
+ data.votes[voter]?.forEach(({ operation }) => {
+ capturedVotes.push({
+ voter: operation.voter,
+ blockNumber: data.block.number
+ });
+ });
+ },
+ error(err) {
+ console.error(err);
+ reject(err);
+ },
+ complete: () => resolve(capturedVotes)
+ });
+ });
+
+ expect(result).toEqual([
+ {
+ voter: "noctury",
+ blockNumber: 96549403
+ },
+ {
+ voter: "the-burn",
+ blockNumber: 96549403
+ }
+ ]);
+ });
+
+ test("3.2 - Should NOT trigger when account creates post/comment instead of voting", async({ createWorkerBeeTest }) => {
+ const result = await createWorkerBeeTest((bot, resolve, reject) => {
+ let votesDetected = 0;
+ let commentOperationsDetected = 0;
+
+ /*
+ * Monitor an account known to create posts/comments but does not vote in this range
+ * Also Check for posts to verify account was active
+ */
+ bot.providePastOperations(96549390, 96549415).onVotes("mtyszczak").or.onPosts("mtyszczak").or.onComments("mtyszczak").subscribe({
+ next(data) {
+ // Count votes (should be 0)
+ data.votes["mtyszczak"]?.forEach(() => {
+ votesDetected++;
+ });
+
+ // Count comments (should be > 0)
+ data.comments["mtyszczak"]?.forEach(() => {
+ commentOperationsDetected++;
+ });
+
+ data.posts["mtyszczak"]?.forEach(() => {
+ commentOperationsDetected++;
+ });
+ },
+ error(err) {
+ console.error(err);
+ reject(err);
+ },
+ complete: () => resolve({ votesDetected, commentOperationsDetected })
+ });
+ });
+
+ // Should detect posts/comments but no votes from this account in this range
+ expect(result.commentOperationsDetected).toBeGreaterThan(0);
+ expect(result.votesDetected).toBe(0);
+ });
+
+ test("3.2 - Should NOT trigger when different account votes", async({ createWorkerBeeTest }) => {
+ const result = await createWorkerBeeTest((bot, resolve, reject) => {
+ let monitoredAccountVotes = 0;
+ let otherAccountVotes = 0;
+
+ /*
+ * Monitor for votes from a specific account that doesn't vote much
+ * Also Verify other accounts were voting in this range
+ */
+ bot.providePastOperations(96549390, 96549415).onVotes("nonexistent-voter").or.onVotes("noctury").subscribe({
+ next(data) {
+ data.votes["nonexistent-voter"]?.forEach(() => {
+ monitoredAccountVotes++;
+ });
+
+ data.votes["noctury"]?.forEach(() => {
+ otherAccountVotes++;
+ });
+ },
+ error(err) {
+ console.error(err);
+ reject(err);
+ },
+ complete: () => resolve({ monitoredAccountVotes, otherAccountVotes })
+ });
+ });
+
+ // Should NOT detect votes from monitored account, but should detect from other account
+ expect(result.monitoredAccountVotes).toBe(0);
+ expect(result.otherAccountVotes).toBeGreaterThan(0);
+ });
+
+ test("3.2 - Should handle empty account list for votes", async({ createWorkerBeeTest }) => {
+ const result = await createWorkerBeeTest((bot, resolve, reject) => {
+ let dataReceived = false;
+
+ try {
+ // Test with no accounts (edge case)
+ bot.providePastOperations(96549390, 96549415).onVotes().subscribe({
+ next(_data) {
+ dataReceived = true;
+ console.log("Data received for empty votes account list");
+ },
+ error(err) {
+ console.error("Error with empty votes account list:", err);
+ reject(err);
+ },
+ complete: () => resolve(dataReceived)
+ });
+ } catch {
+ reject(new Error("Unexpected error occurred"));
+ }
+ });
+
+ expect(result).toBeFalsy();
+ });
+
+ test("Multiple 'or' filters should work correctly", async({ createWorkerBeeTest }) => {
+ const result = await createWorkerBeeTest((bot, resolve, reject) => {
+ const capturedPosts: string[] = [];
+
+ bot.providePastOperations(96549390, 96549415)
+ .onPosts("mtyszczak").or.or.or.or.or.onComments("secret-art")
+ .subscribe({
+ next(data) {
+ for (const author of ["mtyszczak", "secret-art"]) {
+ data.posts[author]?.forEach(({ operation }) => {
+ capturedPosts.push(`Post by ${operation.author}: ${operation.permlink}`);
+ });
+
+ data.comments[author]?.forEach(({ operation }) => {
+ capturedPosts.push(`Comment by ${operation.author}: ${operation.permlink}`);
+ });
+ }
+
+ },
+ error(err) {
+ console.error(err);
+ reject(err);
+ },
+ complete: () => resolve(capturedPosts)
+ });
+ });
+
+ expect(result).toEqual([
+ "Comment by secret-art: re-jfang003-sxg1lb",
+ "Comment by secret-art: re-aussieninja-sxg1lm",
+ "Post by mtyszczak: hi-ve-everyone",
+ "Comment by secret-art: re-aussieninja-sxg1m5",
+ "Comment by secret-art: re-jfang003-sxg1mg"
+ ]);
+ });
+});
diff --git a/__tests__/detailed/mock_realistic_scenarios_live_data.ts b/__tests__/detailed/mock_realistic_scenarios_live_data.ts
new file mode 100644
index 0000000000000000000000000000000000000000..faafb0d7a0a56dc57cdb109f4d878769a19497c5
--- /dev/null
+++ b/__tests__/detailed/mock_realistic_scenarios_live_data.ts
@@ -0,0 +1,492 @@
+/* eslint-disable no-console */
+import { ChromiumBrowser, chromium, expect } from "playwright/test";
+import { test } from "../assets/jest-helper";
+
+import { JsonRpcMock, resetMockCallIndexes } from "../assets/mock/api-mock";
+import { resetCallIndexes } from "../assets/mock/jsonRpcMock";
+import { createServer } from "../assets/mock/proxy-mock-server";
+
+let browser: ChromiumBrowser;
+
+let closeServer: () => Promise;
+
+test.describe("Realistic Scenarios with Live Data", () => {
+ test.beforeAll(async () => {
+ browser = await chromium.launch({
+ headless: true
+ });
+
+ closeServer = await createServer(new JsonRpcMock(), 8000);
+ });
+
+ test.beforeEach(async ({ page }) => {
+ await page.goto("http://localhost:8080/__tests__/assets/test.html", {
+ waitUntil: "load",
+ });
+
+ resetMockCallIndexes();
+ resetCallIndexes();
+ });
+
+ test("3.1 - Should be able to create real-time social dashboard", async ({ createMockWorkerBeeTest }) => {
+ const result = await createMockWorkerBeeTest((bot, resolve, reject) => {
+ let vote: { text: string, accountName: string, manabar: string } | undefined;
+ let post: { text: string, accountName: string, manabar: string } | undefined;
+ let comment: { text: string, accountName: string, manabar: string } | undefined;
+
+ bot.observe.onPosts("gtg")
+ .or.onComments("gtg")
+ .or.onVotes("gtg")
+ .provideAccounts("gtg")
+ .provideManabarData(/* RC */ 2, "gtg")
+ .subscribe({
+ next(data) {
+ data.posts.gtg?.forEach(({ operation }) => {
+ post = {
+ text: `Post: ${operation.author} - ${operation.title}`,
+ accountName: JSON.stringify(data.accounts.gtg?.name),
+ manabar: JSON.stringify(data.manabarData.gtg?.[2]?.currentMana)
+ };
+ });
+
+ data.comments.gtg?.forEach(({ operation }) => {
+ comment = {
+ text: `Comment: ${operation.author} -> ${operation.parent_author}`,
+ accountName: JSON.stringify(data.accounts.gtg?.name),
+ manabar: JSON.stringify(data.manabarData.gtg?.[2]?.currentMana)
+ };
+ });
+
+ data.votes.gtg?.forEach(({ operation }) => {
+ vote = {
+ text: `Vote: ${operation.voter} - ${operation.author}`,
+ accountName: JSON.stringify(data.accounts.gtg?.name),
+ manabar: JSON.stringify(data.manabarData.gtg?.[2]?.currentMana)
+ };
+ });
+
+ if (post !== undefined && vote !== undefined && comment !== undefined)
+ resolve([post, vote, comment]);
+ },
+ error: (err) => {
+ console.error(err);
+ reject(err);
+ }
+ });
+ });
+
+ expect(result).toEqual([
+ {
+ accountName: "\"gtg\"",
+ manabar: "{\"low\":2125861720,\"high\":501074,\"unsigned\":true}",
+ text: "Post: gtg - SkyTeam Airline Alliance - Official partner of HiveFest",
+ },
+ {
+ accountName: "\"gtg\"",
+ manabar: "{\"low\":1965705338,\"high\":37491,\"unsigned\":true}",
+ text: "Vote: gtg - hbd.funder",
+ },
+ {
+ accountName: "\"gtg\"",
+ manabar: "{\"low\":2125861720,\"high\":501074,\"unsigned\":true}",
+ text: "Comment: gtg -> purepinay",
+ }
+ ]);
+ });
+
+ test("3.2 - Should be able to create account health monitor", async ({ createMockWorkerBeeTest }) => {
+ const result = await createMockWorkerBeeTest((bot, resolve, reject) => {
+ let manabarData: string | undefined;
+
+ bot.observe.onAccountsBalanceChange(false, "gtg")
+ .or.onAccountsMetadataChange("gtg")
+ .or.onAccountsManabarPercent(0, 100, "gtg")
+ .provideAccounts("gtg")
+ .subscribe({
+ next(data) {
+ manabarData = `Reached ${data.manabarData.gtg?.[0]?.percent}% of manabar`;
+
+ if (
+ manabarData !== undefined &&
+ // eslint-disable-next-line max-len
+ JSON.stringify(data.accounts.gtg?.jsonMetadata) === JSON.stringify({profile:{witness_description:"Gandalf the Grey, building Hive, improving Hive infrastructure.", profile_image:"https://grey.house/img/grey_4.jpg", name:"Gandalf the Grey", about:"IT Wizard, Hive Witness", location:"Hive", version:2}}) &&
+ data.accounts.gtg?.balance.HBD.savings.amount === "3468"
+ )
+ resolve([manabarData, data.accounts.gtg?.jsonMetadata, data.accounts.gtg?.balance.HBD.savings.amount]);
+ },
+ error: (err) => {
+ console.error(err);
+ reject(err);
+ }
+ });
+ });
+
+ expect(result).toEqual([
+ "Reached 100% of manabar",
+ {
+ profile: {
+ about: "IT Wizard, Hive Witness",
+ location: "Hive",
+ name: "Gandalf the Grey",
+ profile_image: "https://grey.house/img/grey_4.jpg",
+ version: 2,
+ witness_description: "Gandalf the Grey, building Hive, improving Hive infrastructure.",
+ },
+ },
+ "3468" // HBD savings balance
+ ]);
+ });
+
+ test("3.3 - Should be able to create market alert system", async ({ createMockWorkerBeeTest }) => {
+ const result = await createMockWorkerBeeTest((bot, resolve, reject) => {
+ bot.observe.onFeedPriceChange(95)
+ .or.onFeedPriceNoChange(1)
+ .or.onWitnessesMissedBlocks(5, "gtg")
+ .provideFeedPriceData()
+ .subscribe({
+ next(data) {
+ let percentChange = 0;
+
+ const priceHistoryArray = Array.from(data.feedPrice.priceHistory);
+
+ const price1 = Number.parseInt(priceHistoryArray[0].base!.amount) / Number.parseInt(priceHistoryArray[0].quote!.amount);
+ const price2 = Number.parseInt(priceHistoryArray[1].base!.amount) / Number.parseInt(priceHistoryArray[1].quote!.amount);
+
+ percentChange = Math.abs(price1 - price2) / price2 * 100;
+
+ resolve(percentChange);
+ },
+ error: (err) => {
+ console.error(err);
+ reject(err);
+ }
+ });
+ });
+
+ expect(result).toEqual(134.30962343096238);
+ });
+
+ test("3.5 - Should be able to create investment portfolio monitor", async ({ createMockWorkerBeeTest }) => {
+ const result = await createMockWorkerBeeTest((bot, resolve, reject) => {
+ const marketOperations: string[] = [];
+
+ bot.observe.onAccountsBalanceChange(true, "gtg", "blocktrades")
+ .or.onWhaleAlert(bot.chain!.hiveCoins(1000))
+ .or.onExchangeTransfer()
+ .provideAccounts("gtg", "blocktrades")
+ .subscribe({
+ next(data) {
+ data.exchangeTransferOperations.forEach(({ operation }) => {
+ marketOperations.push(`Exchange transfer: ${operation.from} -> ${operation.to} (${operation.amount.amount})`);
+ });
+
+ data.whaleOperations.forEach(({ operation }) => {
+ marketOperations.push(`Whale alert: ${operation.from} -> ${operation.to} (${operation.amount.amount})`);
+ });
+
+ if (marketOperations.length >= 2)
+ resolve(marketOperations);
+ },
+ error: (err) => {
+ console.error(err);
+ reject(err);
+ }
+ });
+ });
+
+ expect(result).toEqual([
+ "Exchange transfer: mxchive -> inhivepool (23890)",
+ "Exchange transfer: bdhivesteem -> gtg (1000)",
+ "Whale alert: mxchive -> inhivepool (23890)",
+ "Whale alert: blocktrades -> gtg (10000000)"
+ ]);
+ });
+
+ test("3.6 - Should be able to create content aggregation service", async ({ createMockWorkerBeeTest }) => {
+ const result = await createMockWorkerBeeTest((bot, resolve, reject) => {
+ const contentOperations: string[] = [];
+
+ bot.observe.onPosts("mtyszczak")
+ .or.onPosts("fwaszkiewicz")
+ .or.onReblog("thebeedevs")
+ .subscribe({
+ next(data) {
+ data.posts.mtyszczak?.forEach(({ operation }) => {
+ contentOperations.push(`Post: ${operation.author} - ${operation.title}`);
+ });
+
+ data.posts.fwaszkiewicz?.forEach(({ operation }) => {
+ contentOperations.push(`Post: ${operation.author} - ${operation.title}`);
+ });
+
+ data.reblogs.thebeedevs?.forEach(({ operation }) => {
+ contentOperations.push(`Reblog: ${operation.account} -> ${operation.author}/${operation.permlink}`);
+ });
+
+ if (contentOperations.length >= 3)
+ resolve(contentOperations);
+ },
+ error: (err) => {
+ console.error(err);
+ reject(err);
+ }
+ });
+ });
+
+ expect(result).toEqual([
+ "Post: mtyszczak - Write on Hive, Read Everywhere!",
+ "Post: fwaszkiewicz - Hi To Hive! ๐",
+ "Reblog: thebeedevs -> fwaszkiewicz/hi-to-hive",
+ ]);
+ });
+
+ test("3.7 - Should be able to create engagement optimization bot", async ({ createMockWorkerBeeTest }) => {
+ const result = await createMockWorkerBeeTest((bot, resolve, reject) => {
+ const content: string[] = [];
+
+ bot.observe.onAccountsManabarPercent(/* UPVOTE */ 0, 90, "gtg")
+ .or.onPosts("fwaszkiewicz")
+ .or.onComments("fwaszkiewicz")
+ .provideManabarData(/* UPVOTE */ 0, "gtg")
+ .subscribe({
+ next(data) {
+ data.posts.fwaszkiewicz?.forEach(({ operation }) => {
+ content.push(`Post: ${operation.author} - ${operation.title}`);
+ });
+
+ data.comments.fwaszkiewicz?.forEach(({ operation }) => {
+ content.push(`Comment: ${operation.author} -> ${operation.parent_author}`);
+ });
+
+ if (data.manabarData.gtg![0]!.percent >= 90 && content.length >= 2)
+ resolve(`Reached 90% of manabar for upvote: ${data.manabarData.gtg![0]!.percent}, available content: ${content}`);
+ },
+ error: (err) => {
+ console.error(err);
+ reject(err);
+ }
+ });
+ });
+
+ expect(result).toEqual("Reached 90% of manabar for upvote: 100, available content: Post: fwaszkiewicz - Hi To Hive! ๐,Comment: fwaszkiewicz -> mtyszczak");
+ });
+
+ test("4.1 - Should be able to perform complete account analysis", async ({ createMockWorkerBeeTest }) => {
+ const result = await createMockWorkerBeeTest((bot, resolve, reject) => {
+ const content: string[] = [];
+
+ bot.observe.onBlock()
+ .provideAccounts("gtg")
+ .provideRcAccounts("gtg")
+ .provideManabarData(/* RC */2, "gtg")
+ .provideManabarData(/* UPVOTE */0, "gtg")
+ .provideBlockData()
+ .provideFeedPriceData()
+ .subscribe({
+ next(data) {
+ content.push(`Account: ${data.accounts.gtg?.name}, Balance: ${data.accounts.gtg?.balance.HBD.savings.amount}`);
+ content.push(`RC mana: ${data.rcAccounts.gtg?.rcManabar.currentMana}`);
+ content.push(`UPVOTE mana: ${data.manabarData.gtg?.[0]?.currentMana}`);
+ content.push(`Block number: ${data.block.number}`);
+ content.push(`Feed price: ${Array.from(data.feedPrice.priceHistory)[0].base!.amount}/${Array.from(data.feedPrice.priceHistory)[0].quote!.amount}`);
+
+ if (content.length >= 5)
+ resolve(content);
+ },
+ error: (err) => {
+ console.error(err);
+ reject(err);
+ }
+ });
+ });
+
+ expect(result).toEqual([
+ "Account: gtg, Balance: 0",
+ "RC mana: 161024584599674",
+ "UPVOTE mana: 2897631713028020",
+ "Block number: 97477291",
+ "Feed price: 280/1000"
+ ]);
+ });
+
+ test("4.2 - Should be able to perform multi-account comparison", async ({ createMockWorkerBeeTest }) => {
+ const result = await createMockWorkerBeeTest((bot, resolve, reject) => {
+ const content: string[] = [];
+
+ bot.observe.onBlock()
+ .provideAccounts("gtg", "blocktrades", "thebeedevs")
+ .provideManabarData(/* RC */2, "gtg", "blocktrades", "thebeedevs")
+ .provideWitnesses("gtg", "blocktrades")
+ .subscribe({
+ next(data) {
+ content.push(`Account: ${data.accounts.gtg?.name}, Balance: ${data.accounts.gtg?.balance.HBD.savings.amount}`);
+ content.push(`RC mana: ${data.manabarData.gtg?.[2]?.currentMana}`);
+ content.push(`Witnesses missed blocks: ${data.witnesses.gtg?.totalMissedBlocks}`);
+
+ content.push(`Account: ${data.accounts.blocktrades?.name}, Balance: ${data.accounts.blocktrades?.balance.HBD.savings.amount}`);
+ content.push(`RC mana: ${data.manabarData.blocktrades?.[2]?.currentMana}`);
+ content.push(`Witnesses missed blocks: ${data.witnesses.blocktrades?.totalMissedBlocks}`);
+
+ content.push(`Account: ${data.accounts.thebeedevs?.name}, Balance: ${data.accounts.thebeedevs?.balance.HBD.savings.amount}`);
+ content.push(`RC mana: ${data.manabarData.thebeedevs?.[2]?.currentMana}`);
+
+ if (content.length >= 8)
+ resolve(content);
+ },
+ error: (err) => {
+ console.error(err);
+ reject(err);
+ }
+ });
+ });
+
+ expect(result).toEqual([
+ "Account: gtg, Balance: 0",
+ "RC mana: 161024584599674",
+ "Witnesses missed blocks: 988",
+ "Account: blocktrades, Balance: 130076015",
+ "RC mana: 15564167323386971",
+ "Witnesses missed blocks: 3728",
+ "Account: thebeedevs, Balance: 215216",
+ "RC mana: 3851154925254"
+ ]);
+ });
+
+ test("4.3 - Should be able to create comprehensive market analysis", async ({ createMockWorkerBeeTest }) => {
+ const result = await createMockWorkerBeeTest((bot, resolve, reject) => {
+ const content: string[] = [];
+
+ bot.observe.onBlock()
+ .or.onInternalMarketOperation()
+ .or.onExchangeTransfer()
+ .provideBlockData()
+ .provideFeedPriceData()
+ .provideAccounts("gtg", "blocktrades")
+ .subscribe({
+ next(data) {
+ data.internalMarketOperations.forEach(({ operation }) => {
+ content.push(`Internal market operation: owner: ${operation.owner}, order id: ${operation.orderId}, block : ${data.block.number}`);
+ });
+
+ data.exchangeTransferOperations.forEach(({ operation }) => {
+ content.push(`Exchange transfer: ${operation.from} -> ${operation.to} (${operation.amount.amount}), block: ${data.block.number}`);
+ });
+
+ if (content.length >= 2)
+ resolve(content);
+ },
+ error: (err) => {
+ console.error(err);
+ reject(err);
+ }
+ });
+ });
+
+ expect(result).toEqual([
+ "Internal market operation: owner: honeybot, order id: 1485200410, block : 97477294",
+ "Exchange transfer: mxchive -> inhivepool (23890), block: 97477294",
+ "Exchange transfer: bdhivesteem -> gtg (1000), block: 97477294"
+ ]);
+ });
+
+ test("4.4 - Should be able to create social network analysis", async ({ createMockWorkerBeeTest }) => {
+ const result = await createMockWorkerBeeTest((bot, resolve, reject) => {
+ const content: string[] = [];
+
+ bot.observe.onFollow("gtg")
+ .or.onFollow("blocktrades")
+ .or.onReblog("gtg")
+ .or.onMention("gtg")
+ .provideAccounts("gtg", "blocktrades")
+ .provideManabarData(/* RC */ 2, "gtg", "blocktrades")
+ .subscribe({
+ next(data) {
+ data.follows.gtg?.forEach(({ operation }) => {
+ content.push(`Follow: ${operation.follower} -> ${operation.following}, (${data.accounts.gtg?.name})`);
+ });
+
+ data.follows.blocktrades?.forEach(({ operation }) => {
+ content.push(`Follow: ${operation.follower} -> ${operation.following}, (${data.accounts.blocktrades?.name})`);
+ });
+
+ data.reblogs.gtg?.forEach(({ operation }) => {
+ content.push(`Reblog: ${operation.account} -> ${operation.author}/${operation.permlink} (${data.accounts.gtg?.name})`);
+ });
+
+ data.mentioned.gtg?.forEach((operation) => {
+ content.push(`Mention: ${operation.author} -> ${operation.permlink} (${data.accounts.gtg?.name})`);
+ });
+
+ if (content.length >= 4)
+ resolve(content);
+ },
+ error: (err) => {
+ console.error(err);
+ reject(err);
+ }
+ });
+ });
+
+ expect(result).toEqual([
+ "Follow: gtg -> thebeedevs, (gtg)",
+ "Follow: blocktrades -> thebeedevs, (blocktrades)",
+ "Reblog: gtg -> fwaszkiewicz/hi-to-hive (gtg)",
+ "Mention: mtyszczak -> write-on-hive-read-everywhere (gtg)",
+ "Mention: fwaszkiewicz -> hi-to-hive (gtg)"
+ ]);
+ });
+
+ test("4.5 - Should be able to create content performance dashboard", async ({ createMockWorkerBeeTest }) => {
+ const result = await createMockWorkerBeeTest((bot, resolve, reject) => {
+ const content: string[] = [];
+
+ bot.observe.onPosts("gtg")
+ .or.onComments("gtg")
+ .or.onVotes("gtg")
+ .or.onReblog("gtg")
+ .provideAccounts("gtg")
+ .provideManabarData(/* UPVOTE */ 0, "gtg")
+ .provideBlockData()
+ .subscribe({
+ next(data) {
+ data.posts.gtg?.forEach(({ operation }) => {
+ content.push(`Post: ${operation.author} - ${operation.title} (${data.accounts.gtg?.name}) (${data.manabarData.gtg?.[0]?.currentMana})`);
+ });
+
+ data.comments.gtg?.forEach(({ operation }) => {
+ // eslint-disable-next-line max-len
+ content.push(`Comment: ${operation.author} -> ${operation.parent_author} (${data.accounts.gtg?.name}) (${data.manabarData.gtg?.[0]?.currentMana})`);
+ });
+
+ data.votes.gtg?.forEach(({ operation }) => {
+ content.push(`Vote: ${operation.voter} - ${operation.author} (${data.accounts.gtg?.name}) (${data.manabarData.gtg?.[0]?.currentMana})`);
+ });
+
+ data.reblogs.gtg?.forEach(({ operation }) => {
+ // eslint-disable-next-line max-len
+ content.push(`Reblog: ${operation.account} -> ${operation.author}/${operation.permlink} (${data.accounts.gtg?.name}) (${data.manabarData.gtg?.[0]?.currentMana})`);
+ });
+
+ if (content.length >= 4)
+ resolve(content);
+ },
+ error: (err) => {
+ console.error(err);
+ reject(err);
+ }
+ });
+ });
+
+ expect(result).toEqual([
+ "Vote: gtg - hbd.funder (gtg) (2897631713028020)",
+ "Comment: gtg -> purepinay (gtg) (18469160006473)",
+ "Reblog: gtg -> fwaszkiewicz/hi-to-hive (gtg) (18469160006473)",
+ "Post: gtg - SkyTeam Airline Alliance - Official partner of HiveFest (gtg) (18469160006473)"
+ ]);
+ });
+
+ test.afterAll(async () => {
+ await browser.close();
+ await closeServer();
+ });
+});
diff --git a/__tests__/detailed/realistic_scenarios.ts b/__tests__/detailed/realistic_scenarios.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0e860fe3091a4de573d74cb1348797963182d31b
--- /dev/null
+++ b/__tests__/detailed/realistic_scenarios.ts
@@ -0,0 +1,489 @@
+/* eslint-disable no-console */
+import { custom_json } from "@hiveio/wax";
+import { expect } from "playwright/test";
+import { test } from "../assets/jest-helper";
+
+test.describe("Bot Realistic Scenarios", () => {
+ test("1.1 - Should be able to monitor posts OR comments from multiple authors", async({ createWorkerBeeTest }) => {
+ const result = await createWorkerBeeTest((bot, resolve, reject) => {
+ const content: string[] = [];
+
+ bot.providePastOperations(96549390, 96549415).onPosts("mtyszczak").or.onPosts("nickdongsik").or.onComments("brando28").subscribe({
+ next(data) {
+ for (const author in data.posts)
+ data.posts[author].forEach(({ operation }) => content.push(`${operation.author} - ${operation.permlink}`));
+
+ for (const author in data.comments)
+ data.comments[author].forEach(({ operation }) => content.push(`${operation.author} - ${operation.permlink}`));
+ },
+ error: (err) => {
+ console.error(err);
+ reject(err);
+ },
+ complete: () => resolve(content)
+ });
+ }, true);
+
+ expect(result).toEqual([
+ "brando28 - re-bitcoinman-ovjhawi6",
+ "mtyszczak - hi-ve-everyone",
+ "nickdongsik - yay-hb1hao"
+ ]);
+ });
+
+ test("1.2 - Should be able to create social activity aggregator", async({ createWorkerBeeTest }) => {
+ const result = await createWorkerBeeTest((bot, resolve, reject) => {
+ const content: string[] = [];
+
+ bot.providePastOperations(97146285, 97146300).onVotes("e-sport-gamer").or.onFollow("fwaszkiewicz").or.onReblog("maxinpower").subscribe({
+ next(data) {
+ for (const author in data.votes)
+ data.votes[author].forEach(({ operation }) => content.push(`Vote: ${operation.voter} - ${operation.permlink}`));
+
+ for (const author in data.follows)
+ data.follows[author].forEach(({ operation }) => content.push(`Follow: ${operation.follower} - ${operation.following}`));
+
+ for (const author in data.reblogs)
+ data.reblogs[author].forEach(({ operation }) => content.push(`Reblog: ${operation.author} - ${operation.permlink}`));
+ },
+ error: (err) => {
+ console.error(err);
+ reject(err);
+ },
+ complete: () => resolve(content)
+ });
+ }, true);
+
+ expect(result).toEqual([
+ "Vote: e-sport-gamer - city-pingeons",
+ "Follow: fwaszkiewicz - thebeedevs",
+ "Follow: fwaszkiewicz - thebeedevs",
+ "Reblog: maxinpower - erinnnerungen-an-eine-gute-currywurst-berlin-impressions"
+ ]);
+ });
+
+ test("1.3 - Should be able to create financial activity monitor", async({ createWorkerBeeTest }) => {
+ const result = await createWorkerBeeTest((bot, resolve, reject) => {
+ const content: string[] = [];
+
+ bot
+ .providePastOperations(97347575, 97347585)
+ .onWhaleAlert(bot.chain!.hiveCoins(50))
+ .or.onInternalMarketOperation()
+ .or.onExchangeTransfer()
+ .subscribe({
+ next(data) {
+ data.exchangeTransferOperations.forEach(({ operation }) => {
+ content.push(`Exchange Transfer: ${operation.from} -> ${operation.to} - ${operation.amount.amount}`);
+ });
+
+ data.internalMarketOperations.forEach(({ operation }) => {
+ content.push(`Internal Market Operation: ${operation.owner} - ${operation.orderId}`);
+ });
+
+ data.whaleOperations.forEach(({ operation }) => {
+ content.push(`Whale Alert: ${operation.from} -> ${operation.to} - ${operation.amount.amount}`);
+ });
+ },
+ error: (err) => {
+ console.error(err);
+ reject(err);
+ },
+ complete: () => resolve(content)
+ });
+ }, true);
+
+ expect(result).toEqual([
+ "Internal Market Operation: honeybot - 243293707",
+ "Whale Alert: honey-swap -> luluwinda - 53308",
+ "Internal Market Operation: honeybot - 1485200410",
+ "Exchange Transfer: mxchive -> inhivepool - 23890"
+ ]);
+ });
+
+ test("1.4 - Should be able to create content engagement tracker", async({ createWorkerBeeTest }) => {
+ const result = await createWorkerBeeTest((bot, resolve, reject) => {
+ const content: string[] = [];
+
+ bot.providePastOperations(97639665, 97639695).onMention("thebeedevs").or.onPosts("thebeedevs").or.onReblog("thebeedevs").subscribe({
+ next(data) {
+ data.posts.thebeedevs?.forEach(({ operation }) => {
+ content.push(`Post: ${operation.author} - ${operation.permlink}`);
+ });
+
+ data.mentioned.thebeedevs?.forEach((operation) => {
+ content.push(`Mention: ${operation.author} - ${operation.permlink}`);
+ });
+
+ data.reblogs.thebeedevs?.forEach(({ operation }) => {
+ content.push(`Reblog: ${operation.author} - ${operation.permlink}`);
+ });
+ },
+ error: (err) => {
+ console.error(err);
+ reject(err);
+ },
+ complete: () => resolve(content)
+ });
+ }, true);
+
+ expect(result).toEqual([
+ "Post: thebeedevs - hivesense-why-nothing-worked-at-first-and-what-we-did-about-it",
+ "Mention: thebeedevs - hivesense-why-nothing-worked-at-first-and-what-we-did-about-it",
+ "Reblog: thebeedevs - hivesense-why-nothing-worked-at-first-and-what-we-did-about-it"
+ ]);
+ });
+
+ test("1.5 - Should be able to create cross-platform activity monitor", async({ createWorkerBeeTest }) => {
+ const result = await createWorkerBeeTest((bot, resolve, reject) => {
+ const content: string[] = [];
+
+ bot
+ .providePastOperations(97664614, 97664618)
+ .onCustomOperation("follow")
+ .or.onCustomOperation("reblog")
+ .or.onNewAccount().subscribe({
+ next(data) {
+ data.customOperations.follow?.forEach(({ operation }) => {
+ content.push(`Follow: ${(operation as custom_json).json}`);
+ });
+
+ data.customOperations.reblog?.forEach(({ operation }) => {
+ content.push(`Reblog: ${(operation as custom_json).json}`);
+ });
+
+ data.newAccounts.forEach((operation) => {
+ content.push(`New Account: ${operation.accountName}`);
+ });
+ },
+ error: (err) => {
+ console.error(err);
+ reject(err);
+ },
+ complete: () => resolve(content)
+ });
+ }, true);
+
+ expect(result).toEqual([
+ "Follow: [\"reblog\",{\"account\":\"cribbio\",\"author\":\"donasycafe\",\"permlink\":\"feliz-4o-aniversario-mi-historia\"}]",
+ "Follow: [\"reblog\",{\"account\":\"gasaeightyfive\",\"author\":\"donasycafe\",\"permlink\":\"feliz-4o-aniversario-mi-historia\"}]",
+ "Reblog: [\"reblog\",{\"account\":\"dehai\",\"author\":\"rubenjr\",\"permlink\":\"hello-its-me-what-can-a-father-do\"}]",
+ "New Account: ayasolene20"
+ ]);
+ });
+
+ test("1.6 - Should be able to create content creator dashboard", async({ createWorkerBeeTest }) => {
+ const result = await createWorkerBeeTest((bot, resolve, reject) => {
+ const content: string[] = [];
+
+ bot
+ .providePastOperations(97547200, 97547250)
+ .onPosts("thebeedevs")
+ .or.onComments("thebeedevs")
+ .or.onMention("thebeedevs")
+ .or.onReblog("thebeedevs")
+ .or.onVotes("thebeedevs")
+ .subscribe({
+ next(data) {
+ data.posts.thebeedevs?.forEach(({ operation }) => {
+ content.push(`Post: ${operation.author} - ${operation.permlink}`);
+ });
+
+ data.comments.thebeedevs?.forEach(({ operation }) => {
+ content.push(`Comment: ${operation.author} - ${operation.permlink}`);
+ });
+
+ data.mentioned.thebeedevs?.forEach((operation) => {
+ content.push(`Mention: ${operation.author} - ${operation.permlink}`);
+ });
+
+ data.reblogs.thebeedevs?.forEach(({ operation }) => {
+ content.push(`Reblog: ${operation.author} - ${operation.permlink}`);
+ });
+
+ data.votes.thebeedevs?.forEach(({ operation }) => {
+ content.push(`Vote: ${operation.voter} - ${operation.permlink}`);
+ });
+ },
+ error: (err) => {
+ console.error(err);
+ reject(err);
+ },
+ complete: () => resolve(content)
+ });
+ }, true);
+
+ expect(result).toEqual([
+ "Post: thebeedevs - meet-workerbee-the-easy-way-to-build-smart-blockchain-bots",
+ "Mention: thebeedevs - meet-workerbee-the-easy-way-to-build-smart-blockchain-bots",
+ "Vote: thebeedevs - meet-workerbee-the-easy-way-to-build-smart-blockchain-bots",
+ "Reblog: thebeedevs - meet-workerbee-the-easy-way-to-build-smart-blockchain-bots"
+ ]);
+ });
+
+ test("1.7 - Should be able to create market movement detector", async({ createWorkerBeeTest }) => {
+ const result = await createWorkerBeeTest((bot, resolve, reject) => {
+ const content: string[] = [];
+
+ bot
+ .providePastOperations(97347545, 97347555)
+ .or.onWhaleAlert(bot.chain!.hiveCoins(10000))
+ .or.onInternalMarketOperation()
+ .or.onExchangeTransfer()
+ .subscribe({
+ next(data) {
+ data.whaleOperations.forEach(({ operation }) => {
+ content.push(`Whale Alert: ${operation.from} -> ${operation.to} - ${operation.amount.amount}`);
+ });
+
+ data.internalMarketOperations.forEach(({ operation }) => {
+ content.push(`Internal Market Operation: ${operation.owner} - ${operation.orderId}`);
+ });
+
+ data.exchangeTransferOperations.forEach(({ operation }) => {
+ content.push(`Exchange Transfer: ${operation.from} -> ${operation.to} - ${operation.amount.amount}`);
+ });
+ },
+ error: (err) => {
+ console.error(err);
+ reject(err);
+ },
+ complete: () => resolve(content)
+ });
+ }, true);
+
+ expect(result).toEqual([
+ "Whale Alert: huobi-pro -> huobi-withdrawal - 1598290",
+ "Exchange Transfer: huobi-pro -> huobi-withdrawal - 1598290",
+ "Whale Alert: aerrilee -> checkyzk - 2",
+ "Internal Market Operation: daverick - 1751626472"
+ ]);
+ });
+
+ test("2.1 - Should be able to create pattern analysis bot", async({ createWorkerBeeTest }) => {
+ const result = await createWorkerBeeTest((bot, resolve, reject) => {
+ const content: string[] = [];
+
+ bot
+ .providePastOperations(97547200, 97547250)
+ .onVotes("thebeedevs")
+ .or.onPosts("thebeedevs")
+ .subscribe({
+ next(data) {
+ data.votes.thebeedevs?.forEach(({ operation }) => {
+ content.push(`Vote: ${operation.voter} - ${operation.permlink}`);
+ });
+
+ data.posts.thebeedevs?.forEach(({ operation }) => {
+ content.push(`Post: ${operation.author} - ${operation.permlink}`);
+ });
+ },
+ error: (err) => {
+ console.error(err);
+ reject(err);
+ },
+ complete: () => resolve(content)
+ });
+ }, true);
+
+ expect(result).toEqual([
+ "Post: thebeedevs - meet-workerbee-the-easy-way-to-build-smart-blockchain-bots",
+ "Vote: thebeedevs - meet-workerbee-the-easy-way-to-build-smart-blockchain-bots"
+ ]);
+ });
+
+ test("2.2 - Should be able to create market trend analyzer", async({ createWorkerBeeTest }) => {
+ const result = await createWorkerBeeTest((bot, resolve, reject) => {
+ const content: string[] = [];
+
+ bot
+ .providePastOperations(97347545, 97347555)
+ .onWhaleAlert(bot.chain!.hiveCoins(10000))
+ .or.onInternalMarketOperation()
+ .subscribe({
+ next(data) {
+ data.whaleOperations.forEach(({ operation }) => {
+ content.push(`Whale Alert: ${operation.from} -> ${operation.to} - ${operation.amount.amount}`);
+ });
+
+ data.internalMarketOperations.forEach(({ operation }) => {
+ content.push(`Internal Market: ${operation.owner} - ${operation.orderId}`);
+ });
+ },
+ error: (err) => {
+ console.error(err);
+ reject(err);
+ },
+ complete: () => resolve(content)
+ });
+ }, true);
+
+ expect(result).toEqual([
+ "Whale Alert: huobi-pro -> huobi-withdrawal - 1598290",
+ "Whale Alert: aerrilee -> checkyzk - 2",
+ "Internal Market: daverick - 1751626472",
+ ]);
+ });
+
+ test("2.3 - Should be able to create community growth monitor", async({ createWorkerBeeTest }) => {
+ const result = await createWorkerBeeTest((bot, resolve, reject) => {
+ const content: string[] = [];
+
+ bot
+ .providePastOperations(97664610, 97664620)
+ .onNewAccount()
+ .or.onFollow("thebeedevs")
+ .or.onCustomOperation("follow")
+ .subscribe({
+ next(data) {
+ data.newAccounts.forEach((operation) => {
+ content.push(`New Account: ${operation.accountName}`);
+ });
+
+ data.follows.thebeedevs?.forEach(({ operation }) => {
+ content.push(`Follow: ${operation.follower} -> ${operation.following}`);
+ });
+
+ data.customOperations.follow?.forEach(({ operation }) => {
+ content.push(`Custom Follow: ${(operation as custom_json).json}`);
+ });
+ },
+ error: (err) => {
+ console.error(err);
+ reject(err);
+ },
+ complete: () => resolve(content)
+ });
+ }, true);
+
+ expect(result).toEqual([
+ "Custom Follow: [\"follow\",{\"follower\":\"dehai\",\"following\":\"rubenjr\",\"what\":[\"blog\"]}]",
+ "Custom Follow: [\"follow\",{\"follower\":\"dehai\",\"following\":\"rubenjr\",\"what\":[]}]",
+ "Custom Follow: [\"follow\",{\"follower\":\"dehai\",\"following\":\"rubenjr\",\"what\":[\"blog\"]}]",
+ "Custom Follow: [\"reblog\",{\"account\":\"cribbio\",\"author\":\"donasycafe\",\"permlink\":\"feliz-4o-aniversario-mi-historia\"}]",
+ "New Account: ayasolene20",
+ "Custom Follow: [\"reblog\",{\"account\":\"gasaeightyfive\",\"author\":\"donasycafe\",\"permlink\":\"feliz-4o-aniversario-mi-historia\"}]"
+ ]);
+ });
+
+ test("2.4 - Should be able to create content performance analyzer", async({ createWorkerBeeTest }) => {
+ const result = await createWorkerBeeTest((bot, resolve, reject) => {
+ const content: string[] = [];
+
+ bot
+ .providePastOperations(97547200, 97547250)
+ .onPosts("thebeedevs")
+ .or.onComments("thebeedevs")
+ .or.onVotes("thebeedevs")
+ .subscribe({
+ next(data) {
+ data.posts.thebeedevs?.forEach(({ operation }) => {
+ content.push(`Post: ${operation.author} - ${operation.permlink}`);
+ });
+
+ data.comments.thebeedevs?.forEach(({ operation }) => {
+ content.push(`Comment: ${operation.author} - ${operation.permlink}`);
+ });
+
+ data.votes.thebeedevs?.forEach(({ operation }) => {
+ content.push(`Vote: ${operation.voter} - ${operation.permlink}`);
+ });
+ },
+ error: (err) => {
+ console.error(err);
+ reject(err);
+ },
+ complete: () => resolve(content)
+ });
+ }, true);
+
+ expect(result).toEqual([
+ "Post: thebeedevs - meet-workerbee-the-easy-way-to-build-smart-blockchain-bots",
+ "Vote: thebeedevs - meet-workerbee-the-easy-way-to-build-smart-blockchain-bots"
+ ]);
+ });
+
+ test("2.5 - Should be able to create economic activity tracker", async({ createWorkerBeeTest }) => {
+ const result = await createWorkerBeeTest((bot, resolve, reject) => {
+ const content: string[] = [];
+
+ bot
+ .providePastOperations(97347575, 97347585)
+ .onWhaleAlert(bot.chain!.hiveCoins(1000))
+ .or.onExchangeTransfer()
+ .or.onInternalMarketOperation()
+ .subscribe({
+ next(data) {
+ data.whaleOperations.forEach(({ operation }) => {
+ content.push(`Whale: ${operation.from} -> ${operation.to} - ${operation.amount.amount}`);
+ });
+
+ data.exchangeTransferOperations.forEach(({ operation }) => {
+ content.push(`Exchange: ${operation.from} -> ${operation.to} - ${operation.amount.amount}`);
+ });
+
+ data.internalMarketOperations.forEach(({ operation }) => {
+ content.push(`Market: ${operation.owner} - ${operation.orderId}`);
+ });
+ },
+ error: (err) => {
+ console.error(err);
+ reject(err);
+ },
+ complete: () => resolve(content)
+ });
+ }, true);
+
+ expect(result).toEqual([
+ "Whale: honey-swap -> hive-engine - 403",
+ "Whale: honey-swap -> luluwinda - 53308",
+ "Market: honeybot - 243293707",
+ "Market: honeybot - 1485200410",
+ "Whale: mxchive -> inhivepool - 23890",
+ "Exchange: mxchive -> inhivepool - 23890"
+ ]);
+ });
+
+ test("2.6 - Should be able to create account behavior analysis", async({ createWorkerBeeTest }) => {
+ const result = await createWorkerBeeTest((bot, resolve, reject) => {
+ const content: string[] = [];
+
+ bot
+ .providePastOperations(97547200, 97547250)
+ .onPosts("thebeedevs")
+ .or.onVotes("thebeedevs")
+ .or.onFollow("thebeedevs")
+ .or.onReblog("thebeedevs")
+ .subscribe({
+ next(data) {
+ data.posts.thebeedevs?.forEach(({ operation }) => {
+ content.push(`Post: ${operation.author} - ${operation.permlink}`);
+ });
+
+ data.votes.thebeedevs?.forEach(({ operation }) => {
+ content.push(`Vote: ${operation.voter} - ${operation.permlink}`);
+ });
+
+ data.follows.thebeedevs?.forEach(({ operation }) => {
+ content.push(`Follow: ${operation.follower} -> ${operation.following}`);
+ });
+
+ data.reblogs.thebeedevs?.forEach(({ operation }) => {
+ content.push(`Reblog: ${operation.author} - ${operation.permlink}`);
+ });
+ },
+ error: (err) => {
+ console.error(err);
+ reject(err);
+ },
+ complete: () => resolve(content)
+ });
+ }, true);
+
+ expect(result).toEqual([
+ "Post: thebeedevs - meet-workerbee-the-easy-way-to-build-smart-blockchain-bots",
+ "Vote: thebeedevs - meet-workerbee-the-easy-way-to-build-smart-blockchain-bots",
+ "Reblog: thebeedevs - meet-workerbee-the-easy-way-to-build-smart-blockchain-bots"
+ ]);
+ });
+});
diff --git a/__tests__/index.spec.ts b/__tests__/index.spec.ts
index 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..ac0d689abfc3246b719a8068627ad52fc041a294 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": [
{
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/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;
}
}
}