{"id":17800346,"url":"https://github.com/pooltogether/v4-utils-js","last_synced_at":"2026-03-02T10:32:22.585Z","repository":{"id":37895482,"uuid":"426279057","full_name":"pooltogether/v4-utils-js","owner":"pooltogether","description":"Javascript Utility Library for PoolTogether V4 off-chain calculations, computations and core logic.","archived":false,"fork":false,"pushed_at":"2023-03-06T15:04:22.000Z","size":1002,"stargazers_count":5,"open_issues_count":7,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-10-14T20:53:34.464Z","etag":null,"topics":["ethereum","pooltogether","web3"],"latest_commit_sha":null,"homepage":"https://github.com/pooltogether/v4-utils-js","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pooltogether.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-11-09T15:18:24.000Z","updated_at":"2023-04-18T19:41:58.000Z","dependencies_parsed_at":"2024-06-19T05:35:53.225Z","dependency_job_id":null,"html_url":"https://github.com/pooltogether/v4-utils-js","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/pooltogether/v4-utils-js","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pooltogether%2Fv4-utils-js","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pooltogether%2Fv4-utils-js/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pooltogether%2Fv4-utils-js/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pooltogether%2Fv4-utils-js/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pooltogether","download_url":"https://codeload.github.com/pooltogether/v4-utils-js/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pooltogether%2Fv4-utils-js/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29998513,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-02T09:59:02.300Z","status":"ssl_error","status_checked_at":"2026-03-02T09:59:02.001Z","response_time":60,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ethereum","pooltogether","web3"],"created_at":"2024-10-27T12:19:58.743Z","updated_at":"2026-03-02T10:32:22.348Z","avatar_url":"https://github.com/pooltogether.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/pooltogether/pooltogether--brand-assets\"\u003e\n    \u003cimg src=\"https://github.com/pooltogether/pooltogether--brand-assets/blob/977e03604c49c63314450b5d432fe57d34747c66/logo/pooltogether-logo--purple-gradient.png?raw=true\" alt=\"PoolTogether Brand\" style=\"max-width:100%;\" width=\"200\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cbr /\u003e\n\n# 🧰 Javascript Utilility Library - PoolTogether V4\n![Tests](https://github.com/pooltogether/v4-utils-js/actions/workflows/main.yml/badge.svg)\n[![Coverage Status](https://coveralls.io/repos/github/pooltogether/v4-utils-js/badge.svg?branch=main)](https://coveralls.io/github/pooltogether/v4-utils-js?branch=main)\n![ts](https://badgen.net/badge/-/TypeScript?icon=typescript\u0026label\u0026labelColor=blue\u0026color=555555)\n[![GPLv3 license](https://img.shields.io/badge/License-GPLv3-blue.svg)](http://perso.crans.org/besson/LICENSE.html)\n![npm](https://img.shields.io/npm/v/@pooltogether/v4-utils-js)\n\n[Application](https://app.pooltogether.com/) | [Contracts](https://github.com/pooltogether/v4-core) | [Documentation](https://docs.pooltogether.com/) | [Draw Calculator](https://github.com/pooltogether/draw-calculator-cli) | [Frontend Client](https://github.com/pooltogether/v4-js-client) | [Static Cache](https://github.com/pooltogether/v4-draw-results)\n\n## Calculations, Computations and Core Logic\n\nThe `@pooltogether/v4-utils-js` [node module package](https://www.npmjs.com/package/@pooltogether/v4-utils-js) provides calculations, computations and core logic for the PoolTogether V4 protocol.\n\nAssisting with low-level tasks like hashing addresses to generate picks and calculating the total number of prizes for a prize tier. The `calculations` namespaced functions are modular: consuming low-level inputs/types to parity smart contract EVM operations.\n\nHigh-order operations like filtering for a users winning picks and processing chain state (draws, prizeDistributions, etc..) to analyze/predict short and long term outcomes are included in the `computations` namespaced functions.\n\n**🧮 Caclulations:**\n\nArithmetic and operations to match `v4-core` [smart contract](https://github.com/pooltogether/v4-core) operations:\n\n- [calculateCardinality](docs/md/modules.md#calculatecardinality)\n- [calculateFractionOfPrize](docs/md/modules.md#calculatefractionofprize)\n- [calculateNormalizedBalancePicksFromTotalPicks](docs/md/modules.md#calculatenormalizedbalancepicksfromtotalpicks)\n- [calculateNumberOfMatches](docs/md/modules.md#calculatenumberofmatches)\n- [calculateNumberOfPrizesForTierIndex](docs/md/modules.md#calculatenumberofprizesfortierindex)\n- [calculatePick](docs/md/modules.md#calculatepick)\n- [calculatePicks](docs/md/modules.md#calculatepicks)\n- [calculatePicksFromAverageTotalSuppliesBetween](docs/md/modules.md#calculatepicksfromaveragetotalsuppliesbetween)\n- [calculatePrizeForTierPercentage](docs/md/modules.md#calculateprizefortierpercentage)\n- [calculateTierIndexFromMatches](docs/md/modules.md#calculatetierindexfrommatches)\n\n**🖥️ Computations:** \n\nConsume protocol chain state and return computed outcomes:\n\n- [computeDrawResults](docs/md/modules.md#computedrawresults)\n- [computePickPrize](docs/md/modules.md#computepickprize)\n- [computePicksPrizes](docs/md/modules.md#computepicksprizes)\n- [computePrizeAmount](docs/md/modules.md#computeprizeamount)\n- [computePrizeDistributionFromTicketAverageTotalSupplies](docs/md/modules.md#computeprizedistributionfromticketaveragetotalsupplies)\n- [computeUserPicks](docs/md/modules.md#computeuserpicks)\n- [computeUserWinningPicksForRandomNumber](docs/md/modules.md#computeuserwinningpicksforrandomnumber)\n- [computeWinningPicks](docs/md/modules.md#computewinningpicks)\n\n**🏆 Core:**\n\nGain insights into the protocol state by analyzing and encoding historical and potential chain state.\n\n- [encodeWinningPicks](docs/md/modules.md#encodewinningpicks)\n- [winningPicks](docs/md/modules.md#winningpicks)\n\n🙋 *Potential Additions:*\n\n- poolAverageYieldBetweenTimestamps\n- userAverageYieldBetweenTimestamps\n- oddsPerPrizeTierUsingNormalizedBalance\n- encodeDrawPercentageRateAtomicUpdatesAcrossChains\n\n[Create Issue](https://github.com/pooltogether/v4-utils-js/issues) to request new features.\u003cbr/\u003e[Open Pull Request](#) adhering to Contribution guidelines.\n\n\n# 💾 Installation\n\nThis project is available as an NPM package:\n\n```sh\nnpm install @pooltogether/v4-utils-js\n```\n\n```sh\nyarn add @pooltogether/v4-utils-js\n```\n\nThe repo can be cloned from Github for contributions.\n\n```sh\ngit clone https://github.com/pooltogether/v4-utils-js\n```\n\n# 🏆 Quickstart (Claim Winning Picks)\n\nCore utility functions like `winningPicks(user, draw, prizeDistribution)` calculate, compute and encode any EVM chain compatible transaction with the maximum number of winning picks using the input arguments.\n\nIn short, if you just need to calulcate winning picks and claim prizes the `winningPicks` function is for you 👋 \n```ts\nimport { Wallet } from '@ethersproject/wallet';\nimport { providers } from '@ethersproject/provider';\nimport { winningPicks, computeWinningPicks, encodeWinningPicks } from '@pooltogether/v4-utils-js';\n\n// Compute and Encode Winning Picks Seperately\nconst computedPicks = computeWinningPicks(user, [draw], [prizeDistribution]);\nconst encodePicks = encodeWinningPicks(user, computedWinningPicks);\n\n// Compute and Encode Winning Picks Together\nconst computedAndEncodedWinningPicks = winningPicks(user, [draw], [prizeDistribution]);\n\n// Send Encoded Transaction to Mainnet\nconst wallet = Wallet.createRandom().connect(providers.getDefaultProvider())\nwallet.send(computedAndEncodedWinningPicks.encodedWinningPickIndices)\n```\n\n# 🪜 Examples\n\n```ts\nimport { BigNumber } from '@ethersproject/bignumber';\nimport { parseEther } from '@ethersproject/units';\nimport { winningPicks, utils } from '@pooltogether/v4-utils-js';\n\nconst user = {\n    address: '0x0000000000000000000000000000000000000001',\n    normalizedBalances: [\n        parseEther('0.1'), // 10% of totalSupply\n    ],\n};\n\nconst draw = {\n    drawId: 1,\n    winningRandomNumber: BigNumber.from(\n        '0x0000000000000000000000000000000000000000000000000000000000000001'\n    ),\n};\n\nconst prizeDistribution = {\n    bitRangeSize: 4,\n    matchCardinality: 10,\n    numberOfPicks: 1000,\n    prize: parseEther('1000'),\n    maxPicksPerUser: 30,\n    tiers: [\n        // Tier prizeAmount is 100% split between 10 tiers. \n        utils.formatTierPercentage('0.1'),\n        utils.formatTierPercentage('0.1'),\n        utils.formatTierPercentage('0.1'),\n        utils.formatTierPercentage('0.1'),\n        utils.formatTierPercentage('0.1'),\n        utils.formatTierPercentage('0.1'),\n        utils.formatTierPercentage('0.1'),\n        utils.formatTierPercentage('0.1'),\n        utils.formatTierPercentage('0.1'),\n        utils.formatTierPercentage('0.1'),\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n    ],\n};\n\nconst generatedPicks = winningPicks(user, [draw], [prizeDistribution]);\n/**\nuserAddress: string;\ndrawIds: number[];\nwinningPickIndices: BigNumber[][];\nencodedWinningPickIndices: string;\n* -------------------\nuserAddress: '0x0000000000000000000000000000000000000001',\ndrawIds: [1],\nwinningPickIndices: [[1]],\nencodedWinningPickIndices: '0x000...2000...0001'\n* /\n```\n# 💻 Developer Experience\n\nThe package is setup using the [TSDX zero-config CLI](https://tsdx.io/) which includes:\n\n- Typescript\n- Rollup\n- Jest\n- Prettier\n- ESLint\n\n**Minor changes have been made to extend the default configuration.**\n\n### ESLint\n\nThe TSDX linting configuration is overwritten to include override(s)* for:\n\n- Import/Order (used to enforce consistent module import ordering)\n\n###### *The ESLint overrides may incorrectly be interpreted by VSCode since the nested config file is ignored in the IDE\n\n# 📖 Documentation\n\n### Namespaces\n\n- [calculate](docs/md/modules/calculate.md)\n- [compute](docs/md/modules/compute.md)\n- [utils](docs/md/modules/utils.md)\n\n### References\n\n- [calculateCardinality](docs/md/modules.md#calculatecardinality)\n- [calculateFractionOfPrize](docs/md/modules.md#calculatefractionofprize)\n- [calculateNormalizedBalancePicksFromTotalPicks](docs/md/modules.md#calculatenormalizedbalancepicksfromtotalpicks)\n- [calculateNumberOfMatches](docs/md/modules.md#calculatenumberofmatches)\n- [calculateNumberOfPrizesForTierIndex](docs/md/modules.md#calculatenumberofprizesfortierindex)\n- [calculatePick](docs/md/modules.md#calculatepick)\n- [calculatePicks](docs/md/modules.md#calculatepicks)\n- [calculatePicksFromAverageTotalSuppliesBetween](docs/md/modules.md#calculatepicksfromaveragetotalsuppliesbetween)\n- [calculatePrizeForTierPercentage](docs/md/modules.md#calculateprizefortierpercentage)\n- [calculateTierIndexFromMatches](docs/md/modules.md#calculatetierindexfrommatches)\n- [computeDrawResults](docs/md/modules.md#computedrawresults)\n- [computePickPrize](docs/md/modules.md#computepickprize)\n- [computePicksPrizes](docs/md/modules.md#computepicksprizes)\n- [computePrizeAmount](docs/md/modules.md#computeprizeamount)\n- [computePrizeDistributionFromTicketAverageTotalSupplies](docs/md/modules.md#computeprizedistributionfromticketaveragetotalsupplies)\n- [computeUserPicks](docs/md/modules.md#computeuserpicks)\n- [computeUserWinningPicksForRandomNumber](docs/md/modules.md#computeuserwinningpicksforrandomnumber)\n- [computeWinningPicks](docs/md/modules.md#computewinningpicks)\n- [encodeWinningPicks](docs/md/modules.md#encodewinningpicks)\n- [winningPicks](docs/md/modules.md#winningpicks)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpooltogether%2Fv4-utils-js","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpooltogether%2Fv4-utils-js","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpooltogether%2Fv4-utils-js/lists"}