diff --git a/CHANGELOG.md b/CHANGELOG.md index d10586aad..916866fe2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,116 @@ -## [7.14.1](https://github.com/hirosystems/stacks-blockchain-api/compare/v7.14.0...v7.14.1) (2024-08-21) +## [8.0.3](https://github.com/hirosystems/stacks-blockchain-api/compare/v8.0.2...v8.0.3) (2024-10-01) ### Bug Fixes +* query param `until_block` not working in several endpoints ([#2101](https://github.com/hirosystems/stacks-blockchain-api/issues/2101)) ([fce15d6](https://github.com/hirosystems/stacks-blockchain-api/commit/fce15d68377b6fe5fabeab65b34bd4e7a8d3bef6)) + +## [8.0.2](https://github.com/hirosystems/stacks-blockchain-api/compare/v8.0.1...v8.0.2) (2024-09-27) + + +### Bug Fixes + +* tests ([689ff18](https://github.com/hirosystems/stacks-blockchain-api/commit/689ff183dd0bdd1779f0220835123a0cc99e37c6)) + + +## [8.0.2-beta.1](https://github.com/hirosystems/stacks-blockchain-api/compare/v8.0.1...v8.0.2-beta.1) (2024-09-26) + +### Bug Fixes + +* use current circulating STX tokens for `stx_supply` endpoint, year 2050 estimate in new field ([b3e08e7](https://github.com/hirosystems/stacks-blockchain-api/commit/b3e08e7872c4a6b5a076d8bbcc22eb388ecef5ab)) + +## [8.0.1](https://github.com/hirosystems/stacks-blockchain-api/compare/v8.0.0...v8.0.1) (2024-09-23) + + +### Bug Fixes + +* package.json & package-lock.json to reduce vulnerabilities ([159d0ca](https://github.com/hirosystems/stacks-blockchain-api/commit/159d0ca1a2b55017883661b5c6ffb3cf5aefeb9f)) + +## [8.0.0](https://github.com/hirosystems/stacks-blockchain-api/compare/v7.14.1...v8.0.0) (2024-08-28) + + +### ⚠ BREAKING CHANGES + +> [!NOTE] +> This is only a breaking change because significant changes were made to the JavaScript client library's interface and how its types are generated, and because its library version always matches the API version. +> There are **no changes** to endpoints or database schemas that necessitate a full Stacks node event replay i.e. you may upgrade to v8.0.0 from v7.x directly. + +* refactor from express to fastify (#2045) +* refactor from Express to Fastify + +### Features + +* cursor-based pagination on blocks endpoint ([#2060](https://github.com/hirosystems/stacks-blockchain-api/issues/2060)) ([bfdcce1](https://github.com/hirosystems/stacks-blockchain-api/commit/bfdcce1c2936980299c90bf36f3d45fe74bd573c)) +* export events tsv directly to postgres instance ([#2048](https://github.com/hirosystems/stacks-blockchain-api/issues/2048)) ([f401a0f](https://github.com/hirosystems/stacks-blockchain-api/commit/f401a0f676ced14572b9f3f263dcc8559e831cdf)) +* refactor from Express to Fastify ([aa0e51e](https://github.com/hirosystems/stacks-blockchain-api/commit/aa0e51e557491daff1a98dd36c4e952e05c58dd4)), closes [#2042](https://github.com/hirosystems/stacks-blockchain-api/issues/2042) +* refactor from express to fastify ([#2045](https://github.com/hirosystems/stacks-blockchain-api/issues/2045)) ([bd65fcf](https://github.com/hirosystems/stacks-blockchain-api/commit/bd65fcf93984c37a9de3cb284c43a49cb6b3694a)), closes [#2042](https://github.com/hirosystems/stacks-blockchain-api/issues/2042) + + +### Bug Fixes + +* missing event limit max overrides on a few endpoints ([4f70930](https://github.com/hirosystems/stacks-blockchain-api/commit/4f709308fb95721866b523142536b738aa64a3eb)) +* pagination and query param parsing bugs ([a382d2b](https://github.com/hirosystems/stacks-blockchain-api/commit/a382d2b80fc8d3e7ff49ce96047f1621749172b2)), closes [#2042](https://github.com/hirosystems/stacks-blockchain-api/issues/2042) +* perform status endpoint sql inside transactions ([b23445c](https://github.com/hirosystems/stacks-blockchain-api/commit/b23445c85f826d0e6cf98695f985c3670d00c1db)) +* tx event-limit default should be 100 ([32d0670](https://github.com/hirosystems/stacks-blockchain-api/commit/32d0670a531582b8eb269790fa7a3695a8ce7610)) + +## [8.0.0-beta.6](https://github.com/hirosystems/stacks-blockchain-api/compare/v8.0.0-beta.5...v8.0.0-beta.6) (2024-08-27) + + +### ⚠ BREAKING CHANGES + +* refactor from express to fastify (#2045) + +### Features + +* cursor-based pagination on blocks endpoint ([#2060](https://github.com/hirosystems/stacks-blockchain-api/issues/2060)) ([bfdcce1](https://github.com/hirosystems/stacks-blockchain-api/commit/bfdcce1c2936980299c90bf36f3d45fe74bd573c)) +* export events tsv directly to postgres instance ([#2048](https://github.com/hirosystems/stacks-blockchain-api/issues/2048)) ([f401a0f](https://github.com/hirosystems/stacks-blockchain-api/commit/f401a0f676ced14572b9f3f263dcc8559e831cdf)) +* export events tsv directly to postgres instance ([#2048](https://github.com/hirosystems/stacks-blockchain-api/issues/2048)) ([#2058](https://github.com/hirosystems/stacks-blockchain-api/issues/2058)) ([a1f5b12](https://github.com/hirosystems/stacks-blockchain-api/commit/a1f5b12675118f6d7742c54e3420c38151aef4a7)) +* refactor from express to fastify ([#2045](https://github.com/hirosystems/stacks-blockchain-api/issues/2045)) ([bd65fcf](https://github.com/hirosystems/stacks-blockchain-api/commit/bd65fcf93984c37a9de3cb284c43a49cb6b3694a)), closes [#2042](https://github.com/hirosystems/stacks-blockchain-api/issues/2042) + + +### Bug Fixes + +* index on `principal_stx_txs` table for faster `/v1/address/{addr}/transactions` lookups ([#2059](https://github.com/hirosystems/stacks-blockchain-api/issues/2059)) ([ab64ab7](https://github.com/hirosystems/stacks-blockchain-api/commit/ab64ab7148a3656f81f0a3c5a176c40caca3345a)) + +## [8.0.0-beta.5](https://github.com/hirosystems/stacks-blockchain-api/compare/v8.0.0-beta.4...v8.0.0-beta.5) (2024-08-16) + + +### Bug Fixes + +* perform status endpoint sql inside transactions ([b23445c](https://github.com/hirosystems/stacks-blockchain-api/commit/b23445c85f826d0e6cf98695f985c3670d00c1db)) + +## [8.0.0-beta.4](https://github.com/hirosystems/stacks-blockchain-api/compare/v8.0.0-beta.3...v8.0.0-beta.4) (2024-08-15) + + +### Bug Fixes + +* missing event limit max overrides on a few endpoints ([4f70930](https://github.com/hirosystems/stacks-blockchain-api/commit/4f709308fb95721866b523142536b738aa64a3eb)) + +## [8.0.0-beta.3](https://github.com/hirosystems/stacks-blockchain-api/compare/v8.0.0-beta.2...v8.0.0-beta.3) (2024-08-15) + + +### Bug Fixes + +* tx event-limit default should be 100 ([32d0670](https://github.com/hirosystems/stacks-blockchain-api/commit/32d0670a531582b8eb269790fa7a3695a8ce7610)) + +## [8.0.0-beta.2](https://github.com/hirosystems/stacks-blockchain-api/compare/v8.0.0-beta.1...v8.0.0-beta.2) (2024-08-15) + + +### Bug Fixes + +* pagination and query param parsing bugs ([a382d2b](https://github.com/hirosystems/stacks-blockchain-api/commit/a382d2b80fc8d3e7ff49ce96047f1621749172b2)), closes [#2042](https://github.com/hirosystems/stacks-blockchain-api/issues/2042) + +## [8.0.0-beta.1](https://github.com/hirosystems/stacks-blockchain-api/compare/v7.13.2...v8.0.0-beta.1) (2024-08-13) + + +### ⚠ BREAKING CHANGES + +* refactor from Express to Fastify + +### Features + +* refactor from Express to Fastify ([aa0e51e](https://github.com/hirosystems/stacks-blockchain-api/commit/aa0e51e557491daff1a98dd36c4e952e05c58dd4)), closes [#2042](https://github.com/hirosystems/stacks-blockchain-api/issues/2042) + * index on `principal_stx_txs` table for faster `/v1/address/{addr}/transactions` lookups ([#2059](https://github.com/hirosystems/stacks-blockchain-api/issues/2059)) ([ab64ab7](https://github.com/hirosystems/stacks-blockchain-api/commit/ab64ab7148a3656f81f0a3c5a176c40caca3345a)) ## [7.14.0](https://github.com/hirosystems/stacks-blockchain-api/compare/v7.13.2...v7.14.0) (2024-08-20) diff --git a/README.md b/README.md index 9be736f79..cfc15e4ad 100644 --- a/README.md +++ b/README.md @@ -9,11 +9,11 @@ ### Local -This service requires `postgres`, `stacks-node`, `bitcoind`, and a few other components in order to run. +This service requires `postgres`, `stacks-node`, `bitcoind`, and a few other components in order to run. The [`clarinet`](https://github.com/hirosystems/clarinet) project provides an easy way to spin up the API and all these services: > clarinet devnet - a local standalone development environment that simulates Bitcoin, Stacks node and other helpful components, similar to a staging environment. -Get started at https://docs.hiro.so/clarinet/getting-started +Get started at https://docs.hiro.so/clarinet/getting-started ### Production @@ -36,7 +36,7 @@ Check to see if the server started successfully by visiting http://localhost:399 ## Local Development -To run the server, run `npm run dev:integrated`, which uses docker-compose to deploy the service dependencies (e.g., PostgreSQL, Stacks core node, etc.). +To run the server, run `npm run dev:integrated`, which uses docker-compose to deploy the service dependencies (e.g., PostgreSQL, Stacks core node, etc.). You'll have a server on port 3999. @@ -52,7 +52,7 @@ We recommend running the API database on PostgreSQL version 14 or newer for opti ## Upgrading -If upgrading the API to a new major version (e.g., `3.0.0` to `4.0.0`), then the Postgres database from the previous version will not be compatible, and the process will fail to start. +If upgrading the API to a new major version (e.g., `3.0.0` to `4.0.0`), then the Postgres database from the previous version will likely be incompatible, and the process will fail to start. However, in some cases, the major versions are for client library changes (which are synced with the api version number). Check the changelog if you're unclear. [Event Replay](#event-replay) must be used when upgrading major versions. Follow the event replay [instructions](#event-replay-instructions) below. Failure to do so will require wiping the Stacks Blockchain chain state data and the API Postgres database and re-syncing from scratch. @@ -170,7 +170,7 @@ To run the new event-replay, please follow the instructions at [stacks-event-rep * `archival` (default): The process will import and ingest *all* blockchain events that have happened since the first block. * `pruned`: The import process will ignore some prunable events (mempool, microblocks) until the - import block height has reached `chain tip - 256` blocks. This saves considerable + import block height has reached `chain tip - 256` blocks. This saves considerable time during import but sacrifices some historical data. You can use this mode if you're mostly interested in running an API that prioritizes real-time information. @@ -189,7 +189,7 @@ Please **do not** use the issue tracker for personal support requests or to ask Development of this product happens in the open on GitHub, and we are grateful to the community for contributing bug fixes and improvements. Read below to learn how you can take part in improving the product. ### Code of Conduct -Please read our [Code of Conduct](../../../.github/blob/main/CODE_OF_CONDUCT.md) since we expect project participants to adhere to it. +Please read our [Code of Conduct](../../../.github/blob/main/CODE_OF_CONDUCT.md) since we expect project participants to adhere to it. ### Contributing Guide @@ -199,7 +199,7 @@ Hiro welcomes all contributions to Hiro documentation. These contributions come Bugs, feature requests, and development-related questions should be directed to our [GitHub issues tracker](https://github.com/hirosystems/stacks-blockchain-api/issues/new). -If reporting a bug, try to provide as much context as possible and anything else that might be relevant to the describe the issue. If possible include a simple test case that we can use to reproduce the problem on our own. +If reporting a bug, try to provide as much context as possible and anything else that might be relevant to the describe the issue. If possible include a simple test case that we can use to reproduce the problem on our own. For feature requests, please explain what you're trying to do, and how the requested feature would be a complement to the project. diff --git a/package-lock.json b/package-lock.json index e7fd835fa..0a0cb58de 100644 --- a/package-lock.json +++ b/package-lock.json @@ -62,7 +62,7 @@ "postgres": "3.3.1", "prom-client": "15.1.3", "rpc-bitcoin": "2.0.0", - "socket.io": "4.6.2", + "socket.io": "^4.8.0", "source-map-support": "0.5.21", "split2": "3.2.2", "stacks-encoding-native-js": "1.1.0-beta.7", @@ -3626,7 +3626,8 @@ "node_modules/@types/cookie": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", + "license": "MIT" }, "node_modules/@types/cookiejar": { "version": "2.1.5", @@ -5075,6 +5076,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "license": "MIT", "engines": { "node": "^4.5.0 || >= 5.9" } @@ -6871,9 +6873,10 @@ } }, "node_modules/engine.io": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.4.2.tgz", - "integrity": "sha512-FKn/3oMiJjrOEOeUub2WCox6JhxBXq/Zn3fZOMCBxKnNYtsdKjxhl7yR3fZhM9PV+rdE75SU5SYMc+2PGzo+Tg==", + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.1.tgz", + "integrity": "sha512-NEpDCw9hrvBW+hVEOK4T7v0jFJ++KgtPl4jKFwsZVfG1XhS0dCrSb3VMb9gPAd7VAdW52VT1EnaNiU2vM8C0og==", + "license": "MIT", "dependencies": { "@types/cookie": "^0.4.1", "@types/cors": "^2.8.12", @@ -6883,11 +6886,11 @@ "cookie": "~0.4.1", "cors": "~2.8.5", "debug": "~4.3.1", - "engine.io-parser": "~5.0.3", - "ws": "~8.11.0" + "engine.io-parser": "~5.2.1", + "ws": "~8.17.1" }, "engines": { - "node": ">=10.0.0" + "node": ">=10.2.0" } }, "node_modules/engine.io-client": { @@ -6928,6 +6931,7 @@ "version": "5.0.7", "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.7.tgz", "integrity": "sha512-P+jDFbvK6lE3n1OL+q9KuzdOFWkkZ/cMV9gol/SbVfpyqfvrfrFTOFJ6fQm2VC3PZHlU3QPhVwmbsCnauHF2MQ==", + "dev": true, "engines": { "node": ">=10.0.0" } @@ -6936,20 +6940,31 @@ "version": "0.4.2", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "license": "MIT", "engines": { "node": ">= 0.6" } }, + "node_modules/engine.io/node_modules/engine.io-parser": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/engine.io/node_modules/ws": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", - "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "license": "MIT", "engines": { "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { @@ -15599,20 +15614,21 @@ } }, "node_modules/socket.io": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.6.2.tgz", - "integrity": "sha512-Vp+lSks5k0dewYTfwgPT9UeGGd+ht7sCpB7p0e83VgO4X/AHYWhXITMrNk/pg8syY2bpx23ptClCQuHhqi2BgQ==", + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.0.tgz", + "integrity": "sha512-8U6BEgGjQOfGz3HHTYaC/L1GaxDCJ/KM0XTkJly0EhZ5U/du9uNEZy4ZgYzEzIqlx2CMm25CrCqr1ck899eLNA==", "license": "MIT", "dependencies": { "accepts": "~1.3.4", "base64id": "~2.0.0", + "cors": "~2.8.5", "debug": "~4.3.2", - "engine.io": "~6.4.2", + "engine.io": "~6.6.0", "socket.io-adapter": "~2.5.2", "socket.io-parser": "~4.2.4" }, "engines": { - "node": ">=10.0.0" + "node": ">=10.2.0" } }, "node_modules/socket.io-adapter": { diff --git a/package.json b/package.json index 308683eb1..8fd46275c 100644 --- a/package.json +++ b/package.json @@ -140,7 +140,7 @@ "postgres": "3.3.1", "prom-client": "15.1.3", "rpc-bitcoin": "2.0.0", - "socket.io": "4.6.2", + "socket.io": "4.8.0", "source-map-support": "0.5.21", "split2": "3.2.2", "stacks-encoding-native-js": "1.1.0-beta.7", diff --git a/src/api/query-helpers.ts b/src/api/query-helpers.ts index b36ab0814..c782734be 100644 --- a/src/api/query-helpers.ts +++ b/src/api/query-helpers.ts @@ -41,10 +41,10 @@ export function parseUntilBlockQuery( ): undefined | number | string { if (!untilBlock) return; if (typeof untilBlock === 'string') { - if (unanchored !== undefined) { + if (unanchored) { // if mutually exclusive unachored is also specified, throw bad request error throw new InvalidRequestError( - `can't handle both 'unanchored' and 'until_block' in the same request`, + `can't handle both 'unanchored=true' and 'until_block' in the same request`, InvalidRequestErrorType.bad_request ); } diff --git a/src/api/routes/stx-supply.ts b/src/api/routes/stx-supply.ts index 9d19666ca..52c45321f 100644 --- a/src/api/routes/stx-supply.ts +++ b/src/api/routes/stx-supply.ts @@ -1,5 +1,5 @@ import BigNumber from 'bignumber.js'; -import { microStxToStx, STACKS_DECIMAL_PLACES, TOTAL_STACKS } from '../../helpers'; +import { microStxToStx, STACKS_DECIMAL_PLACES, TOTAL_STACKS_YEAR_2050 } from '../../helpers'; import { handleChainTipCache } from '../controllers/cache-controller'; import { FastifyPluginAsync } from 'fastify'; @@ -23,18 +23,23 @@ export const StxSupplyRoutes: FastifyPluginAsync< ): Promise<{ unlockedPercent: string; totalStx: string; + totalStxYear2050: string; unlockedStx: string; blockHeight: number; }> { const { stx: unlockedSupply, blockHeight } = await fastify.db.getUnlockedStxSupply(args); - const totalMicroStx = new BigNumber(TOTAL_STACKS).shiftedBy(STACKS_DECIMAL_PLACES); + const totalMicroStx = unlockedSupply; + const totalMicroStxYear2050 = new BigNumber(TOTAL_STACKS_YEAR_2050).shiftedBy( + STACKS_DECIMAL_PLACES + ); const unlockedPercent = new BigNumber(unlockedSupply.toString()) - .div(totalMicroStx) + .div(new BigNumber(totalMicroStx.toString())) .times(100) .toFixed(2); return { unlockedPercent, totalStx: microStxToStx(totalMicroStx), + totalStxYear2050: microStxToStx(totalMicroStxYear2050), unlockedStx: microStxToStx(unlockedSupply), blockHeight: blockHeight, }; @@ -47,8 +52,7 @@ export const StxSupplyRoutes: FastifyPluginAsync< schema: { operationId: 'get_stx_supply', summary: 'Get total and unlocked STX supply', - description: `Retrieves the total and unlocked STX supply. More information on Stacking can be found [here] (https://docs.stacks.co/understand-stacks/stacking). - **Note:** This uses the estimated future total supply for the year 2050.`, + description: `Retrieves the total and unlocked STX supply. More information on Stacking can be found [here] (https://docs.stacks.co/understand-stacks/stacking).`, tags: ['Info'], querystring: Type.Object({ height: Type.Optional( @@ -70,7 +74,12 @@ export const StxSupplyRoutes: FastifyPluginAsync< 'String quoted decimal number of the percentage of STX that have unlocked', }), total_stx: Type.String({ - description: 'String quoted decimal number of the total possible number of STX', + description: + 'String quoted decimal number of the total circulating number of STX (at the input block height if provided, otherwise the current block height)', + }), + total_stx_year_2050: Type.String({ + description: + 'String quoted decimal number of total circulating STX supply in year 2050. STX supply grows approx 0.3% annually thereafter in perpetuity.', }), unlocked_stx: Type.String({ description: @@ -98,6 +107,7 @@ export const StxSupplyRoutes: FastifyPluginAsync< await reply.send({ unlocked_percent: supply.unlockedPercent, total_stx: supply.totalStx, + total_stx_year_2050: supply.totalStxYear2050, unlocked_stx: supply.unlockedStx, block_height: supply.blockHeight, }); @@ -109,10 +119,10 @@ export const StxSupplyRoutes: FastifyPluginAsync< { preHandler: handleChainTipCache, schema: { + deprecated: true, operationId: 'get_stx_supply_total_supply_plain', summary: 'Get total STX supply in plain text format', - description: `Retrieves the total supply for STX tokens as plain text. - **Note:** this uses the estimated future total supply for the year 2050.`, + description: `Retrieves the total circulating STX token supply as plain text.`, tags: ['Info'], response: { 200: { @@ -136,6 +146,7 @@ export const StxSupplyRoutes: FastifyPluginAsync< { preHandler: handleChainTipCache, schema: { + deprecated: true, operationId: 'get_stx_supply_circulating_plain', summary: 'Get circulating STX supply in plain text format', description: `Retrieves the STX tokens currently in circulation that have been unlocked as plain text.`, @@ -162,11 +173,11 @@ export const StxSupplyRoutes: FastifyPluginAsync< { preHandler: handleChainTipCache, schema: { + deprecated: true, operationId: 'get_total_stx_supply_legacy_format', summary: 'Get total and unlocked STX supply (results formatted the same as the legacy 1.0 API)', - description: `Retrieves total supply of STX tokens including those currently in circulation that have been unlocked. - **Note:** this uses the estimated future total supply for the year 2050.`, + description: `Retrieves total supply of STX tokens including those currently in circulation that have been unlocked.`, tags: ['Info'], querystring: Type.Object({ height: Type.Optional( @@ -188,11 +199,20 @@ export const StxSupplyRoutes: FastifyPluginAsync< 'String quoted decimal number of the percentage of STX that have unlocked', }), totalStacks: Type.String({ - description: 'String quoted decimal number of the total possible number of STX', + description: + 'String quoted decimal number of the total circulating number of STX (at the input block height if provided, otherwise the current block height)', }), totalStacksFormatted: Type.String({ description: 'Same as `totalStacks` but formatted with comma thousands separators', }), + totalStacksYear2050: Type.String({ + description: + 'String quoted decimal number of total circulating STX supply in year 2050. STX supply grows approx 0.3% annually thereafter in perpetuity.', + }), + totalStacksYear2050Formatted: Type.String({ + description: + 'Same as `totalStacksYear2050` but formatted with comma thousands separators', + }), unlockedSupply: Type.String({ description: 'String quoted decimal number of the STX that have been mined or unlocked', @@ -224,6 +244,11 @@ export const StxSupplyRoutes: FastifyPluginAsync< unlockedPercent: supply.unlockedPercent, totalStacks: supply.totalStx, totalStacksFormatted: new BigNumber(supply.totalStx).toFormat(STACKS_DECIMAL_PLACES, 8), + totalStacksYear2050: supply.totalStxYear2050, + totalStacksYear2050Formatted: new BigNumber(supply.totalStxYear2050).toFormat( + STACKS_DECIMAL_PLACES, + 8 + ), unlockedSupply: supply.unlockedStx, unlockedSupplyFormatted: new BigNumber(supply.unlockedStx).toFormat( STACKS_DECIMAL_PLACES, diff --git a/src/api/routes/ws/channels/socket-io-channel.ts b/src/api/routes/ws/channels/socket-io-channel.ts index 20c72e82c..9d373e281 100644 --- a/src/api/routes/ws/channels/socket-io-channel.ts +++ b/src/api/routes/ws/channels/socket-io-channel.ts @@ -123,7 +123,9 @@ export class SocketIOChannel extends WebSocketChannel { if (!this.io && callback) { callback(); } - this.io?.close(callback); + this.io?.close(callback).catch(err => { + logger.error(err, `Error closing socket.io`); + }); this.io = undefined; } diff --git a/src/helpers.ts b/src/helpers.ts index 9301aeff5..a80efb657 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -169,7 +169,7 @@ export function formatMapToObject( // > 500 STX/block for following 4 yrs; // > 250 for the 4 yrs after that; and then 125 STX/block in perpetuity after that. // We are going to use the year 2050 projected supply because "125 STX/block in perpetuity" means the total supply is infinite. -export const TOTAL_STACKS = new BigNumber(1_818_000_000n.toString()); +export const TOTAL_STACKS_YEAR_2050 = new BigNumber(1_818_000_000n.toString()); const MICROSTACKS_IN_STACKS = 1_000_000n; export const STACKS_DECIMAL_PLACES = 6; diff --git a/tests/api/address.test.ts b/tests/api/address.test.ts index 2a9c7c4d2..e031343fe 100644 --- a/tests/api/address.test.ts +++ b/tests/api/address.test.ts @@ -1580,6 +1580,12 @@ describe('address tests', () => { }; expect(JSON.parse(fetchAddrBalance1.text)).toEqual(expectedResp1); + const fetchAddrBalance1AtBlock = await supertest(api.server).get( + `/extended/v1/address/${testAddr2}/balances?until_block=1` + ); + expect(fetchAddrBalance1AtBlock.status).toBe(200); + expect(fetchAddrBalance1AtBlock.type).toBe('application/json'); + const fetchAddrBalance2 = await supertest(api.server).get( `/extended/v1/address/${testContractAddr}/balances` ); @@ -2621,16 +2627,6 @@ describe('address tests', () => { ); expect(response.status).toBe(400); } - - const addressEndpoints1 = ['/transactions', '/transactions_with_transfers', '/stx_inbound']; - - /// check for mutually exclusive until_block adn height params - for (const path of addressEndpoints1) { - const response1 = await supertest(api.server).get( - `/extended/v1/address/STB44HYPYAT2BB2QE513NSP81HTMYWBJP02HPGK6${path}?until_block=5&height=0` - ); - expect(response1.status).toBe(400); - } }); test('/transactions materialized view separates anchored and unanchored counts correctly', async () => { diff --git a/tests/api/other.test.ts b/tests/api/other.test.ts index 86f8de19b..fc7974c9f 100644 --- a/tests/api/other.test.ts +++ b/tests/api/other.test.ts @@ -141,11 +141,13 @@ describe('other tests', () => { expect(result1.status).toBe(200); expect(result1.type).toBe('application/json'); const expectedResp1 = { - unlocked_percent: '12.93', - total_stx: '1818000000.000000', - unlocked_stx: microStxToStx(expectedTotalStx1), - block_height: dbBlock1.block_height, + unlocked_percent: '100.00', + total_stx: '235000000.000000', + total_stx_year_2050: '1818000000.000000', + unlocked_stx: '235000000.000000', + block_height: 1, }; + expect(JSON.parse(result1.text)).toEqual(expectedResp1); // ensure burned STX reduce the unlocked stx supply @@ -166,9 +168,10 @@ describe('other tests', () => { expect(result2.status).toBe(200); expect(result2.type).toBe('application/json'); const expectedResp2 = { - unlocked_percent: '12.38', - total_stx: '1818000000.000000', + unlocked_percent: '100.00', + total_stx: microStxToStx(expectedTotalStx2), unlocked_stx: microStxToStx(expectedTotalStx2), + total_stx_year_2050: '1818000000.000000', block_height: dbBlock1.block_height, }; expect(JSON.parse(result2.text)).toEqual(expectedResp2); @@ -197,8 +200,9 @@ describe('other tests', () => { expect(result3.status).toBe(200); expect(result3.type).toBe('application/json'); const expectedResp3 = { - unlocked_percent: '13.20', - total_stx: '1818000000.000000', + unlocked_percent: '100.00', + total_stx: microStxToStx(expectedTotalStx3), + total_stx_year_2050: '1818000000.000000', unlocked_stx: microStxToStx(expectedTotalStx3), block_height: dbBlock1.block_height, }; @@ -207,7 +211,7 @@ describe('other tests', () => { const result4 = await supertest(api.server).get(`/extended/v1/stx_supply/total/plain`); expect(result4.status).toBe(200); expect(result4.type).toBe('text/plain'); - expect(result4.text).toEqual('1818000000.000000'); + expect(result4.text).toEqual('240000000.000000'); const result5 = await supertest(api.server).get(`/extended/v1/stx_supply/circulating/plain`); expect(result5.status).toBe(200); @@ -219,13 +223,17 @@ describe('other tests', () => { expect(result6.status).toBe(200); expect(result6.type).toBe('application/json'); const expectedResp6 = { - unlockedPercent: '13.20', - totalStacks: '1818000000.000000', - totalStacksFormatted: '1,818,000,000.000000', + unlockedPercent: '100.00', + totalStacks: microStxToStx(expectedTotalStx3), + totalStacksFormatted: new Intl.NumberFormat('en', { + minimumFractionDigits: STACKS_DECIMAL_PLACES, + }).format(parseInt(microStxToStx(expectedTotalStx3))), unlockedSupply: microStxToStx(expectedTotalStx3), unlockedSupplyFormatted: new Intl.NumberFormat('en', { minimumFractionDigits: STACKS_DECIMAL_PLACES, }).format(parseInt(microStxToStx(expectedTotalStx3))), + totalStacksYear2050: '1818000000.000000', + totalStacksYear2050Formatted: '1,818,000,000.000000', blockHeight: dbBlock1.block_height.toString(), }; expect(JSON.parse(result6.text)).toEqual(expectedResp6);