diff --git a/.yarn/cache/@types-big.js-npm-6.1.2-736ff68e59-fb0daa4b23.zip b/.yarn/cache/@types-big.js-npm-6.1.2-736ff68e59-fb0daa4b23.zip new file mode 100644 index 0000000..63de651 Binary files /dev/null and b/.yarn/cache/@types-big.js-npm-6.1.2-736ff68e59-fb0daa4b23.zip differ diff --git a/.yarn/cache/big.js-npm-6.1.1-12b92a0f20-ba5db278e7.zip b/.yarn/cache/big.js-npm-6.1.1-12b92a0f20-ba5db278e7.zip new file mode 100644 index 0000000..cfaf012 Binary files /dev/null and b/.yarn/cache/big.js-npm-6.1.1-12b92a0f20-ba5db278e7.zip differ diff --git a/package.json b/package.json index 2c8c09b..ab06f9a 100644 --- a/package.json +++ b/package.json @@ -10,11 +10,13 @@ "@oclif/core": "1.0.4", "@oclif/plugin-help": "^5", "bech32": "^2.0.0", + "big.js": "^6.1.1", "cli-ux": "^5.6.4", "safe-stable-stringify": "^2.2.0", "tslib": "^1" }, "devDependencies": { + "@types/big.js": "^6.1.2", "@types/jest": "^27.0.3", "@types/node": "^14", "@typescript-eslint/eslint-plugin": "^5.4.0", diff --git a/src/commands/query/stake-distribution.ts b/src/commands/query/stake-distribution.ts index 1ce37f5..676cd1c 100644 --- a/src/commands/query/stake-distribution.ts +++ b/src/commands/query/stake-distribution.ts @@ -1,3 +1,5 @@ +import { Responses } from '@blockfrost/blockfrost-js'; +import Big from 'big.js'; import { cli } from 'cli-ux'; import { BaseCommand } from '../../helpers/BaseCommand'; @@ -40,72 +42,116 @@ import { BaseCommand } from '../../helpers/BaseCommand'; // "denominator": 20150911152895487 // }, // ... + +type Data = { + pool_id: string; + numerator: BigInt; + denominator: BigInt; +}; export class StakeDistribution extends BaseCommand { - // TODO: toFile method - prettyPrint = ( - res: { - pool_id: string; - live_stake: string; - }[], - ) => { + prettyPrint = (res: Data[]) => { + const calculatedData = res.map(stake => ({ + pool_id: stake.pool_id, + frac: Big(stake.numerator.toString()).div(Big(stake.denominator.toString())).toExponential(3), + })); this.log(); - cli.table( - res, - { - pool_id: { - header: 'PoolId', - minWidth: 30, + try { + cli.table( + calculatedData, + { + pool_id: { + header: 'PoolId', + minWidth: 30, + }, + frac: { + header: 'Stake frac', + }, }, - live_stake: { - header: 'Stake frac', - }, - }, - { printLine: this.log }, - ); + { printLine: console.log, 'no-truncate': true }, + ); + } catch (err) { + console.error(err); + } this.log(); }; + async toFile(data: Data[]): Promise { + const stakePerPool: Record< + string, + { + numerator: BigInt; + denominator: BigInt; + } + > = {}; + data.map(stake => { + stakePerPool[stake.pool_id] = { + numerator: stake.numerator, + denominator: stake.denominator, + }; + }); + super.toFile(stakePerPool); + } + doWork = async () => { const client = await this.getClient(); // TODO: refactor once we have proper endpoint for stake distribution - const pools = await client.poolsAll(); + const pools = (await client.poolsAll()).slice(0, 20); const allStakes: { pool_id: string; - live_stake: string; + live_stake: BigInt; }[] = []; const SMALL_BATCH = 10; const LARGE_BATCH = 100; let batch_size = LARGE_BATCH; + let stakesSum = BigInt(0); const getPromiseBundle = (startIndex: number, batchSize: number) => { - const promises = [...Array(batchSize).keys()].map(i => - client.poolsById(pools[startIndex + i]), - ); - return promises; + const promises = [...Array(batchSize).keys()].map(i => { + const poolId = pools[startIndex + i]; + return poolId ? client.poolsById(poolId) : undefined; + }); + return promises.filter(p => !!p) as unknown as Responses['pool'][]; }; + // cli.action.start('Fetching pools'); + const progressBar = cli.progress({ + format: '{value}/{total} pools {bar}', + barCompleteChar: '\u2588', + barIncompleteChar: '\u2591', + }); + progressBar.start(pools.length, 0); // Blockfrost API allows burst of 500 request, then we can only make 10 requests per second for (let i = 0; i < pools.length; i += batch_size) { - this.log(`Fetching pools ${i + batch_size}/${pools.length}`); + // this.log(`Fetching pools ${i + batch_size}/${pools.length}`); const promiseSlice = getPromiseBundle(i, batch_size); if (batch_size === SMALL_BATCH) { // wait 1 second before each small batch - await new Promise((resolve, reject) => setTimeout(() => resolve(true), 1000)); + await new Promise(resolve => setTimeout(() => resolve(true), 1000)); } const partialResults = await Promise.all(promiseSlice); + progressBar.update(i + batch_size); partialResults.forEach(res => { + const liveStake = BigInt(res.live_stake); allStakes.push({ pool_id: res.pool_id, - live_stake: res.live_stake, + live_stake: liveStake, }); + stakesSum += liveStake; }); if (i >= 400) { // after 400 request switch to small batch batch_size = SMALL_BATCH; } } + // cli.action.stop(); + progressBar.stop(); - return allStakes; + const formattedStakes = allStakes.map(stake => ({ + pool_id: stake.pool_id, + numerator: stake.live_stake, + denominator: stakesSum, + })); + return formattedStakes; }; } diff --git a/yarn.lock b/yarn.lock index 6441bb3..161839d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,6 +1163,13 @@ __metadata: languageName: node linkType: hard +"@types/big.js@npm:^6.1.2": + version: 6.1.2 + resolution: "@types/big.js@npm:6.1.2" + checksum: fb0daa4b23e1cb9d0d1c847722ae3764978d0290875d91687c6ecc7566860129ce86b190b732294484077d45f9b82ef3e97784ee32c83aef05e8c8433c4fde6a + languageName: node + linkType: hard + "@types/cacheable-request@npm:^6.0.1": version: 6.0.2 resolution: "@types/cacheable-request@npm:6.0.2" @@ -2054,6 +2061,13 @@ __metadata: languageName: node linkType: hard +"big.js@npm:^6.1.1": + version: 6.1.1 + resolution: "big.js@npm:6.1.1" + checksum: ba5db278e7d6700d7f92b7421e851bb65b6336d90b882869696c50574623c6be31f81500c3195fb1b391045163ffe62745e1c2bc30b35cb15e1b3e3ed135266b + languageName: node + linkType: hard + "binaryextensions@npm:^2.1.2": version: 2.3.0 resolution: "binaryextensions@npm:2.3.0" @@ -2098,11 +2112,13 @@ __metadata: "@blockfrost/blockfrost-js": 3.0.0-beta.10 "@oclif/core": 1.0.4 "@oclif/plugin-help": ^5 + "@types/big.js": ^6.1.2 "@types/jest": ^27.0.3 "@types/node": ^14 "@typescript-eslint/eslint-plugin": ^5.4.0 "@typescript-eslint/parser": ^5.4.0 bech32: ^2.0.0 + big.js: ^6.1.1 cli-ux: ^5.6.4 eslint: ^7.32.0 eslint-config-oclif: ^4.0.0