├── .eslintignore ├── .eslintrc ├── .github ├── actions │ ├── create-prerelease │ │ ├── action.yml │ │ └── remove-stable-version.js │ └── create-release │ │ ├── action.yml │ │ └── gh-release-script.js ├── pull_request_template.md └── workflows │ ├── codeql-analysis.yml │ ├── pr.yml │ ├── prerelease.yml │ └── release.yml ├── .gitignore ├── .husky └── pre-commit ├── .prettierrc ├── .yarn ├── plugins │ └── @yarnpkg │ │ ├── plugin-version.cjs │ │ └── plugin-workspace-tools.cjs ├── releases │ └── yarn-3.2.4.cjs └── versions │ ├── 02c27695.yml │ ├── 04067352.yml │ ├── 05406117.yml │ ├── 144ae8e3.yml │ ├── 174f7c82.yml │ ├── 19dca71a.yml │ ├── 1d73b113.yml │ ├── 22fbe415.yml │ ├── 241727ef.yml │ ├── 24c48501.yml │ ├── 2534b5fa.yml │ ├── 27a4f916.yml │ ├── 311cecc5.yml │ ├── 32d9a24b.yml │ ├── 344cedd0.yml │ ├── 34a9b5fd.yml │ ├── 3de3f57f.yml │ ├── 3f934f6e.yml │ ├── 42fd7951.yml │ ├── 43e6a6fd.yml │ ├── 4611bcd1.yml │ ├── 4b0751a0.yml │ ├── 4dd32d98.yml │ ├── 53381b35.yml │ ├── 5368cde2.yml │ ├── 53bb2961.yml │ ├── 550ce4a4.yml │ ├── 57521769.yml │ ├── 5cfb8237.yml │ ├── 5dcc6c60.yml │ ├── 62eb43a3.yml │ ├── 6332090f.yml │ ├── 69510e87.yml │ ├── 708b44a5.yml │ ├── 78f9ca83.yml │ ├── 7cb66ab7.yml │ ├── 7e518aa5.yml │ ├── 83a877aa.yml │ ├── 850203aa.yml │ ├── 88308c77.yml │ ├── 8c12a9d7.yml │ ├── 8c76dae9.yml │ ├── 8d5f68de.yml │ ├── 8f3f4961.yml │ ├── 9045847e.yml │ ├── 96813870.yml │ ├── 992a80f3.yml │ ├── 9dbfa029.yml │ ├── a8755ed1.yml │ ├── b3e0f960.yml │ ├── cba20470.yml │ ├── cdfdcc75.yml │ ├── d272c05b.yml │ ├── da309c78.yml │ ├── dea7a49c.yml │ ├── e0bb153c.yml │ ├── e0f57c21.yml │ ├── e133d23a.yml │ ├── e90f7bfc.yml │ ├── ec02d70e.yml │ ├── ed70da4a.yml │ ├── efedca0e.yml │ ├── f161440e.yml │ ├── f72a513a.yml │ ├── fb87cd42.yml │ └── fe02ac81.yml ├── .yarnrc.yml ├── LICENSE ├── README.md ├── __mocks__ └── axios.ts ├── jest.config.ts ├── package.json ├── packages ├── apollo-links │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── package.json │ ├── src │ │ ├── auth │ │ │ ├── authHelper.ts │ │ │ ├── eip712.ts │ │ │ └── index.ts │ │ ├── authHttpLink.ts │ │ ├── core │ │ │ ├── authLink.ts │ │ │ ├── clusterAuthLink.ts │ │ │ ├── dynamicHttpLink.ts │ │ │ ├── errorLink.ts │ │ │ ├── fallbackLink.ts │ │ │ ├── index.ts │ │ │ ├── responseLink.ts │ │ │ └── retryLink.ts │ │ ├── index.ts │ │ ├── types.ts │ │ └── utils │ │ │ └── logger.ts │ └── tsconfig.json ├── eth-provider │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── package.json │ ├── src │ │ ├── index.ts │ │ └── provider.ts │ ├── test │ │ └── provider.test.ts │ └── tsconfig.json ├── network-clients │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── package.json │ ├── src │ │ ├── clients │ │ │ ├── contractClient.ts │ │ │ ├── index.ts │ │ │ ├── ipfsClient.ts │ │ │ ├── networkClient.ts │ │ │ └── queryClient.ts │ │ ├── globalTypes.ts │ │ ├── index.ts │ │ ├── models │ │ │ ├── common.ts │ │ │ ├── eraValue.ts │ │ │ ├── index.ts │ │ │ └── indexer.ts │ │ └── utils │ │ │ ├── apollo.ts │ │ │ ├── index.ts │ │ │ ├── ipfs.ts │ │ │ ├── parseEraValue.ts │ │ │ └── waitForSomething.ts │ └── tsconfig.json ├── network-config │ ├── CHANGELOG.md │ ├── LICENSE │ ├── package.json │ ├── src │ │ ├── config.ts │ │ ├── constants.ts │ │ └── index.ts │ └── tsconfig.json ├── network-query │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── leaderboard.codegen.ts │ ├── network.codegen.ts │ ├── package.json │ ├── queries │ │ ├── leaderboard │ │ │ └── topIndexer.gql │ │ └── network │ │ │ ├── agreements.gql │ │ │ ├── dashboard.gql │ │ │ ├── delegations.gql │ │ │ ├── delegatorApr.gql │ │ │ ├── deploymentBooster.gql │ │ │ ├── deployments.gql │ │ │ ├── eraRewards.gql │ │ │ ├── eraStakes.gql │ │ │ ├── indexerAllocation.gql │ │ │ ├── indexerAllocationRewards.gql │ │ │ ├── indexerApr.gql │ │ │ ├── indexerStake.gql │ │ │ ├── indexers.gql │ │ │ ├── offers.gql │ │ │ ├── orders.gql │ │ │ ├── plans.gql │ │ │ ├── project.gql │ │ │ ├── staking.gql │ │ │ ├── statechannel.gql │ │ │ └── totalLock.gql │ ├── scripts │ │ └── codegen.sh │ ├── src │ │ └── index.ts │ ├── tsconfig.json │ └── types.codegen.ts ├── network-support │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── package.json │ ├── src │ │ ├── fetch.ts │ │ ├── index.ts │ │ ├── orderManager.ts │ │ ├── scoreManager.ts │ │ ├── stateManager.ts │ │ ├── types.ts │ │ └── utils │ │ │ ├── auth.ts │ │ │ ├── common.ts │ │ │ ├── hash.ts │ │ │ ├── index.ts │ │ │ ├── logger.ts │ │ │ ├── query.ts │ │ │ ├── store.ts │ │ │ ├── uniqueId.ts │ │ │ └── version.ts │ ├── test │ │ └── fetch.test.ts │ └── tsconfig.json └── react-hooks │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── leaderboard.codegen.ts │ ├── network.codegen.ts │ ├── package.json │ ├── scripts │ └── codegen.sh │ ├── src │ ├── graphql.ts │ ├── index.ts │ ├── renderAsync.ts │ ├── types.ts │ ├── useAsyncMemo.ts │ ├── useStableCoin.tsx │ └── utils.ts │ └── tsconfig.json ├── test ├── authLink.test.ts ├── jest-setup.ts ├── networkClient.test.ts ├── queryClient.test.ts └── react-hooks.test.tsx ├── tsconfig.json ├── tsconfig.test.json └── yarn.lock /.eslintignore: -------------------------------------------------------------------------------- 1 | **/__graphql__/** 2 | **/__hooks__/** -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "@typescript-eslint/parser", 3 | "parserOptions": { 4 | "sourceType": "module" 5 | }, 6 | "plugins": [ 7 | "@typescript-eslint/eslint-plugin", 8 | "header" 9 | ], 10 | "extends": [ 11 | "eslint:recommended", 12 | "plugin:@typescript-eslint/recommended" 13 | ], 14 | "root": true, 15 | "env": { 16 | "node": true, 17 | "jest": true, 18 | "browser": true 19 | }, 20 | "ignorePatterns": [ 21 | "**/packages/**/dist/**", 22 | "/test/jest-setup.ts" 23 | ], 24 | "rules": { 25 | "@typescript-eslint/interface-name-prefix": "off", 26 | "@typescript-eslint/explicit-function-return-type": "off", 27 | "@typescript-eslint/explicit-module-boundary-types": "off", 28 | "@typescript-eslint/no-explicit-any": "off", 29 | "header/header": [ 30 | 2, 31 | "line", 32 | [ 33 | { 34 | "pattern": " Copyright \\d{4}(-\\d{4})? SubQuery Pte Ltd authors & contributors", 35 | "template": " Copyright 2020-2024 SubQuery Pte Ltd authors & contributors" 36 | }, 37 | " SPDX-License-Identifier: Apache-2.0" 38 | ], 39 | 2 40 | ] 41 | } 42 | } -------------------------------------------------------------------------------- /.github/actions/create-prerelease/action.yml: -------------------------------------------------------------------------------- 1 | # Composite action needed to access github context 2 | 3 | # This is to compensate for yarn 3 issue https://github.com/yarnpkg/berry/issues/3868 4 | name: 'Remove Stable Versions' 5 | description: 'This will remove stableVersion from packages for prerelease' 6 | inputs: 7 | package-path: 8 | description: 'package path to run action e.g. package/common' 9 | required: true 10 | npm-token: 11 | description: 'token to push to npm registry' 12 | required: true 13 | 14 | runs: 15 | using: "composite" 16 | steps: 17 | - working-directory: ${{ github.workspace }} 18 | run: node ${{ github.action_path }}/remove-stable-version.js ${{ github.workspace }}/${{ inputs.package-path }} 19 | shell: bash 20 | 21 | - working-directory: ${{ inputs.package-path }} 22 | run: echo "Changes exist in ${{ inputs.package-path }}" && yarn version prerelease && yarn npm publish --access public --tag dev 23 | env: 24 | NPM_AUTH_TOKEN: ${{ inputs.npm-token }} 25 | shell: bash 26 | -------------------------------------------------------------------------------- /.github/actions/create-prerelease/remove-stable-version.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const myArgs = process.argv.slice(2); 3 | const pJson = require(`${myArgs[0]}/package.json`) 4 | 5 | if (pJson.stableVersion){ 6 | delete pJson.stableVersion 7 | fs.writeFileSync(`${myArgs[0]}/package.json`, JSON.stringify(pJson, null, 2)) 8 | } 9 | -------------------------------------------------------------------------------- /.github/actions/create-release/action.yml: -------------------------------------------------------------------------------- 1 | # Composite action needed to access github context 2 | 3 | name: 'Create Release' 4 | description: 'This will publish to NPM registry and create Github release' 5 | inputs: 6 | package-path: # id of input 7 | description: 'package path to run action e.g. package/common' 8 | required: true 9 | repo-token: 10 | description: 'token to create github release' 11 | required: true 12 | npm-token: 13 | description: 'token to push to npm registry' 14 | required: true 15 | 16 | runs: 17 | using: "composite" 18 | steps: 19 | - working-directory: ${{ inputs.package-path }} 20 | run: echo "Changes exist in ${{ inputs.package-path }}" && yarn npm publish --access public --tag latest 21 | env: 22 | NPM_AUTH_TOKEN: ${{ inputs.npm-token }} 23 | shell: bash 24 | 25 | - working-directory: ${{ github.workspace }} 26 | run: node ${{ github.action_path }}/gh-release-script.js ${{ github.workspace }}/${{ inputs.package-path }} 27 | env: 28 | REPO_TOKEN: ${{ inputs.repo-token }} 29 | shell: bash 30 | -------------------------------------------------------------------------------- /.github/actions/create-release/gh-release-script.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const { exit } = require('process'); 3 | const core = require('@actions/core'); 4 | const { request } = require('@octokit/request'); 5 | 6 | const myArgs = process.argv.slice(2); 7 | 8 | const pJson = require(`${myArgs[0]}/package.json`) 9 | 10 | const version = pJson.version; 11 | const repoName = pJson.name; 12 | 13 | const packageName = repoName.split('/'); 14 | 15 | function checkForBetaVersion(version) { 16 | if (version.includes('-')){ 17 | exit(0); //skip this package but continue trying to release others 18 | } 19 | } 20 | 21 | function gatherReleaseInfo(logPath) { 22 | const changeLogs = fs.readFileSync(logPath, 'utf8'); 23 | const regex = /## \[([0-9]+(\.[0-9]+)+)] - [0-9]{4}-[0-9]{2}-[0-9]{2}/i; 24 | 25 | let lines = changeLogs.split(/\n/); 26 | let foundChangelog = false; 27 | let releaseInfo = ''; 28 | let i = 0; 29 | 30 | for(let j = 0; j < lines.length; j++){ 31 | if(lines[j].includes(`[${version}]`)){ 32 | i = j; 33 | j = lines.length; 34 | foundChangelog = true; 35 | } 36 | } 37 | 38 | lines = lines.slice(i); 39 | 40 | if(foundChangelog){ 41 | for(let j = 0; j < lines.length; j++){ 42 | if(j == 0){ 43 | releaseInfo += `${lines[j]}`+ '\n'; 44 | continue; 45 | } 46 | 47 | if(!regex.test(lines[j])){ 48 | releaseInfo += `${lines[j]}`+ '\n'; 49 | } else { 50 | j = lines.length; 51 | } 52 | } 53 | } 54 | 55 | if(releaseInfo === ''){ 56 | core.setFailed("No release info found, either missing in changelog or changelog is formatted incorrectly") 57 | } 58 | 59 | console.log("Gathered release info...") 60 | return releaseInfo; 61 | } 62 | 63 | async function publishRelease(releaseInfo) { 64 | 65 | await request('POST /repos/{owner}/{repo}/releases', { 66 | headers: { 67 | authorization: `token ${process.env.REPO_TOKEN}`, 68 | }, 69 | owner: 'subquery', 70 | name: `[${version}] ${repoName}`, 71 | repo: 'client', 72 | tag_name: `${packageName[1]}/${version}`, 73 | body: releaseInfo 74 | }).catch( err => { 75 | core.setFailed(err) 76 | }) 77 | 78 | console.log("Release Created...") 79 | } 80 | 81 | checkForBetaVersion(version); 82 | 83 | const releaseInfo = gatherReleaseInfo(`./packages/${packageName[1]}/CHANGELOG.md`); 84 | 85 | publishRelease(releaseInfo); 86 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change. 4 | 5 | Fixes # (issue) Ticket # (ticket number) 6 | 7 | ## Type of change 8 | 9 | Please delete options that are not relevant. 10 | 11 | - [ ] Bug fix (non-breaking change which fixes an issue) 12 | - [ ] New feature (non-breaking change which adds functionality) 13 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) 14 | - [ ] This change requires a documentation update 15 | 16 | ## Changes 17 | 18 | - First change 19 | - Second change 20 | - etc 21 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ "main", "develop" ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ "main", "develop" ] 20 | schedule: 21 | - cron: '21 0 * * 0' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'javascript' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support 38 | 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@v3 42 | 43 | # Initializes the CodeQL tools for scanning. 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@v2 46 | with: 47 | languages: ${{ matrix.language }} 48 | # If you wish to specify custom queries, you can do so here or in a config file. 49 | # By default, queries listed here will override any specified in a config file. 50 | # Prefix the list here with "+" to use these queries and those in the config file. 51 | 52 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 53 | # queries: security-extended,security-and-quality 54 | 55 | 56 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 57 | # If this step fails, then you should remove it and run the build manually (see below) 58 | - name: Autobuild 59 | uses: github/codeql-action/autobuild@v2 60 | 61 | # ℹ️ Command-line programs to run using the OS shell. 62 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 63 | 64 | # If the Autobuild fails above, remove it and uncomment the following three lines. 65 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. 66 | 67 | # - run: | 68 | # echo "Run, Build Application using script" 69 | # ./location_of_script_within_repo/buildscript.sh 70 | 71 | - name: Perform CodeQL Analysis 72 | uses: github/codeql-action/analyze@v2 73 | with: 74 | category: "/language:${{matrix.language}}" 75 | -------------------------------------------------------------------------------- /.github/workflows/pr.yml: -------------------------------------------------------------------------------- 1 | name: PR 2 | on: 3 | pull_request: 4 | paths-ignore: 5 | - '.github/workflows/**' 6 | jobs: 7 | pr: 8 | name: pr 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - uses: actions/checkout@v2 13 | - name: Setup Node.js environment 14 | uses: actions/setup-node@v2 15 | with: 16 | node-version: 16 17 | - run: yarn 18 | 19 | - name: build 20 | run: yarn build 21 | 22 | - name: lint 23 | run: yarn lint 24 | 25 | - name: test 26 | run: yarn test --forceExit 27 | env: 28 | AUTH_URL: ${{ vars.AUTH_URL }} 29 | 30 | -------------------------------------------------------------------------------- /.github/workflows/prerelease.yml: -------------------------------------------------------------------------------- 1 | name: 'Prerelease' 2 | on: 3 | push: 4 | branches: 5 | - main 6 | - develop 7 | paths-ignore: 8 | - '.github/workflows/**' 9 | workflow_dispatch: 10 | inputs: 11 | force-release: 12 | type: boolean 13 | description: 'Force to publish the packages' 14 | default: false 15 | required: true 16 | 17 | jobs: 18 | pre-ci: 19 | runs-on: ubuntu-latest 20 | timeout-minutes: 1 21 | steps: 22 | - name: 'Block Concurrent Executions' 23 | uses: softprops/turnstyle@v1 24 | with: 25 | poll-interval-seconds: 10 26 | env: 27 | GITHUB_TOKEN: ${{ secrets.REPO_TOKEN }} 28 | 29 | Bump-Prerelease-Publish: 30 | name: Bump-Prerelease-Publish 31 | needs: pre-ci 32 | if: "!startsWith(github.event.head_commit.message, '[SKIP CI]') && !startsWith(github.event.head_commit.message, '[release]') && github.repository == 'subquery/network-clients'" 33 | runs-on: ubuntu-latest 34 | steps: 35 | - uses: actions/checkout@v2 36 | with: 37 | fetch-depth: 100 38 | token: ${{ secrets.REPO_TOKEN }} 39 | 40 | - name: Setup Node.js environment 41 | uses: actions/setup-node@v2 42 | with: 43 | node-version: 16 44 | 45 | - uses: marceloprado/has-changed-path@v1 46 | id: changed-network-config 47 | with: 48 | paths: packages/network-config 49 | 50 | - uses: marceloprado/has-changed-path@v1 51 | id: changed-network-support 52 | with: 53 | paths: packages/network-support 54 | 55 | - uses: marceloprado/has-changed-path@v1 56 | id: changed-eth-provider 57 | with: 58 | paths: packages/eth-provider 59 | 60 | - uses: marceloprado/has-changed-path@v1 61 | id: changed-network-clients 62 | with: 63 | paths: packages/network-clients 64 | 65 | - uses: marceloprado/has-changed-path@v1 66 | id: changed-network-query 67 | with: 68 | paths: packages/network-query 69 | 70 | - uses: marceloprado/has-changed-path@v1 71 | id: changed-react-hooks 72 | with: 73 | paths: packages/react-hooks 74 | 75 | - uses: marceloprado/has-changed-path@v1 76 | id: changed-apollo-links 77 | with: 78 | paths: packages/apollo-links 79 | 80 | - run: yarn 81 | 82 | - name: build 83 | run: yarn build 84 | 85 | - name: Bump network-config & deploy 86 | if: steps.changed-network-config.outputs.changed == 'true' || github.event.inputs.force-release 87 | uses: ./.github/actions/create-prerelease 88 | with: 89 | package-path: packages/network-config 90 | npm-token: ${{ secrets.NPM_TOKEN }} 91 | 92 | - name: Bump network-support & deploy 93 | if: steps.changed-network-support.outputs.changed == 'true' || github.event.inputs.force-release 94 | uses: ./.github/actions/create-prerelease 95 | with: 96 | package-path: packages/network-support 97 | npm-token: ${{ secrets.NPM_TOKEN }} 98 | 99 | - name: Bump eth-provider & deploy 100 | if: steps.changed-eth-provider.outputs.changed == 'true' || steps.changed-network-support == 'true' || github.event.inputs.force-release 101 | uses: ./.github/actions/create-prerelease 102 | with: 103 | package-path: packages/eth-provider 104 | npm-token: ${{ secrets.NPM_TOKEN }} 105 | 106 | - name: Bump network-query & deploy 107 | if: steps.changed-network-query.outputs.changed == 'true' || github.event.inputs.force-release 108 | uses: ./.github/actions/create-prerelease 109 | with: 110 | package-path: packages/network-query 111 | npm-token: ${{ secrets.NPM_TOKEN }} 112 | 113 | - name: Bump network-clients & deploy 114 | if: steps.changed-network-clients.outputs.changed == 'true' || github.event.inputs.force-release 115 | uses: ./.github/actions/create-prerelease 116 | with: 117 | package-path: packages/network-clients 118 | npm-token: ${{ secrets.NPM_TOKEN }} 119 | 120 | - name: Bump react-hooks & deploy 121 | if: steps.changed-react-hooks.outputs.changed == 'true' || steps.changed-network-query.outputs.changed == 'true' || github.event.inputs.force-release 122 | uses: ./.github/actions/create-prerelease 123 | with: 124 | package-path: packages/react-hooks 125 | npm-token: ${{ secrets.NPM_TOKEN }} 126 | 127 | - name: Bump apollo-links & deploy 128 | if: steps.changed-apollo-links.outputs.changed == 'true' || steps.changed-network-support == 'true' || github.event.inputs.force-release 129 | uses: ./.github/actions/create-prerelease 130 | with: 131 | package-path: packages/apollo-links 132 | npm-token: ${{ secrets.NPM_TOKEN }} 133 | 134 | - name: Commit changes 135 | uses: EndBug/add-and-commit@v5 136 | with: 137 | message: '[SKIP CI] Prerelease' 138 | env: 139 | GITHUB_TOKEN: ${{ secrets.REPO_TOKEN }} 140 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: 'Release' 2 | on: 3 | push: 4 | branches: 5 | - main 6 | - develop 7 | paths-ignore: 8 | - '.github/workflows/**' 9 | workflow_dispatch: 10 | 11 | jobs: 12 | pre-ci: 13 | runs-on: ubuntu-latest 14 | timeout-minutes: 1 15 | steps: 16 | - name: 'Block Concurrent Executions' 17 | uses: softprops/turnstyle@v1 18 | with: 19 | poll-interval-seconds: 10 20 | env: 21 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 22 | 23 | Build-Publish: 24 | name: Build-Publish 25 | needs: pre-ci 26 | if: "!startsWith(github.event.head_commit.message, '[SKIP CI]') && startsWith(github.event.head_commit.message, '[release]') && github.repository == 'subquery/network-clients'" 27 | runs-on: ubuntu-latest 28 | steps: 29 | #Check out 30 | - uses: actions/checkout@v2 31 | with: 32 | fetch-depth: 100 33 | 34 | - name: Setup Node.js environment 35 | uses: actions/setup-node@v2 36 | with: 37 | node-version: 16 38 | 39 | #Identify changes 40 | - uses: marceloprado/has-changed-path@v1 41 | id: changed-network-config 42 | with: 43 | paths: packages/network-config 44 | 45 | - uses: marceloprado/has-changed-path@v1 46 | id: changed-network-support 47 | with: 48 | paths: packages/network-support 49 | 50 | - uses: marceloprado/has-changed-path@v1 51 | id: changed-eth-provider 52 | with: 53 | paths: packages/eth-provider 54 | 55 | - uses: marceloprado/has-changed-path@v1 56 | id: changed-network-clients 57 | with: 58 | paths: packages/network-clients 59 | 60 | - uses: marceloprado/has-changed-path@v1 61 | id: changed-network-query 62 | with: 63 | paths: packages/network-query 64 | 65 | - uses: marceloprado/has-changed-path@v1 66 | id: changed-react-hooks 67 | with: 68 | paths: packages/react-hooks 69 | 70 | - uses: marceloprado/has-changed-path@v1 71 | id: changed-apollo-links 72 | with: 73 | paths: packages/apollo-links 74 | 75 | - run: yarn 76 | 77 | - name: build 78 | run: yarn build 79 | 80 | #Publish to npm and github releases 81 | - name: Publish network-config 82 | if: steps.changed-network-config.outputs.changed == 'true' 83 | uses: ./.github/actions/create-release 84 | with: 85 | package-path: packages/network-config 86 | repo-token: ${{ secrets.GITHUB_TOKEN }} 87 | npm-token: ${{ secrets.NPM_TOKEN }} 88 | 89 | - name: Publish network-query 90 | if: steps.changed-network-query.outputs.changed == 'true' 91 | uses: ./.github/actions/create-release 92 | with: 93 | package-path: packages/network-query 94 | repo-token: ${{ secrets.GITHUB_TOKEN }} 95 | npm-token: ${{ secrets.NPM_TOKEN }} 96 | 97 | - name: Publish network-clients 98 | if: steps.changed-network-clients.outputs.changed == 'true' 99 | uses: ./.github/actions/create-release 100 | with: 101 | package-path: packages/network-clients 102 | repo-token: ${{ secrets.GITHUB_TOKEN }} 103 | npm-token: ${{ secrets.NPM_TOKEN }} 104 | 105 | - name: Publish react-hooks 106 | if: steps.changed-react-hooks.outputs.changed == 'true' 107 | uses: ./.github/actions/create-release 108 | with: 109 | package-path: packages/react-hooks 110 | repo-token: ${{ secrets.GITHUB_TOKEN }} 111 | npm-token: ${{ secrets.NPM_TOKEN }} 112 | 113 | - name: Publish apollo-links 114 | if: steps.changed-apollo-links.outputs.changed == 'true' 115 | uses: ./.github/actions/create-release 116 | with: 117 | package-path: packages/apollo-links 118 | repo-token: ${{ secrets.GITHUB_TOKEN }} 119 | npm-token: ${{ secrets.NPM_TOKEN }} 120 | 121 | - name: Publish network-support 122 | if: steps.changed-network-support.outputs.changed == 'true' 123 | uses: ./.github/actions/create-release 124 | with: 125 | package-path: packages/network-support 126 | repo-token: ${{ secrets.GITHUB_TOKEN }} 127 | npm-token: ${{ secrets.NPM_TOKEN }} 128 | 129 | - name: Publish eth-provider 130 | if: steps.changed-eth-provider.outputs.changed == 'true' 131 | uses: ./.github/actions/create-release 132 | with: 133 | package-path: packages/eth-provider 134 | repo-token: ${{ secrets.GITHUB_TOKEN }} 135 | npm-token: ${{ secrets.NPM_TOKEN }} 136 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Yarn 10 | .yarn/* 11 | !.yarn/cache 12 | !.yarn/patches 13 | !.yarn/plugins 14 | !.yarn/releases 15 | !.yarn/sdks 16 | !.yarn/versions 17 | 18 | # Diagnostic reports (https://nodejs.org/api/report.html) 19 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 20 | 21 | # Runtime data 22 | pids 23 | *.pid 24 | *.seed 25 | *.pid.lock 26 | 27 | # Directory for instrumented libs generated by jscoverage/JSCover 28 | lib-cov 29 | 30 | # Coverage directory used by tools like istanbul 31 | coverage 32 | *.lcov 33 | 34 | # nyc test coverage 35 | .nyc_output 36 | 37 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 38 | .grunt 39 | 40 | # Bower dependency directory (https://bower.io/) 41 | bower_components 42 | 43 | # node-waf configuration 44 | .lock-wscript 45 | 46 | # Compiled binary addons (https://nodejs.org/api/addons.html) 47 | build/Release 48 | 49 | # Dependency directories 50 | node_modules/ 51 | jspm_packages/ 52 | 53 | # TypeScript v1 declaration files 54 | typings/ 55 | 56 | # TypeScript cache 57 | *.tsbuildinfo 58 | 59 | # Optional npm cache directory 60 | .npm 61 | .env 62 | 63 | # Optional eslint cache 64 | .eslintcache 65 | 66 | # Microbundle cache 67 | .rpt2_cache/ 68 | .rts2_cache_cjs/ 69 | .rts2_cache_es/ 70 | .rts2_cache_umd/ 71 | 72 | # Optional REPL history 73 | .node_repl_history 74 | 75 | # Output of 'npm pack' 76 | *.tgz 77 | 78 | # Yarn Integrity file 79 | .yarn-integrity 80 | 81 | # yarn v2 82 | .yarn/cache 83 | .yarn/unplugged 84 | .yarn/build-state.yml 85 | .yarn/install-state.gz 86 | .pnp.* 87 | 88 | # parcel-bundler cache (https://parceljs.org/) 89 | .cache 90 | 91 | # Next.js build output 92 | .next 93 | 94 | # Nuxt.js build / generate output 95 | .nuxt 96 | dist 97 | 98 | # Gatsby files 99 | .cache/ 100 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 101 | # https://nextjs.org/blog/next-9-1#public-directory-support 102 | # public 103 | 104 | # vuepress build output 105 | .vuepress/dist 106 | 107 | # Serverless directories 108 | .serverless/ 109 | 110 | # FuseBox cache 111 | .fusebox/ 112 | 113 | # DynamoDB Local files 114 | .dynamodb/ 115 | 116 | # TernJS port file 117 | .tern-port 118 | 119 | .DS_Store 120 | 121 | # Generated graphql types and hooks 122 | __graphql__ 123 | __hooks__ 124 | 125 | # idea 126 | .idea -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npx lint-staged 5 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "trailingComma": "es5", 4 | "tabWidth": 2, 5 | "singleQuote": true, 6 | "bracketSpacing": true 7 | } -------------------------------------------------------------------------------- /.yarn/versions/02c27695.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@subql/network-query" 3 | -------------------------------------------------------------------------------- /.yarn/versions/04067352.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zikc2023/network-clients/e8cc36aa249735ba82a783f8ef7e6af165d6b986/.yarn/versions/04067352.yml -------------------------------------------------------------------------------- /.yarn/versions/05406117.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@subql/network-query" 3 | -------------------------------------------------------------------------------- /.yarn/versions/144ae8e3.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zikc2023/network-clients/e8cc36aa249735ba82a783f8ef7e6af165d6b986/.yarn/versions/144ae8e3.yml -------------------------------------------------------------------------------- /.yarn/versions/174f7c82.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zikc2023/network-clients/e8cc36aa249735ba82a783f8ef7e6af165d6b986/.yarn/versions/174f7c82.yml -------------------------------------------------------------------------------- /.yarn/versions/19dca71a.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@subql/network-clients" 3 | - "@subql/network-config" 4 | - "@subql/network-query" 5 | -------------------------------------------------------------------------------- /.yarn/versions/1d73b113.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@subql/network-query" 3 | -------------------------------------------------------------------------------- /.yarn/versions/22fbe415.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@subql/network-query" 3 | -------------------------------------------------------------------------------- /.yarn/versions/241727ef.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@subql/network-query" 3 | -------------------------------------------------------------------------------- /.yarn/versions/24c48501.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@subql/network-clients" 3 | -------------------------------------------------------------------------------- /.yarn/versions/2534b5fa.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@subql/network-query" 3 | -------------------------------------------------------------------------------- /.yarn/versions/27a4f916.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@subql/network-query" 3 | -------------------------------------------------------------------------------- /.yarn/versions/311cecc5.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@subql/network-query" 3 | -------------------------------------------------------------------------------- /.yarn/versions/32d9a24b.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@subql/react-hooks" 3 | -------------------------------------------------------------------------------- /.yarn/versions/344cedd0.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zikc2023/network-clients/e8cc36aa249735ba82a783f8ef7e6af165d6b986/.yarn/versions/344cedd0.yml -------------------------------------------------------------------------------- /.yarn/versions/34a9b5fd.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@subql/network-query" 3 | -------------------------------------------------------------------------------- /.yarn/versions/3de3f57f.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zikc2023/network-clients/e8cc36aa249735ba82a783f8ef7e6af165d6b986/.yarn/versions/3de3f57f.yml -------------------------------------------------------------------------------- /.yarn/versions/3f934f6e.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zikc2023/network-clients/e8cc36aa249735ba82a783f8ef7e6af165d6b986/.yarn/versions/3f934f6e.yml -------------------------------------------------------------------------------- /.yarn/versions/42fd7951.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@subql/react-hooks" 3 | -------------------------------------------------------------------------------- /.yarn/versions/43e6a6fd.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@subql/network-query" 3 | -------------------------------------------------------------------------------- /.yarn/versions/4611bcd1.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@subql/network-clients" 3 | -------------------------------------------------------------------------------- /.yarn/versions/4b0751a0.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@subql/network-query" 3 | -------------------------------------------------------------------------------- /.yarn/versions/4dd32d98.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@subql/network-config" 3 | - "@subql/network-query" 4 | -------------------------------------------------------------------------------- /.yarn/versions/53381b35.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zikc2023/network-clients/e8cc36aa249735ba82a783f8ef7e6af165d6b986/.yarn/versions/53381b35.yml -------------------------------------------------------------------------------- /.yarn/versions/5368cde2.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@subql/network-query" 3 | -------------------------------------------------------------------------------- /.yarn/versions/53bb2961.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zikc2023/network-clients/e8cc36aa249735ba82a783f8ef7e6af165d6b986/.yarn/versions/53bb2961.yml -------------------------------------------------------------------------------- /.yarn/versions/550ce4a4.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zikc2023/network-clients/e8cc36aa249735ba82a783f8ef7e6af165d6b986/.yarn/versions/550ce4a4.yml -------------------------------------------------------------------------------- /.yarn/versions/57521769.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zikc2023/network-clients/e8cc36aa249735ba82a783f8ef7e6af165d6b986/.yarn/versions/57521769.yml -------------------------------------------------------------------------------- /.yarn/versions/5cfb8237.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zikc2023/network-clients/e8cc36aa249735ba82a783f8ef7e6af165d6b986/.yarn/versions/5cfb8237.yml -------------------------------------------------------------------------------- /.yarn/versions/5dcc6c60.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zikc2023/network-clients/e8cc36aa249735ba82a783f8ef7e6af165d6b986/.yarn/versions/5dcc6c60.yml -------------------------------------------------------------------------------- /.yarn/versions/62eb43a3.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@subql/network-query" 3 | -------------------------------------------------------------------------------- /.yarn/versions/6332090f.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zikc2023/network-clients/e8cc36aa249735ba82a783f8ef7e6af165d6b986/.yarn/versions/6332090f.yml -------------------------------------------------------------------------------- /.yarn/versions/69510e87.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@subql/network-query" 3 | -------------------------------------------------------------------------------- /.yarn/versions/708b44a5.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zikc2023/network-clients/e8cc36aa249735ba82a783f8ef7e6af165d6b986/.yarn/versions/708b44a5.yml -------------------------------------------------------------------------------- /.yarn/versions/78f9ca83.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@subql/network-query" 3 | -------------------------------------------------------------------------------- /.yarn/versions/7cb66ab7.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zikc2023/network-clients/e8cc36aa249735ba82a783f8ef7e6af165d6b986/.yarn/versions/7cb66ab7.yml -------------------------------------------------------------------------------- /.yarn/versions/7e518aa5.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@subql/network-query" 3 | -------------------------------------------------------------------------------- /.yarn/versions/83a877aa.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@subql/network-query" 3 | -------------------------------------------------------------------------------- /.yarn/versions/850203aa.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zikc2023/network-clients/e8cc36aa249735ba82a783f8ef7e6af165d6b986/.yarn/versions/850203aa.yml -------------------------------------------------------------------------------- /.yarn/versions/88308c77.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@subql/network-config" 3 | -------------------------------------------------------------------------------- /.yarn/versions/8c12a9d7.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@subql/network-query" 3 | -------------------------------------------------------------------------------- /.yarn/versions/8c76dae9.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@subql/network-config" 3 | -------------------------------------------------------------------------------- /.yarn/versions/8d5f68de.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@subql/network-query" 3 | -------------------------------------------------------------------------------- /.yarn/versions/8f3f4961.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zikc2023/network-clients/e8cc36aa249735ba82a783f8ef7e6af165d6b986/.yarn/versions/8f3f4961.yml -------------------------------------------------------------------------------- /.yarn/versions/9045847e.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@subql/network-query" 3 | -------------------------------------------------------------------------------- /.yarn/versions/96813870.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@subql/apollo-links" 3 | - "@subql/network-clients" 4 | - "@subql/network-config" 5 | - "@subql/network-query" 6 | -------------------------------------------------------------------------------- /.yarn/versions/992a80f3.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zikc2023/network-clients/e8cc36aa249735ba82a783f8ef7e6af165d6b986/.yarn/versions/992a80f3.yml -------------------------------------------------------------------------------- /.yarn/versions/9dbfa029.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@subql/network-query" 3 | -------------------------------------------------------------------------------- /.yarn/versions/a8755ed1.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@subql/network-query" 3 | -------------------------------------------------------------------------------- /.yarn/versions/b3e0f960.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@subql/network-query" 3 | -------------------------------------------------------------------------------- /.yarn/versions/cba20470.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zikc2023/network-clients/e8cc36aa249735ba82a783f8ef7e6af165d6b986/.yarn/versions/cba20470.yml -------------------------------------------------------------------------------- /.yarn/versions/cdfdcc75.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zikc2023/network-clients/e8cc36aa249735ba82a783f8ef7e6af165d6b986/.yarn/versions/cdfdcc75.yml -------------------------------------------------------------------------------- /.yarn/versions/d272c05b.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@subql/network-query" 3 | -------------------------------------------------------------------------------- /.yarn/versions/da309c78.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@subql/network-query" 3 | -------------------------------------------------------------------------------- /.yarn/versions/dea7a49c.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zikc2023/network-clients/e8cc36aa249735ba82a783f8ef7e6af165d6b986/.yarn/versions/dea7a49c.yml -------------------------------------------------------------------------------- /.yarn/versions/e0bb153c.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zikc2023/network-clients/e8cc36aa249735ba82a783f8ef7e6af165d6b986/.yarn/versions/e0bb153c.yml -------------------------------------------------------------------------------- /.yarn/versions/e0f57c21.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zikc2023/network-clients/e8cc36aa249735ba82a783f8ef7e6af165d6b986/.yarn/versions/e0f57c21.yml -------------------------------------------------------------------------------- /.yarn/versions/e133d23a.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@subql/react-hooks" 3 | -------------------------------------------------------------------------------- /.yarn/versions/e90f7bfc.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@subql/network-clients" 3 | -------------------------------------------------------------------------------- /.yarn/versions/ec02d70e.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@subql/react-hooks" 3 | -------------------------------------------------------------------------------- /.yarn/versions/ed70da4a.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@subql/network-query" 3 | -------------------------------------------------------------------------------- /.yarn/versions/efedca0e.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zikc2023/network-clients/e8cc36aa249735ba82a783f8ef7e6af165d6b986/.yarn/versions/efedca0e.yml -------------------------------------------------------------------------------- /.yarn/versions/f161440e.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zikc2023/network-clients/e8cc36aa249735ba82a783f8ef7e6af165d6b986/.yarn/versions/f161440e.yml -------------------------------------------------------------------------------- /.yarn/versions/f72a513a.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zikc2023/network-clients/e8cc36aa249735ba82a783f8ef7e6af165d6b986/.yarn/versions/f72a513a.yml -------------------------------------------------------------------------------- /.yarn/versions/fb87cd42.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zikc2023/network-clients/e8cc36aa249735ba82a783f8ef7e6af165d6b986/.yarn/versions/fb87cd42.yml -------------------------------------------------------------------------------- /.yarn/versions/fe02ac81.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zikc2023/network-clients/e8cc36aa249735ba82a783f8ef7e6af165d6b986/.yarn/versions/fe02ac81.yml -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nodeLinker: node-modules 2 | 3 | npmAuthToken: "${NPM_AUTH_TOKEN:-}" 4 | 5 | httpTimeout: 30000 6 | 7 | plugins: 8 | - path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs 9 | spec: "@yarnpkg/plugin-workspace-tools" 10 | - path: .yarn/plugins/@yarnpkg/plugin-version.cjs 11 | spec: "@yarnpkg/plugin-version" 12 | 13 | yarnPath: .yarn/releases/yarn-3.2.4.cjs 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Subquery Network - Client SDKs 2 | 3 | SubQuery Network Client SDKs provides various tools to allow you to connect your dApps and services to the SubQuery network easier. 4 | 5 | ## Components 6 | 7 | - [`@subql/apollo-links`](packages/apollo-links) 8 | - [`@subql/network-clients`](packages/network-clients) 9 | - [`@subql/network-query`](packages/network-query) 10 | - [`@subql/react-hooks`](packages/react-hooks) 11 | 12 | ## Developer Guide 13 | 14 | ### Update Changelog 15 | 16 | - Use https://github.com/geut/chan 17 | - Go into the package folder first, than use `chan` to add changes 18 | 19 | ### Release Version Bump 20 | 21 | - use `yarn version [minor|patch|major]` 22 | -------------------------------------------------------------------------------- /__mocks__/axios.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2023 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import mockAxios from 'jest-mock-axios'; 5 | export default mockAxios; 6 | -------------------------------------------------------------------------------- /jest.config.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | export default { 5 | // Automatically clear mock calls, instances, contexts and results before every test 6 | clearMocks: true, 7 | 8 | // Indicates whether the coverage information should be collected while executing the test 9 | collectCoverage: true, 10 | 11 | // The directory where Jest should output its coverage files 12 | coverageDirectory: 'coverage', 13 | 14 | // Indicates which provider should be used to instrument code for coverage 15 | coverageProvider: 'v8', 16 | 17 | // A set of global variables that need to be available in all test environments 18 | globals: { 19 | 'ts-jest': { 20 | tsconfig: 'tsconfig.test.json', 21 | }, 22 | }, 23 | 24 | // An array of file extensions your modules use 25 | moduleFileExtensions: ['js', 'ts', 'json', 'tsx'], 26 | 27 | // The paths to modules that run some code to configure or set up the testing environment before each test 28 | setupFiles: ['./test/jest-setup.ts'], 29 | 30 | // A map from regular expressions to paths to transformers 31 | transform: { 32 | '^.+\\.(ts|tsx)?$': 'ts-jest', 33 | '^.+\\.(js|jsx)$': 'babel-jest', 34 | }, 35 | 36 | // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation 37 | transformIgnorePatterns: ['node_modules/(?!(@polkadot|@subql|@babel/runtime/helpers/esm)/)'], 38 | }; 39 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@subql/network-tools", 3 | "description": "Client sdk for Subquery Network", 4 | "scripts": { 5 | "build": "yarn workspaces foreach -pt run build", 6 | "lint": "eslint . --ext .ts,.tsx", 7 | "postinstall": "husky install", 8 | "test": "jest --passWithNoTests --detectOpenHandles --testTimeout=160000" 9 | }, 10 | "author": "SubQuery Pte Limited", 11 | "license": "Apache-2.0", 12 | "private": true, 13 | "devDependencies": { 14 | "@actions/core": "^1.9.1", 15 | "@apollo/client": "^3.8.8", 16 | "@metamask/eth-sig-util": "^4.0.1", 17 | "@octokit/request": "^5.6.3", 18 | "@subql/contract-sdk": "1.0.3", 19 | "@testing-library/react": "^14.0.0", 20 | "@types/jest": "^28.1.6", 21 | "@types/react": "^18.2.28", 22 | "@typescript-eslint/eslint-plugin": "^5.27.0", 23 | "@typescript-eslint/parser": "^5.27.0", 24 | "axios": "^0.27.2", 25 | "ctix": "^1.5.4", 26 | "dotenv": "^16.0.3", 27 | "eslint": "^8.17.0", 28 | "eslint-plugin-header": "^3.1.1", 29 | "eslint-plugin-prettier": "^4.0.0", 30 | "flag": "^5.0.1", 31 | "graphql": "^16.5.0", 32 | "graphql-language-service-server": "^2.8.9", 33 | "husky": "^8.0.1", 34 | "ipfs-http-client": "^53.0.1", 35 | "jest": "^29.6.2", 36 | "jest-environment-jsdom": "^29.7.0", 37 | "jest-mock-axios": "^4.7.2", 38 | "jwt-decode": "^3.1.2", 39 | "lint-staged": "^13.0.0", 40 | "prettier": "^2.7.1", 41 | "react": "^18.1.0", 42 | "react-dom": "^18.2.0", 43 | "ts-jest": "^29.1.1", 44 | "ts-node": "^10.8.1" 45 | }, 46 | "workspaces": [ 47 | "packages/network-config", 48 | "packages/network-query", 49 | "packages/apollo-links", 50 | "packages/network-clients", 51 | "packages/react-hooks", 52 | "packages/eth-provider", 53 | "packages/network-support" 54 | ], 55 | "lint-staged": { 56 | "*.{ts,tsx}": [ 57 | "eslint --cache --fix", 58 | "prettier --write" 59 | ] 60 | }, 61 | "packageManager": "yarn@3.2.4" 62 | } 63 | -------------------------------------------------------------------------------- /packages/apollo-links/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [Unreleased] 9 | 10 | ## [1.4.2] - 2024-05-13 11 | 12 | ## [1.4.1] - 2024-05-12 13 | 14 | ## [1.4.0] - 2024-04-29 15 | 16 | ## [1.3.2] - 2024-01-26 17 | 18 | ## [1.3.0] - 2024-01-22 19 | 20 | ## [1.2.6] - 2024-01-11 21 | 22 | ## [1.2.5] - 2023-12-21 23 | 24 | ## [1.2.4] - 2023-12-21 25 | 26 | ## [1.2.3] - 2023-11-27 27 | 28 | ## [1.2.2] - 2023-11-13 29 | 30 | ## [1.1.0] - 2023-10-13 31 | 32 | - Support new communication protocol 33 | 34 | ## [1.0.8] - 2023-09-07 35 | 36 | - Enable base64 encoding for payg signature 37 | 38 | ## [1.0.4] - 2023-09-01 39 | 40 | ## [1.0.2] - 2023-08-31 41 | 42 | - Increase default max retry to `8` 43 | - Fix issue for filter out unavailable indexers 44 | - Downgrade all the log level to `debug` 45 | 46 | ## [1.0.0] - 2023-08-25 47 | 48 | Breaking change for `dictHttpLink` and `deploymentHttpLink`, use `const { link } = ...` for get the link. 49 | 50 | ## [0.5.7] - 2023-08-04 51 | 52 | ## [0.5.5] - 2023-07-21 53 | 54 | ## [0.5.3] - 2023-07-13 55 | 56 | ## [0.5.2] - 2023-06-19 57 | 58 | ### Changed 59 | 60 | - upgrade @metamask/eth-sig-util to ^5.1.0 61 | 62 | ## [0.5.1] - 2023-06-15 63 | 64 | ### Changed 65 | 66 | - Improve retry logic & logs (#129) 67 | 68 | ### Added 69 | 70 | - More unit tests for retry logic and fallover 71 | 72 | ## [0.5.0] - 2023-06-14 73 | 74 | ### Fixed 75 | 76 | - fix the apollo/client import to /core to avoid react dep (#125) 77 | 78 | ### Changed 79 | 80 | - separate the link create function for dict & project (#124) 81 | - rename projectHttpLink to deploymentHttpLink (#126) 82 | 83 | ## [0.4.0] - 2023-06-13 84 | 85 | ### Added 86 | 87 | - Feat/auth link routing (#122) 88 | 89 | ## [0.3.4] - 2023-06-13 90 | 91 | ### Added 92 | 93 | - Get networkChainId from authURl (#108) 94 | 95 | ### Fixed 96 | 97 | - Fix runtime error catch for authLink (#120) 98 | 99 | ## [0.2.1] - 2023-06-13 100 | 101 | ### Added 102 | 103 | - Add Authlink for Apollo client 104 | 105 | [unreleased]: https://github.com/subquery/network-clients/compare/v1.4.2...HEAD 106 | [1.4.2]: https://github.com/subquery/network-clients/compare/v1.4.1...v1.4.2 107 | [1.4.1]: https://github.com/subquery/network-clients/compare/v1.4.0...v1.4.1 108 | [1.4.0]: https://github.com/subquery/network-clients/compare/v1.3.2...v1.4.0 109 | [1.3.2]: https://github.com/subquery/network-clients/compare/v1.3.0...v1.3.2 110 | [1.3.0]: https://github.com/subquery/network-clients/compare/v1.2.6...v1.3.0 111 | [1.2.6]: https://github.com/subquery/network-clients/compare/v1.2.4...v1.2.6 112 | [1.2.5]: https://github.com/subquery/network-clients/compare/v1.2.4...v1.2.5 113 | [1.2.4]: https://github.com/subquery/network-clients/compare/v1.2.3...v1.2.4 114 | [1.2.3]: https://github.com/subquery/network-clients/compare/v1.2.2...v1.2.3 115 | [1.2.2]: https://github.com/subquery/network-clients/compare/v1.1.0...v1.2.2 116 | [1.1.0]: https://github.com/subquery/network-clients/compare/v1.0.8...v1.1.0 117 | [1.0.8]: https://github.com/subquery/network-clients/compare/v1.0.4...v1.0.8 118 | [1.0.4]: https://github.com/subquery/network-clients/compare/v1.0.2...v1.0.4 119 | [1.0.2]: https://github.com/subquery/network-clients/compare/v1.0.0...v1.0.2 120 | [1.0.0]: https://github.com/subquery/network-clients/compare/v0.5.7...v1.0.0 121 | [0.5.7]: https://github.com/subquery/network-clients/compare/v0.5.5...v0.5.7 122 | [0.5.5]: https://github.com/subquery/network-clients/compare/v0.5.3...v0.5.5 123 | [0.5.3]: https://github.com/subquery/network-clients/compare/v0.5.2...v0.5.3 124 | [0.5.2]: https://github.com/subquery/network-clients/compare/v0.5.1...v0.5.2 125 | [0.5.1]: https://github.com/subquery/network-clients/compare/v0.5.0...v0.5.1 126 | [0.5.0]: https://github.com/subquery/network-clients/compare/v0.4.0...v0.5.0 127 | [0.4.0]: https://github.com/subquery/network-clients/compare/v0.3.4...v0.4.0 128 | [0.3.4]: https://github.com/subquery/network-clients/compare/v0.2.1...v0.3.4 129 | [0.2.1]: https://github.com/subquery/network-clients/releases/tag/v0.2.1 130 | -------------------------------------------------------------------------------- /packages/apollo-links/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@subql/apollo-links", 3 | "version": "1.4.2", 4 | "description": "SubQuery Network - graphql links", 5 | "main": "dist/index.js", 6 | "author": "SubQuery Pte Limited", 7 | "license": "Apache-2.0", 8 | "scripts": { 9 | "build": "tsc -b" 10 | }, 11 | "dependencies": { 12 | "@apollo/client": "^3.8.8", 13 | "@metamask/eth-sig-util": "5.1.0", 14 | "@subql/network-support": "workspace:*", 15 | "apollo-link-error": "^1.1.13", 16 | "buffer": "^6.0.3", 17 | "cross-fetch": "^4.0.0", 18 | "js-base64": "^3.7.5", 19 | "jwt-decode": "^3.1.2", 20 | "lru-cache": "^10.0.1" 21 | }, 22 | "devDependencies": { 23 | "apollo": "^2.34.0", 24 | "pino": "^8.14.1", 25 | "typescript": "^4.6.4" 26 | }, 27 | "peerDependencies": { 28 | "graphql": "*" 29 | }, 30 | "stableVersion": "1.3.0" 31 | } 32 | -------------------------------------------------------------------------------- /packages/apollo-links/src/auth/authHelper.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import buffer from 'buffer'; 5 | import { signTypedData, SignTypedDataVersion } from '@metamask/eth-sig-util'; 6 | import { POST } from '@subql/network-support'; 7 | 8 | import { AuthMessage, buildTypedMessage, createAuthRequestBody } from './eip712'; 9 | 10 | const Buffer = buffer.Buffer; 11 | 12 | export function signMessage(msg: AuthMessage, sk: string, chainId: number): string { 13 | if (!sk) return ''; 14 | 15 | return signTypedData({ 16 | privateKey: Buffer.from(sk, 'hex'), 17 | data: buildTypedMessage(msg, chainId), 18 | version: SignTypedDataVersion.V4, 19 | }); 20 | } 21 | 22 | export async function requestAuthToken( 23 | authUrl: string, 24 | msg: AuthMessage, 25 | sk: string, 26 | chainId: number 27 | ): Promise { 28 | const signature = signMessage(msg, sk, chainId); 29 | if (!signature) return ''; 30 | 31 | const body = createAuthRequestBody(msg, signature, chainId); 32 | const res = await POST<{ token: string }>(authUrl, body); 33 | return res.token; 34 | } 35 | -------------------------------------------------------------------------------- /packages/apollo-links/src/auth/eip712.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { MessageTypes, TypedMessage } from '@metamask/eth-sig-util'; 5 | 6 | export interface Message { 7 | [key: string]: string | number | undefined; 8 | indexer: string; 9 | deploymentId: string; 10 | agreement?: string; 11 | consumer?: string; 12 | } 13 | 14 | export interface AuthMessage extends Message { 15 | timestamp: number; 16 | } 17 | 18 | const EIP712Domain = [ 19 | { name: 'name', type: 'string' }, 20 | { name: 'chainId', type: 'uint256' }, 21 | ]; 22 | 23 | const ConsumerMessageType = [ 24 | { name: 'consumer', type: 'address' }, 25 | { name: 'indexer', type: 'address' }, 26 | { name: 'agreement', type: 'string' }, 27 | { name: 'timestamp', type: 'uint256' }, 28 | { name: 'deploymentId', type: 'string' }, 29 | ]; 30 | 31 | const IndexerMessageType = [ 32 | { name: 'indexer', type: 'address' }, 33 | { name: 'timestamp', type: 'uint256' }, 34 | { name: 'deploymentId', type: 'string' }, 35 | ]; 36 | 37 | export function buildTypedMessage( 38 | message: AuthMessage, 39 | chainId = 1287 40 | ): TypedMessage { 41 | const messageType = message.consumer ? ConsumerMessageType : IndexerMessageType; 42 | const domain = { name: 'Subquery', chainId }; 43 | 44 | return { 45 | types: { 46 | EIP712Domain, 47 | messageType, 48 | }, 49 | primaryType: 'messageType', 50 | domain, 51 | message, 52 | }; 53 | } 54 | 55 | export function createAuthRequestBody(message: AuthMessage, signature: string, chainId = 137) { 56 | const { consumer, indexer, agreement, deploymentId, timestamp } = message; 57 | const baseBody = { 58 | indexer, 59 | timestamp, 60 | signature: signature.replace(/^0x/, ''), 61 | deployment_id: deploymentId, 62 | chain_id: chainId, 63 | }; 64 | 65 | return consumer ? { ...baseBody, consumer, agreement } : baseBody; 66 | } 67 | -------------------------------------------------------------------------------- /packages/apollo-links/src/auth/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | export * from './authHelper'; 5 | export * from './eip712'; 6 | -------------------------------------------------------------------------------- /packages/apollo-links/src/authHttpLink.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2023 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { ApolloLink, from } from '@apollo/client/core'; 5 | import { 6 | IStore, 7 | OrderManager, 8 | ResponseFormat, 9 | RunnerSelector, 10 | setFetchTimeout, 11 | } from '@subql/network-support'; 12 | import { 13 | ClusterAuthLink, 14 | createRetryLink, 15 | creatErrorLink, 16 | DynamicHttpLink, 17 | FallbackLink, 18 | Options, 19 | ResponseLink, 20 | } from './core'; 21 | import { ProjectType } from './types'; 22 | import { Logger, silentLogger } from './utils/logger'; 23 | 24 | interface BaseAuthOptions { 25 | authUrl: string; // auth service url 26 | httpOptions: Options['httpOptions']; // http options for init `HttpLink` 27 | logger?: Logger; // logger for `AuthLink` 28 | fallbackServiceUrl?: string; // fall back service url for `AuthLink` 29 | scoreStore?: IStore; // pass store in, so it doesn't get lost between page refresh 30 | stateStore?: IStore; 31 | selector?: RunnerSelector; 32 | maxRetries?: number; 33 | useImmediateFallbackOnError?: boolean; 34 | timeout?: number; 35 | } 36 | 37 | export interface DictAuthOptions extends BaseAuthOptions { 38 | chainId: string; // chain id for the requested dictionary 39 | } 40 | 41 | export interface DeploymentAuthOptions extends BaseAuthOptions { 42 | deploymentId: string; // deployment id 43 | } 44 | 45 | export interface AuthOptions extends DeploymentAuthOptions { 46 | projectType: ProjectType; // order type 47 | } 48 | 49 | interface AuthHttpLink { 50 | link: ApolloLink; 51 | cleanup: () => void; 52 | } 53 | 54 | export function dictHttpLink(options: DictAuthOptions): AuthHttpLink { 55 | const { chainId } = options; 56 | return authHttpLink({ ...options, deploymentId: chainId, projectType: ProjectType.dictionary }); 57 | } 58 | 59 | export function deploymentHttpLink(options: DeploymentAuthOptions): AuthHttpLink { 60 | return authHttpLink({ ...options, projectType: ProjectType.deployment }); 61 | } 62 | 63 | function authHttpLink(options: AuthOptions): AuthHttpLink { 64 | const { 65 | deploymentId, 66 | httpOptions, 67 | fallbackServiceUrl, 68 | authUrl, 69 | projectType, 70 | scoreStore, 71 | stateStore, 72 | maxRetries, 73 | useImmediateFallbackOnError = false, 74 | logger: _logger, 75 | timeout = 60000, 76 | selector, 77 | } = options; 78 | setFetchTimeout(timeout); 79 | 80 | const logger = _logger ?? silentLogger(); 81 | const orderManager = new OrderManager({ 82 | authUrl, 83 | fallbackServiceUrl, 84 | projectId: deploymentId, 85 | projectType, 86 | logger, 87 | scoreStore, 88 | stateStore, 89 | responseFormat: ResponseFormat.Inline, 90 | selector, 91 | timeout, 92 | }); 93 | 94 | const retryLink = createRetryLink({ orderManager, logger, maxRetries }); 95 | const fallbackLink = new FallbackLink(fallbackServiceUrl, logger); 96 | const httpLink = new DynamicHttpLink({ httpOptions, logger }); 97 | const responseLink = new ResponseLink({ authUrl, orderManager, logger }); 98 | const errorLink = creatErrorLink({ 99 | orderManager, 100 | fallbackLink, 101 | httpLink, 102 | useImmediateFallbackOnError, 103 | logger, 104 | }); 105 | const authLink = new ClusterAuthLink({ 106 | authUrl, 107 | projectId: deploymentId, 108 | logger, 109 | orderManager, 110 | }); 111 | 112 | const cleanup = () => { 113 | // add more cleanup logic here if needed 114 | orderManager.cleanup(); 115 | }; 116 | 117 | // 1. errorLink: This link helps in handling and logging any GraphQL or network errors that may occur down the chain. 118 | // Placing it at the beginning ensures that it catches any errors that may occur in any of the other links. 119 | // 2. retryLink: This comes after the errorLink to allow it to handle network errors and retry requests if necessary. 120 | // 3. authLink: The authLink comes next. It is responsible for adding authentication credentials to every request. 121 | // 4. httpLink: This should always be at the end of the link chain. This link is responsible for sending the request to the server. 122 | const link = from([errorLink, retryLink, authLink, fallbackLink, responseLink, httpLink]); 123 | 124 | return { link, cleanup }; 125 | } 126 | -------------------------------------------------------------------------------- /packages/apollo-links/src/core/authLink.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2023 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { ApolloLink, FetchResult, NextLink, Observable, Operation } from '@apollo/client/core'; 5 | import { isTokenExpired } from '@subql/network-support'; 6 | import { Subscription } from 'zen-observable-ts'; 7 | 8 | import { Message, requestAuthToken } from '../auth'; 9 | import { Logger } from '../utils/logger'; 10 | 11 | interface AuthOptions extends Message { 12 | indexerUrl: string; // indexer url 13 | chainId: number; // chainId for the network 14 | sk: string; // `sk` of the consumer or corresponding controller account 15 | } 16 | 17 | export class AuthLink extends ApolloLink { 18 | private _options: AuthOptions; 19 | private _logger: Logger; 20 | private _token: string; 21 | 22 | constructor(options: AuthOptions, logger: Logger, token = '') { 23 | super(); 24 | this._options = options; 25 | this._logger = logger; 26 | this._token = token; 27 | } 28 | 29 | override request(operation: Operation, forward?: NextLink): Observable | null { 30 | if (!forward) return null; 31 | 32 | return new Observable((observer) => { 33 | let sub: Subscription; 34 | this.getUrlAndToken() 35 | .then((data) => { 36 | if (data) { 37 | const { token, url } = data; 38 | const headers = { authorization: `Bearer ${token}` }; 39 | operation.setContext({ url, headers }); 40 | } 41 | }) 42 | .catch((error) => observer.error(error)) 43 | .finally(() => { 44 | sub = forward(operation).subscribe(observer); 45 | }); 46 | 47 | return () => sub?.unsubscribe(); 48 | }); 49 | } 50 | 51 | get queryEndpoint() { 52 | const url = new URL('/query', this._options.indexerUrl); 53 | return url.toString(); 54 | } 55 | 56 | private generateMessage() { 57 | const { indexer, consumer, agreement, deploymentId } = this._options; 58 | const timestamp = new Date().getTime(); 59 | return { indexer, consumer, agreement, deploymentId, timestamp }; 60 | } 61 | 62 | private async getUrlAndToken(): Promise<{ url: string; token: string } | undefined> { 63 | if (!isTokenExpired(this._token)) return { token: this._token, url: this.queryEndpoint }; 64 | 65 | const { sk, chainId, agreement, indexerUrl } = this._options; 66 | 67 | if (!chainId || !agreement) throw new Error('chainId and agreement are required'); 68 | 69 | const message = this.generateMessage(); 70 | const tokenUrl = new URL('/token', indexerUrl); 71 | const authToken = await requestAuthToken(tokenUrl.toString(), message, sk, chainId); 72 | this._token = authToken; 73 | 74 | return { token: authToken, url: this.queryEndpoint }; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /packages/apollo-links/src/core/clusterAuthLink.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { ApolloLink, FetchResult, NextLink, Observable, Operation } from '@apollo/client/core'; 5 | import { OrderManager, generateUniqueId } from '@subql/network-support'; 6 | import { Subscription } from 'zen-observable-ts'; 7 | 8 | import { Logger } from '../utils/logger'; 9 | 10 | export type ClusterAuthLinkOptions = { 11 | authUrl: string; // the url for geting token 12 | projectId: string; // chainId or deploymentId for the project 13 | orderManager: OrderManager; // agreement manager for managing agreements 14 | logger: Logger; // logger for logging 15 | }; 16 | 17 | export class ClusterAuthLink extends ApolloLink { 18 | private options: ClusterAuthLinkOptions; 19 | private logger: Logger; 20 | private orderManager: OrderManager; 21 | 22 | constructor(options: ClusterAuthLinkOptions) { 23 | super(); 24 | this.options = options; 25 | this.logger = options.logger; 26 | this.orderManager = options.orderManager; 27 | } 28 | 29 | override request(operation: Operation, forward?: NextLink): Observable | null { 30 | if (!forward) return null; 31 | 32 | return new Observable((observer) => { 33 | let sub: Subscription; 34 | 35 | this.orderManager 36 | .getRequestParams(this.getRequestId(operation)) 37 | .then((params) => { 38 | if (params) { 39 | const { headers, url, type, runner, channelId } = params; 40 | operation.setContext({ url, headers, type, indexer: runner, channelId }); 41 | sub = forward(operation).subscribe(observer); 42 | } else { 43 | this.logger?.debug('no available orders'); 44 | // For handling if one indexer's score is not enough for reduce retries times 45 | // e.g indexer have 10 score, when first failed, the score is reach to 0, 46 | // but because at above code set the url & indexer. retryLink also believe it's a 47 | // valid url. so re-try again. 48 | // set url is null-string can enter fallbackLink to handle if use fallback link 49 | // otherwise would re-try until reach the max retires. 50 | operation.setContext({ url: '' }); 51 | sub = forward(operation).subscribe(observer); 52 | } 53 | }) 54 | .catch((error) => { 55 | if (error.indexer) { 56 | this.logger?.debug(`Failed to get token: ${String(error.message)}`); 57 | operation.setContext({ indexer: error.indexer }); 58 | observer.error(new Error('failed to get indexer request params')); 59 | } else { 60 | this.logger?.debug(`Failed to get order request params: ${String(error.message)}`); 61 | observer.error(new Error('failed to get indexer url and token')); 62 | } 63 | }); 64 | 65 | return () => sub?.unsubscribe(); 66 | }); 67 | } 68 | 69 | private tokenToAuthHeader(token: string) { 70 | return { authorization: `Bearer ${token}` }; 71 | } 72 | 73 | private getRequestId(operation: Operation): string { 74 | let { requestId } = operation.getContext(); 75 | if (requestId) return requestId; 76 | requestId = generateUniqueId(); 77 | operation.setContext({ requestId }); 78 | return requestId; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /packages/apollo-links/src/core/dynamicHttpLink.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { 5 | ApolloLink, 6 | FetchResult, 7 | HttpLink, 8 | HttpOptions, 9 | NextLink, 10 | Observable, 11 | Operation, 12 | } from '@apollo/client/core'; 13 | import { customFetch, timeoutController } from '@subql/network-support'; 14 | import { Logger } from '../utils/logger'; 15 | 16 | export type Options = { 17 | httpOptions: { 18 | /** 19 | * @remarks 20 | * Please confirm your `fetch` attaches headers `Content-Type` and `Content-Length`. 21 | */ 22 | fetch?: HttpOptions['fetch']; 23 | } & HttpOptions; // http options for init `HttpLink` 24 | logger?: Logger; 25 | }; 26 | 27 | export class DynamicHttpLink extends ApolloLink { 28 | private options: Options; 29 | 30 | constructor(options: Options) { 31 | super(); 32 | this.options = options; 33 | } 34 | 35 | get logger(): Logger | undefined { 36 | return this.options.logger; 37 | } 38 | 39 | override request(operation: Operation, forward?: NextLink): Observable | null { 40 | const { url } = operation.getContext(); 41 | if (!url) { 42 | return new Observable((observer) => { 43 | observer.error(new Error(`empty url`)); 44 | }); 45 | } 46 | 47 | this.logger?.debug(`use url: ${url}`); 48 | const httpLink = this.createHttpLink(url); 49 | 50 | return httpLink.request(operation, forward); 51 | } 52 | 53 | private createHttpLink(uri: string): HttpLink { 54 | return new HttpLink({ 55 | ...this.options.httpOptions, 56 | fetchOptions: { 57 | ...this.options.httpOptions.fetchOptions, 58 | signal: timeoutController().signal, 59 | }, 60 | // note: fetch signal is not work even the signle is on customFetch, must pass timeout signle to fetchOptions 61 | fetch: this.options.httpOptions.fetch ? this.options.httpOptions.fetch : customFetch, 62 | uri, 63 | }); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /packages/apollo-links/src/core/errorLink.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { ApolloLink, FetchResult, NextLink, Observable } from '@apollo/client/core'; 5 | import { onError } from '@apollo/client/link/error'; 6 | import { OrderManager, ScoreType } from '@subql/network-support'; 7 | import { Logger } from '../utils/logger'; 8 | 9 | export type ErrorLinkOption = { 10 | orderManager: OrderManager; 11 | fallbackLink: ApolloLink; 12 | httpLink: ApolloLink; 13 | useImmediateFallbackOnError?: boolean; 14 | logger?: Logger; 15 | }; 16 | 17 | export const creatErrorLink = ({ 18 | fallbackLink, 19 | httpLink, 20 | orderManager, 21 | useImmediateFallbackOnError, 22 | logger, 23 | }: ErrorLinkOption) => 24 | onError(({ graphQLErrors, networkError, operation, forward }) => { 25 | const { indexer } = operation.getContext(); 26 | if (networkError) { 27 | orderManager.updateScore(indexer, ScoreType.NETWORK); 28 | logger?.debug(`[Network error]: ${networkError}`); 29 | } 30 | 31 | if (graphQLErrors) { 32 | graphQLErrors.forEach(({ message, locations, path }) => { 33 | orderManager.updateScore(indexer, ScoreType.GRAPHQL); 34 | logger?.debug( 35 | `[GraphQL error]: Message: ${message}, Location: ${JSON.stringify( 36 | locations 37 | )}, Path: ${path}` 38 | ); 39 | }); 40 | } 41 | // graphql error is 200 status. 200 would not handle by retryLink. 42 | // network error will retry before enter this handler. 43 | // both them are need use fallback url to retry. 44 | if (networkError || graphQLErrors) { 45 | if (!operation.getContext().fallback) { 46 | operation.setContext({ url: undefined }); 47 | return fallbackLink.request( 48 | operation, 49 | httpLink.request.bind(httpLink) as NextLink 50 | ) as Observable; 51 | } 52 | } 53 | 54 | return forward(operation); 55 | }); 56 | -------------------------------------------------------------------------------- /packages/apollo-links/src/core/fallbackLink.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { ApolloLink, Operation, NextLink, Observable, FetchResult } from '@apollo/client/core'; 5 | import { Logger } from '../utils/logger'; 6 | 7 | export class FallbackLink extends ApolloLink { 8 | constructor(private url?: string, private logger?: Logger) { 9 | super(); 10 | } 11 | 12 | override request(operation: Operation, forward?: NextLink): Observable | null { 13 | if (!forward) return null; 14 | 15 | return new Observable((observer) => { 16 | if (!operation.getContext().url) { 17 | if (this.url) { 18 | this.logger?.debug(`use fallback url: ${this.url}`); 19 | } 20 | operation.setContext({ url: this.url, fallback: true }); 21 | } 22 | const subscription = forward(operation).subscribe(observer); 23 | return () => subscription.unsubscribe(); 24 | }); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /packages/apollo-links/src/core/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2023 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | export * from './authLink'; 5 | export * from './clusterAuthLink'; 6 | export * from './dynamicHttpLink'; 7 | export * from './errorLink'; 8 | export * from './fallbackLink'; 9 | export * from './responseLink'; 10 | export * from './retryLink'; 11 | -------------------------------------------------------------------------------- /packages/apollo-links/src/core/responseLink.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { ApolloLink, FetchResult, NextLink, Observable, Operation } from '@apollo/client/core'; 5 | import { ChannelState, OrderManager, OrderType, ScoreType, State } from '@subql/network-support'; 6 | import { Base64 } from 'js-base64'; 7 | import { Logger } from '../utils/logger'; 8 | 9 | export type ResponseLinkOptions = { 10 | authUrl: string; 11 | orderManager: OrderManager; 12 | logger?: Logger; 13 | }; 14 | 15 | export class ResponseLink extends ApolloLink { 16 | constructor(private options: ResponseLinkOptions) { 17 | super(); 18 | } 19 | 20 | get logger(): Logger | undefined { 21 | return this.options.logger; 22 | } 23 | 24 | override request(operation: Operation, forward: NextLink): Observable | null { 25 | if (!forward) return null; 26 | 27 | const { type, indexer, channelId } = operation.getContext(); 28 | 29 | return new Observable((observer) => { 30 | const subscription = forward(operation).subscribe({ 31 | next: (response: FetchResult> & { state: State | ChannelState }) => { 32 | if (!response.errors || response.errors?.length === 0) { 33 | this.options.orderManager.updateScore(indexer, ScoreType.SUCCESS); 34 | } 35 | 36 | if (type === OrderType.flexPlan) { 37 | const responseHeaders = operation.getContext().response.headers; 38 | if (responseHeaders) { 39 | let channelState: State | ChannelState; 40 | if (responseHeaders.get('X-Channel-State')) { 41 | try { 42 | channelState = JSON.parse( 43 | Base64.decode(responseHeaders.get('X-Channel-State')).toString() 44 | ) as ChannelState; 45 | } catch { 46 | channelState = { 47 | authorization: responseHeaders.get('X-Channel-State'), 48 | }; 49 | } 50 | } else { 51 | channelState = response.state; 52 | } 53 | 54 | if (!channelState) { 55 | this.logger?.debug("Can't find the channel state information"); 56 | } 57 | void this.options.orderManager.syncChannelState(channelId, channelState); 58 | } 59 | } 60 | 61 | observer.next(response); 62 | }, 63 | error: observer.error.bind(observer), 64 | complete: observer.complete.bind(observer), 65 | }); 66 | 67 | return () => subscription.unsubscribe(); 68 | }); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /packages/apollo-links/src/core/retryLink.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import type { Operation } from '@apollo/client/core'; 5 | import { RetryLink } from '@apollo/client/link/retry'; 6 | import { OrderManager, ScoreType } from '@subql/network-support'; 7 | import { Logger } from '../utils/logger'; 8 | 9 | export type RetryLinkOption = { 10 | orderManager: OrderManager; 11 | maxRetries?: number; 12 | logger?: Logger; 13 | }; 14 | 15 | export const createRetryLink = ({ orderManager, maxRetries = 3, logger }: RetryLinkOption) => 16 | new RetryLink({ 17 | attempts: function (count: number, operation: Operation, error: any) { 18 | if (count <= maxRetries) { 19 | const { indexer } = operation.getContext(); 20 | orderManager.updateScore(indexer, ScoreType.NETWORK); 21 | 22 | const isEmptyUrlError = error?.message?.includes('empty url'); 23 | const isFallback = operation.getContext().fallback; 24 | if (!indexer && (isEmptyUrlError || isFallback)) { 25 | return false; 26 | } 27 | logger?.debug(`retry: ${count}/${maxRetries}`); 28 | return true; 29 | } 30 | logger?.debug(`reach max retries: ${maxRetries}`); 31 | return false; 32 | }, 33 | }); 34 | -------------------------------------------------------------------------------- /packages/apollo-links/src/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | export * from './authHttpLink'; 5 | export * from './auth'; 6 | export * from './core'; 7 | -------------------------------------------------------------------------------- /packages/apollo-links/src/types.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | export enum ProjectType { 5 | dictionary = 'dictionary', 6 | deployment = 'deployment', 7 | } 8 | -------------------------------------------------------------------------------- /packages/apollo-links/src/utils/logger.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | export interface LogFn { 5 | /* tslint:disable:no-unnecessary-generics */ 6 | (obj: T, msg?: string, ...args: any[]): void; 7 | (obj: unknown, msg?: string, ...args: any[]): void; 8 | (msg: string, ...args: any[]): void; 9 | } 10 | 11 | export type Logger = { 12 | error: LogFn; 13 | warn: LogFn; 14 | info: LogFn; 15 | debug: LogFn; 16 | }; 17 | 18 | export function silentLogger(): Logger { 19 | const logfn = (): void => undefined; 20 | return { 21 | debug: logfn, 22 | info: logfn, 23 | warn: logfn, 24 | error: logfn, 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /packages/apollo-links/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "target": "es2017", 5 | "sourceMap": true, 6 | "resolveJsonModule": true, 7 | "rootDir": "./src", 8 | "outDir": "./dist" 9 | }, 10 | "include": ["src/**/*", "test/**/*"] 11 | } 12 | -------------------------------------------------------------------------------- /packages/eth-provider/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [Unreleased] 9 | 10 | ## [1.1.1] 2024-05-13 11 | 12 | ## [1.1.0] 2024-05-12 13 | 14 | ## [1.0.0] 2024-02-21 15 | 16 | ## [0.2.0] 2024-01-22 17 | 18 | ## [0.1.0] 2023-11-27 19 | 20 | ### Added 21 | 22 | - Add Auth eth provider for rpc endpoint. 23 | 24 | [unreleased]: https://github.com/subquery/eth-provider/compare/v1.1.1...HEAD 25 | [1.1.1]: https://github.com/subquery/eth-provider/releases/tag/v1.1.1 26 | [1.1.0]: https://github.com/subquery/eth-provider/releases/tag/v1.1.0 27 | [1.0.0]: https://github.com/subquery/eth-provider/releases/tag/v1.0.0 28 | [0.2.0]: https://github.com/subquery/eth-provider/releases/tag/v0.2.0 29 | [0.1.0]: https://github.com/subquery/eth-provider/releases/tag/v0.1.0 30 | -------------------------------------------------------------------------------- /packages/eth-provider/README.md: -------------------------------------------------------------------------------- 1 | # eth-provider 2 | 3 | ``` 4 | import { SubqueryAuthedRpcProvider } from '@subql/eth-provider' 5 | 6 | const provider = new SubqueryAuthedRpcProvider({ 7 | deploymentId: "RPC deployment id" 8 | authUrl: "auth service url", 9 | selector: { // optional 10 | runnerAddresses: ["0x00000"] 11 | } 12 | }) 13 | ``` 14 | -------------------------------------------------------------------------------- /packages/eth-provider/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@subql/eth-provider", 3 | "version": "1.1.1", 4 | "main": "dist/index.js", 5 | "author": "SubQuery Pte Limited", 6 | "license": "Apache-2.0", 7 | "scripts": { 8 | "build": "tsc -b" 9 | }, 10 | "packageManager": "yarn@3.2.4", 11 | "dependencies": { 12 | "@ethersproject/providers": "^5.7.2", 13 | "@subql/network-support": "workspace:*", 14 | "typescript": "^4.6.4" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/eth-provider/src/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2023 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | export * from './provider'; 5 | -------------------------------------------------------------------------------- /packages/eth-provider/test/provider.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2023 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { Logger } from '@subql/apollo-links/dist/utils/logger'; 5 | import { SubqueryAuthedRpcProvider } from '../src/provider'; 6 | 7 | const mockLogger: Logger = { 8 | debug: jest.fn(console.log), 9 | error: jest.fn(console.log), 10 | warn: jest.fn(console.log), 11 | info: jest.fn(console.log), 12 | }; 13 | describe('eth provider', () => { 14 | it('can send rpc without network option', async () => { 15 | const privider = new SubqueryAuthedRpcProvider({ 16 | deploymentId: 'QmTeutqL8wQqzAdG8MNWMXxoz1LDkkRZkY6HEw1HbdT2um', 17 | authUrl: 'https://kepler-auth.thechaindata.com', 18 | logger: mockLogger, 19 | }); 20 | const res = await privider.send('eth_blockNumber', []); 21 | expect(res).toBeTruthy(); 22 | }); 23 | 24 | it('can send rpc with network option', async () => { 25 | const privider = new SubqueryAuthedRpcProvider({ 26 | deploymentId: 'QmTeutqL8wQqzAdG8MNWMXxoz1LDkkRZkY6HEw1HbdT2um', 27 | authUrl: 'https://kepler-auth.thechaindata.com', 28 | logger: mockLogger, 29 | network: 12345, 30 | }); 31 | const res = await privider.send('eth_blockNumber', []); 32 | expect(res).toBeTruthy(); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /packages/eth-provider/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "target": "es2017", 5 | "sourceMap": true, 6 | "resolveJsonModule": true, 7 | "rootDir": "./src", 8 | "outDir": "./dist" 9 | }, 10 | "include": ["src/**/*"] 11 | } 12 | -------------------------------------------------------------------------------- /packages/network-clients/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [Unreleased] 9 | 10 | ## [1.1.0] - 2024-02-21 11 | 12 | - Mainnet version 13 | 14 | ## [1.0.0] - 2024-02-21 15 | 16 | ## [0.114.0] - 2024-01-23 17 | 18 | ## [0.112.0] - 2023-12-19 19 | 20 | ## [0.111.0] - 2023-12-15 21 | 22 | Upgrade sdk 23 | 24 | ## [0.100.2] - 2023-11-24 25 | 26 | ## [0.100.0] - 2023-11-01 27 | 28 | ## [0.3.18] - 2023-09-28 29 | 30 | Upgrade @subql/contracts 31 | 32 | ## [0.3.17] - 2023-08-18 33 | 34 | ## [0.3.15] - 2023-07-21 35 | 36 | ## [0.3.13] - 2023-07-04 37 | 38 | ## [0.3.11] - 2023-07-04 39 | 40 | ## [0.3.9] - 2023-06-29 41 | 42 | ## [0.3.8] - 2023-06-29 43 | 44 | ## [0.3.7] - 2023-06-21 45 | 46 | ## [0.3.6] - 2023-06-21 47 | 48 | ## [0.3.4] - 2023-06-15 49 | 50 | ### Changed 51 | 52 | - Upgrade Contract SDK to `v0.13.4` (#131) 53 | 54 | ## [0.2.0] - 2022-08-17 55 | 56 | ### Added 57 | 58 | - Added gql queries and refactor the client constructor (#20) 59 | 60 | ## [0.1.0] - 2022-06-06 61 | 62 | ### Added 63 | 64 | - Release first version 65 | 66 | [unreleased]: https://github.com/subquery/network-clients/compare/v1.1.0...HEAD 67 | [1.1.0]: https://github.com/subquery/network-clients/compare/v1.0.0...v1.1.0 68 | [1.0.0]: https://github.com/subquery/network-clients/compare/v0.114.0...v1.0.0 69 | [0.114.0]: https://github.com/subquery/network-clients/compare/v0.112.0...v0.114.0 70 | [0.112.0]: https://github.com/subquery/network-clients/compare/v0.111.0...v0.112.0 71 | [0.111.0]: https://github.com/subquery/network-clients/compare/v0.100.2...v0.111.0 72 | [0.100.2]: https://github.com/subquery/network-clients/compare/v0.100.0...v0.100.2 73 | [0.100.0]: https://github.com/subquery/network-clients/compare/v0.3.18...v0.100.0 74 | [0.3.18]: https://github.com/subquery/network-clients/compare/v0.3.17...v0.3.18 75 | [0.3.17]: https://github.com/subquery/network-clients/compare/v0.3.15...v0.3.17 76 | [0.3.15]: https://github.com/subquery/network-clients/compare/v0.3.13...v0.3.15 77 | [0.3.13]: https://github.com/subquery/network-clients/compare/v0.3.11...v0.3.13 78 | [0.3.11]: https://github.com/subquery/network-clients/compare/v0.3.9...v0.3.11 79 | [0.3.9]: https://github.com/subquery/network-clients/compare/v0.3.7...v0.3.9 80 | [0.3.7]: https://github.com/subquery/network-clients/compare/v0.3.6...v0.3.7 81 | [0.3.6]: https://github.com/subquery/network-clients/compare/v0.3.4...v0.3.6 82 | [0.3.4]: https://github.com/subquery/network-clients/compare/v0.2.0...v0.3.4 83 | [0.2.0]: https://github.com/subquery/network-clients/compare/v0.1.0...v0.2.0 84 | [0.1.0]: https://github.com/subquery/network-clients/releases/tag/v0.1.0 85 | -------------------------------------------------------------------------------- /packages/network-clients/README.md: -------------------------------------------------------------------------------- 1 | # @subql/network-clients 2 | 3 | ## Clients 4 | 5 | ### Network Client 6 | 7 | The high level client for SubQuery Network 8 | 9 | Network Clients provide contract sdk, contract client and ipfs client methods to interact with Subquery Network. 10 | 11 | This high level client is for when we need to access multiple clients for a method. 12 | 13 | ``` TS 14 | import {NetworkClient, getIndexer} from '@subql/network-clients'; 15 | const client = NetworkClient.create(SQNetworks.TESTNET); 16 | 17 | //this method needs to access contract client and query client 18 | const indexer = await getIndexer('') 19 | ``` 20 | 21 | ### Contract Client 22 | 23 | Client where you can access several methods that use 24 | the contract sdk values as inputs. 25 | 26 | ``` TS 27 | import {cancelOfferUnspentBalance} from '@subql/network-clients'; 28 | const offerId = 4 29 | const balance = await cancelOfferUnspentBalance(offerId); 30 | ``` 31 | 32 | ### IPFS Client 33 | 34 | Client where you can call basic ipfs method without having to 35 | implement the logic yourself. 36 | 37 | ```TS 38 | import {cat} from '@subql/network-clients'; 39 | 40 | const output = await cat(''); 41 | console.log(output); 42 | ``` 43 | 44 | ### Query Client 45 | 46 | Client providing commonly used graphql requests that we use 47 | to get data from the network subquery project. 48 | 49 | ```TS 50 | import {GraphqlQueryClient, getIndexer} from '@subql/network-clients'; 51 | 52 | import {GetIndexer} from '@subql/network-query'; 53 | 54 | const client = new GraphqlQueryClient(config).networkClient; 55 | const result = await client.query({ 56 | query: GetIndexer, 57 | variables: { address: address1 }, 58 | }); 59 | ``` 60 | 61 | ## ChangeLogs 62 | 63 | [CHANGELOG.md](./CHANGELOG.md) 64 | -------------------------------------------------------------------------------- /packages/network-clients/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@subql/network-clients", 3 | "version": "1.1.1-3", 4 | "description": "SubQuery client sdk for network", 5 | "main": "dist/index.js", 6 | "author": "SubQuery Pte Limited", 7 | "license": "Apache-2.0", 8 | "scripts": { 9 | "build": "tsc -b" 10 | }, 11 | "dependencies": { 12 | "@ethersproject/bignumber": "^5.7.0", 13 | "@subql/network-config": "workspace:*", 14 | "@subql/network-query": "workspace:*", 15 | "axios": "^0.27.2", 16 | "buffer": "^6.0.3", 17 | "cross-fetch": "^3.1.5", 18 | "ethers": "^5.6.8", 19 | "graphql": "^16.5.0" 20 | }, 21 | "devDependencies": { 22 | "@apollo/client": "^3.8.0", 23 | "apollo": "^2.34.0", 24 | "create-ts-index": "^1.14.0", 25 | "typescript": "^4.6.4" 26 | }, 27 | "peerDependencies": { 28 | "@apollo/client": "*", 29 | "@subql/contract-sdk": "^1.0.3", 30 | "ipfs-http-client": "^53.0.1" 31 | }, 32 | "stableVersion": "1.1.1-2" 33 | } 34 | -------------------------------------------------------------------------------- /packages/network-clients/src/clients/contractClient.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { ContractSDK } from '@subql/contract-sdk/sdk'; 5 | import { BigNumber, utils } from 'ethers'; 6 | 7 | export class ContractClient { 8 | private readonly _sdk: ContractSDK; 9 | 10 | constructor(sdk: ContractSDK) { 11 | this._sdk = sdk; 12 | } 13 | 14 | public static create(sdk: ContractSDK) { 15 | return new ContractClient(sdk); 16 | } 17 | 18 | get perMill(): BigNumber { 19 | return BigNumber.from(1e6); 20 | } 21 | 22 | get perBill(): BigNumber { 23 | return BigNumber.from(1e9); 24 | } 25 | 26 | get perTrill(): BigNumber { 27 | return BigNumber.from(1e12); 28 | } 29 | 30 | public async latestRewardCollected(indexer: string): Promise { 31 | if (!utils.isAddress(indexer)) throw new Error(`Invalid address: ${indexer}`); 32 | 33 | const [currentEra, { lastClaimEra }, lastSettledEra] = await Promise.all([ 34 | this._sdk.eraManager.eraNumber(), 35 | this._sdk.rewardsDistributor.getRewardInfo(indexer), 36 | this._sdk.rewardsStaking.getLastSettledEra(indexer), 37 | ]); 38 | 39 | return currentEra.eq(lastClaimEra.add(1)) && lastSettledEra.lte(lastClaimEra); 40 | } 41 | 42 | public async cancelOfferUnspentBalance(offerId: number): Promise { 43 | const offer = await this._sdk.purchaseOfferMarket.offers(offerId); 44 | if (offer.deposit.eq(0)) throw new Error(`Invalid offerId: ${offerId}`); 45 | 46 | const unspentValue = offer.deposit.mul(offer.limit - offer.numAcceptedContracts); 47 | return unspentValue; 48 | } 49 | 50 | public async cancelOfferPenaltyFee(offerId: number): Promise { 51 | const offer = await this._sdk.purchaseOfferMarket.offers(offerId); 52 | if (offer.deposit.eq(0)) throw new Error(`Invalid offerId: ${offerId}`); 53 | 54 | const penaltyRate = await this._sdk.purchaseOfferMarket.penaltyRate(); 55 | const unspentValue = await this.cancelOfferUnspentBalance(offerId); 56 | const penaltyFee = penaltyRate.mul(unspentValue).div(this.perMill); 57 | 58 | return penaltyFee; 59 | } 60 | 61 | public async canStartNewUnbonding(account: string): Promise { 62 | const staking = this._sdk.staking; 63 | const [maxUnbondingRequest, unbondingLength, withdrawLength] = await Promise.all([ 64 | staking.maxUnbondingRequest(), 65 | staking.unbondingLength(account), 66 | staking.withdrawnLength(account), 67 | ]); 68 | 69 | return unbondingLength.sub(withdrawLength).lt(maxUnbondingRequest.sub(1)); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /packages/network-clients/src/clients/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | export * from './networkClient'; 5 | export * from './contractClient'; 6 | export * from './ipfsClient'; 7 | export * from './queryClient'; 8 | -------------------------------------------------------------------------------- /packages/network-clients/src/clients/ipfsClient.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import buffer from 'buffer'; 5 | import { IPFSHTTPClient, create } from 'ipfs-http-client'; 6 | import { concatU8A, isCID } from '../utils'; 7 | 8 | const Buffer = buffer.Buffer; 9 | 10 | export class IPFSClient { 11 | private _client: IPFSHTTPClient; 12 | 13 | constructor(url: string) { 14 | this._client = create({ url }); 15 | } 16 | 17 | public async getJSON(cid: string): Promise { 18 | const raw = await this.cat(cid); 19 | return JSON.parse(raw); 20 | } 21 | 22 | public async cat(cid: string, encoding: BufferEncoding = 'utf8'): Promise { 23 | const results = this._client.cat(cid); 24 | 25 | let raw: Uint8Array | undefined; 26 | for await (const result of results) { 27 | raw = raw ? concatU8A(raw, result) : result; 28 | } 29 | 30 | if (!raw) { 31 | throw new Error(`Unable to fetch data from ipfs: ${cid}`); 32 | } 33 | 34 | return Buffer.from(raw).toString(encoding); 35 | } 36 | 37 | public async add(entry: string): Promise { 38 | const result = await this._client.add(entry, { pin: true }); 39 | return result.cid.toV0().toString(); 40 | } 41 | 42 | public async image(url: string): Promise { 43 | const cid = url.replace('ipfs://', ''); 44 | if (!isCID(cid)) throw new Error(`Invalid cid: ${cid}`); 45 | 46 | const data = await this.cat(cid, 'base64'); 47 | return `data:image/png;base64,${data}`; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /packages/network-clients/src/clients/queryClient.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { 5 | ApolloClient, 6 | ApolloClientOptions, 7 | HttpLink, 8 | InMemoryCache, 9 | NormalizedCacheObject, 10 | } from '@apollo/client/core'; 11 | import fetch from 'cross-fetch'; 12 | import { 13 | GetDelegation, 14 | GetDelegationQuery, 15 | GetDelegationQueryVariables, 16 | GetIndexer, 17 | GetIndexerQuery, 18 | GetIndexerQueryVariables, 19 | GetTotalLock, 20 | GetTotalLockQuery, 21 | GetDelegator, 22 | GetDelegatorQuery, 23 | GetDelegatorQueryVariables, 24 | } from '@subql/network-query'; 25 | import { GQLEndpoint, NetworkConfig } from '@subql/network-config'; 26 | 27 | import { wrapApolloResult } from '../utils/apollo'; 28 | 29 | type ApolloClients = { [key: string]: ApolloClient }; 30 | 31 | export class GraphqlQueryClient { 32 | private apolloClients: ApolloClients = {}; 33 | 34 | get networkClient() { 35 | return this.apolloClients[GQLEndpoint.Network]; 36 | } 37 | 38 | constructor( 39 | private config: NetworkConfig, 40 | apolloClientOptionsOrClient?: 41 | | Partial> 42 | | ApolloClient 43 | ) { 44 | if (apolloClientOptionsOrClient instanceof ApolloClient) { 45 | this.apolloClients[GQLEndpoint.Network] = apolloClientOptionsOrClient; 46 | } else { 47 | this.apolloClients[GQLEndpoint.Network] = new ApolloClient({ 48 | cache: new InMemoryCache({ resultCaching: true }), 49 | link: new HttpLink({ uri: config.gql.network, fetch: fetch }), 50 | defaultOptions: { 51 | watchQuery: { 52 | fetchPolicy: 'no-cache', 53 | }, 54 | query: { 55 | fetchPolicy: 'no-cache', 56 | }, 57 | }, 58 | 59 | ...apolloClientOptionsOrClient, 60 | }); 61 | } 62 | } 63 | 64 | // QUERY REGISTRY QUERY FUNCTIONS 65 | 66 | async getIndexer(address: string): Promise { 67 | const result = await wrapApolloResult( 68 | this.networkClient.query({ 69 | query: GetIndexer, 70 | variables: { address }, 71 | }) 72 | ); 73 | 74 | return result?.indexer; 75 | } 76 | 77 | async getDelegation( 78 | indexer: string, 79 | delegator: string 80 | ): Promise { 81 | const result = await wrapApolloResult( 82 | this.networkClient.query({ 83 | query: GetDelegation, 84 | variables: { id: `${indexer}:${delegator}` }, 85 | }) 86 | ); 87 | return result?.delegation; 88 | } 89 | 90 | async getDelegator(delegator: string): Promise { 91 | const result = await wrapApolloResult( 92 | this.networkClient.query({ 93 | query: GetDelegator, 94 | variables: { address: delegator }, 95 | }) 96 | ); 97 | return result?.delegator; 98 | } 99 | 100 | async getTotalLock(): Promise { 101 | const result = await wrapApolloResult( 102 | this.networkClient.query({ 103 | query: GetTotalLock, 104 | }) 105 | ); 106 | return result?.totalLocks; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /packages/network-clients/src/globalTypes.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | -------------------------------------------------------------------------------- /packages/network-clients/src/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | export * from './clients'; 5 | export * from './models'; 6 | export * from './utils'; 7 | -------------------------------------------------------------------------------- /packages/network-clients/src/models/common.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { ethers } from 'ethers'; 5 | 6 | export class EraBasedValue { 7 | public era: number; 8 | public value: ethers.BigNumber; 9 | public valueAfter: ethers.BigNumber; 10 | private _delay: number; 11 | 12 | constructor(era: number, value: any, valueAfter: any, delay = 1) { 13 | this.era = era; 14 | this.value = ethers.BigNumber.from(value); 15 | this.valueAfter = ethers.BigNumber.from(valueAfter); 16 | this._delay = delay; 17 | } 18 | 19 | getValue(currentEra: number): ethers.BigNumber { 20 | return currentEra >= this.era + this._delay ? this.valueAfter : this.value; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/network-clients/src/models/eraValue.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { BigNumber } from 'ethers'; 5 | 6 | export type JSONBigInt = { 7 | type: 'bigint'; 8 | value: string; // Hex encoded string 9 | }; 10 | // Subql project type 11 | export type RawEraValue = EraValue; 12 | 13 | export interface EraValue { 14 | era: number; 15 | value: T; 16 | valueAfter: T; 17 | } 18 | 19 | export type CurrentEraValue = { current: T; after: T }; 20 | -------------------------------------------------------------------------------- /packages/network-clients/src/models/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | export * from './common'; 5 | export * from './eraValue'; 6 | export * from './indexer'; 7 | -------------------------------------------------------------------------------- /packages/network-clients/src/models/indexer.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { CurrentEraValue } from './eraValue'; 5 | 6 | export interface Indexer { 7 | metadata?: IndexerMetadata; 8 | address: string; 9 | controller: string | null; 10 | commission: CurrentEraValue; 11 | totalStake: CurrentEraValue; 12 | ownStake: CurrentEraValue; 13 | delegated: CurrentEraValue; 14 | capacity: CurrentEraValue; 15 | } 16 | 17 | export type IndexerMetadata = { 18 | name: string; 19 | image?: string; 20 | url: string; 21 | }; 22 | -------------------------------------------------------------------------------- /packages/network-clients/src/utils/apollo.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { ApolloQueryResult } from '@apollo/client/core'; 5 | 6 | export async function wrapApolloResult(_result: Promise>): Promise { 7 | const { error, data } = await _result; 8 | if (error) { 9 | throw error; 10 | } 11 | if (data) { 12 | return data; 13 | } 14 | 15 | throw new Error('unknown gql query error'); 16 | } 17 | -------------------------------------------------------------------------------- /packages/network-clients/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { BigNumber } from 'ethers'; 5 | import { sleep, waitForSomething } from './waitForSomething'; 6 | 7 | export * from './ipfs'; 8 | 9 | export function min(a: BigNumber, b: BigNumber): BigNumber { 10 | return a.lte(b) ? a : b; 11 | } 12 | 13 | export const indexingProgress = ({ 14 | currentHeight, 15 | targetHeight, 16 | startHeight = 0, 17 | }: { 18 | currentHeight: number; 19 | targetHeight: number; 20 | startHeight: number; 21 | }) => { 22 | if (targetHeight === startHeight) return 0; 23 | const rawProgress = (currentHeight - startHeight) / (targetHeight - startHeight); 24 | return isNaN(rawProgress) ? 0 : Math.min(Math.max(rawProgress, 0), 1); 25 | }; 26 | 27 | export const cachedResult: Map = new Map(); 28 | export enum CacheEnum { 29 | CACHED_PENDING = 'cached-pending', 30 | } 31 | export const fetchByCacheFirst = async >( 32 | asyncFunc: () => T, 33 | cacheName?: string, 34 | cacheTime = 3000 35 | ): Promise => { 36 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 37 | let error: any = null; 38 | if (cacheName) { 39 | if (cachedResult.has(cacheName)) { 40 | const curCachedResult = cachedResult.get(cacheName); 41 | if (curCachedResult === CacheEnum.CACHED_PENDING) { 42 | const getCache = await waitForSomething({ 43 | func: () => cachedResult.get(cacheName) !== CacheEnum.CACHED_PENDING, 44 | timeout: 5 * 10000, 45 | }); 46 | if (getCache) return cachedResult.get(cacheName); 47 | } else { 48 | return curCachedResult; 49 | } 50 | } 51 | 52 | cachedResult.set(cacheName, CacheEnum.CACHED_PENDING); 53 | } 54 | 55 | // try 3 times 56 | for (const _ of [0, 0, 0]) { 57 | try { 58 | const result = await asyncFunc(); 59 | if (cacheName) { 60 | cachedResult.set(cacheName, result); 61 | if (cacheTime) { 62 | setTimeout(() => { 63 | cachedResult.delete(cacheName); 64 | }, cacheTime); 65 | } 66 | } 67 | return result; 68 | } catch (e) { 69 | error = e; 70 | } 71 | 72 | await sleep(10000); 73 | } 74 | 75 | if (cacheName && cacheTime) { 76 | cachedResult.delete(cacheName); 77 | } 78 | throw new Error(error); 79 | }; 80 | -------------------------------------------------------------------------------- /packages/network-clients/src/utils/ipfs.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { utils } from 'ethers'; 5 | import buffer from 'buffer'; 6 | 7 | const Buffer = buffer.Buffer; 8 | 9 | export const CIDv0 = new RegExp(/Qm[1-9A-HJ-NP-Za-km-z]{44}/i); 10 | export const CIDv1 = new RegExp( 11 | /Qm[1-9A-HJ-NP-Za-km-z]{44,}|b[A-Za-z2-7]{58,}|B[A-Z2-7]{58,}|z[1-9A-HJ-NP-Za-km-z]{48,}|F[0-9A-F]{50,}/i 12 | ); 13 | 14 | export function isCID(cid: string): boolean { 15 | return CIDv0.test(cid) || CIDv1.test(cid); 16 | } 17 | 18 | export function cidToBytes32(cid: string): string { 19 | return `0x${Buffer.from(utils.base58.decode(cid)).slice(2).toString('hex')}`; 20 | } 21 | 22 | export function bytes32ToCid(bytes: string): string { 23 | // Add our default ipfs values for first 2 bytes: 24 | // function:0x12=sha2, size:0x20=256 bits 25 | // and cut off leading "0x" 26 | const hashHex = `1220${bytes.slice(2)}`; 27 | const hashBytes = Buffer.from(hashHex, 'hex'); 28 | return utils.base58.encode(hashBytes); 29 | } 30 | 31 | export function concatU8A(a: Uint8Array, b: Uint8Array): Uint8Array { 32 | const res = new Uint8Array(a.length + b.length); 33 | res.set(a, 0); 34 | res.set(b, a.length); 35 | return res; 36 | } 37 | -------------------------------------------------------------------------------- /packages/network-clients/src/utils/parseEraValue.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import assert from 'assert'; 5 | import { BigNumber, BigNumberish } from 'ethers'; 6 | import { isBigNumberish } from '@ethersproject/bignumber/lib/bignumber'; 7 | import { CurrentEraValue, EraValue, JSONBigInt, RawEraValue } from '../models/eraValue'; 8 | 9 | function jsonBigIntToBigInt(value: JSONBigInt | BigNumberish): BigNumber { 10 | if (isBigNumberish(value)) { 11 | return BigNumber.from(value); 12 | } 13 | assert(value.type === 'bigint', 'Value is not a JSONBigInt'); 14 | 15 | return BigNumber.from(value.value); 16 | } 17 | 18 | export function convertRawEraValue(raw: RawEraValue | EraValue): EraValue { 19 | return { 20 | ...raw, 21 | value: jsonBigIntToBigInt(raw.value), 22 | valueAfter: jsonBigIntToBigInt(raw.valueAfter), 23 | }; 24 | } 25 | 26 | export function isEraValue(eraValue: RawEraValue) { 27 | const { era, value, valueAfter } = eraValue ?? {}; 28 | 29 | return !!(era && value && valueAfter); 30 | } 31 | 32 | export function parseRawEraValue(value: RawEraValue, curEra: number): CurrentEraValue { 33 | assert(isEraValue(value), `Value is not of type EraValue: ${JSON.stringify(value)}`); 34 | const eraValue = convertRawEraValue(value); 35 | 36 | if (curEra && curEra > eraValue.era) { 37 | return { current: eraValue.valueAfter, after: eraValue.valueAfter }; 38 | } 39 | 40 | const sortedValueAfter = eraValue.value.eq(eraValue.valueAfter) 41 | ? eraValue.value 42 | : eraValue.valueAfter; 43 | 44 | return { current: eraValue.value, after: sortedValueAfter }; 45 | } 46 | -------------------------------------------------------------------------------- /packages/network-clients/src/utils/waitForSomething.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | export const sleep = (time = 2000) => new Promise((resolve) => setTimeout(resolve, time)); 5 | 6 | interface waitForSomethingArg { 7 | func: () => boolean | PromiseLike; 8 | timeout?: number; 9 | splitTime?: number; 10 | } 11 | 12 | export const waitForSomething = async ( 13 | { func, timeout, splitTime = 50 }: waitForSomethingArg, 14 | sleepTime = 0 15 | ): Promise => { 16 | if (timeout && sleepTime >= timeout) { 17 | return false; 18 | } 19 | try { 20 | const r = await func(); 21 | 22 | if (r) { 23 | return r; 24 | } 25 | } catch (e) { 26 | console.error(e); 27 | } 28 | 29 | await sleep(splitTime); 30 | 31 | return waitForSomething({ func, timeout }, splitTime + sleepTime); 32 | }; 33 | -------------------------------------------------------------------------------- /packages/network-clients/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "target": "es2017", 5 | "sourceMap": true, 6 | "resolveJsonModule": true, 7 | "rootDir": "./src", 8 | "outDir": "./dist" 9 | }, 10 | "include": ["src/**/*", "test/**/*", "../network-config/constants.ts", "../network-config/config.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /packages/network-config/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [Unreleased] 9 | 10 | ## [1.1.1] - 2024-02-21 11 | 12 | - Change Leaderboard api address. 13 | 14 | ## [1.1.0] - 2024-02-21 15 | 16 | - Mainnet version 17 | 18 | ## [1.0.0] - 2024-02-21 19 | 20 | ## [0.114.0] - 2024-01-23 21 | 22 | ## [0.112.0] - 2023-12-19 23 | 24 | ## [0.111.0] - 2023-12-15 25 | 26 | ## [0.100.2] - 2023-11-24 27 | 28 | ## [0.100.0] - 2023-11-01 29 | 30 | ## [0.3.16] - 2023-09-28 31 | 32 | Upgrade @subql/contracts 33 | 34 | ## [0.3.14] - 2023-08-18 35 | 36 | ## [0.3.13] - 2023-07-04 37 | 38 | ## [0.3.11] - 2023-07-04 39 | 40 | ## [0.3.9] - 2023-06-29 41 | 42 | ## [0.3.8] - 2023-06-29 43 | 44 | ## [0.3.7] - 2023-06-21 45 | 46 | ## [0.3.6] - 2023-06-21 47 | 48 | Add `LEADERBOARD_SUBQL_ENDPOINTS` 49 | 50 | ## [0.3.5] - 2023-06-15 51 | 52 | ### Changed 53 | 54 | - Upgrade Contract SDK to `v0.13.4` (#131) 55 | 56 | ### Added 57 | 58 | - Release first version 59 | 60 | [unreleased]: https://github.com/subquery/network-clients/compare/v1.1.1...HEAD 61 | [1.1.1]: https://github.com/subquery/network-clients/compare/v1.1.0...v1.1.1 62 | [1.1.0]: https://github.com/subquery/network-clients/compare/v1.0.0...v1.1.0 63 | [1.0.0]: https://github.com/subquery/network-clients/compare/v0.114.0...v1.0.0 64 | [0.114.0]: https://github.com/subquery/network-clients/compare/v0.112.0...v0.114.0 65 | [0.112.0]: https://github.com/subquery/network-clients/compare/v0.111.0...v0.112.0 66 | [0.111.0]: https://github.com/subquery/network-clients/compare/v0.100.2...v0.111.0 67 | [0.100.2]: https://github.com/subquery/network-clients/compare/v0.100.0...v0.100.2 68 | [0.100.0]: https://github.com/subquery/network-clients/compare/v0.3.16...v0.100.0 69 | [0.3.16]: https://github.com/subquery/network-clients/compare/v0.3.14...v0.3.16 70 | [0.3.14]: https://github.com/subquery/network-clients/compare/v0.3.13...v0.3.14 71 | [0.3.13]: https://github.com/subquery/network-clients/compare/v0.3.11...v0.3.13 72 | [0.3.11]: https://github.com/subquery/network-clients/compare/v0.3.9...v0.3.11 73 | [0.3.9]: https://github.com/subquery/network-clients/compare/v0.3.7...v0.3.9 74 | [0.3.7]: https://github.com/subquery/network-clients/compare/v0.3.5...v0.3.7 75 | [0.3.4]: https://github.com/subquery/network-clients/compare/v0.2.0...v0.3.5 76 | -------------------------------------------------------------------------------- /packages/network-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@subql/network-config", 3 | "version": "1.1.2-0", 4 | "main": "dist/index.js", 5 | "description": "SubQuery package containing network configuration", 6 | "author": "SubQuery Pte Limited", 7 | "license": "Apache-2.0", 8 | "scripts": { 9 | "build": "tsc -b" 10 | }, 11 | "devDependencies": { 12 | "typescript": "^4.8.4" 13 | }, 14 | "peerDependencies": { 15 | "@subql/contract-sdk": "^1.0.3", 16 | "ipfs-http-client": "^53.0.1" 17 | }, 18 | "stableVersion": "1.1.1" 19 | } 20 | -------------------------------------------------------------------------------- /packages/network-config/src/config.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { GQLEndpoint, IPFS_URLS, RPC_ENDPOINTS, SQNetworks, gqlEndpoints } from './constants'; 5 | 6 | import { SdkOptions } from '@subql/contract-sdk/types'; 7 | 8 | import mainnetDeploymentDetails from '@subql/contract-sdk/publish/mainnet.json'; 9 | import testnetDeploymentDetails from '@subql/contract-sdk/publish/testnet.json'; 10 | 11 | export interface NetworkConfig { 12 | gql: Record; 13 | defaultEndpoint: string | undefined; 14 | sdkOptions: SdkOptions; 15 | } 16 | 17 | export const NETWORK_CONFIGS: Record = { 18 | [SQNetworks.MAINNET]: { 19 | defaultEndpoint: RPC_ENDPOINTS.mainnet, 20 | sdkOptions: { network: 'mainnet', deploymentDetails: mainnetDeploymentDetails.child }, 21 | gql: gqlEndpoints(SQNetworks.MAINNET), 22 | }, 23 | [SQNetworks.TESTNET]: { 24 | defaultEndpoint: RPC_ENDPOINTS.testnet, 25 | sdkOptions: { network: 'testnet', deploymentDetails: testnetDeploymentDetails.child }, 26 | gql: gqlEndpoints(SQNetworks.TESTNET), 27 | }, 28 | [SQNetworks.LOCAL]: { 29 | defaultEndpoint: RPC_ENDPOINTS.testnet, 30 | sdkOptions: { network: 'testnet', deploymentDetails: testnetDeploymentDetails.child }, 31 | gql: gqlEndpoints(SQNetworks.TESTNET), 32 | }, 33 | }; 34 | 35 | export const DEFAULT_IPFS_URL = IPFS_URLS.metadata; 36 | -------------------------------------------------------------------------------- /packages/network-config/src/constants.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | export enum SQNetworks { 5 | TESTNET = 'testnet', 6 | MAINNET = 'mainnet', 7 | LOCAL = 'local', 8 | } 9 | 10 | export enum GQLEndpoint { 11 | Network = 'network', 12 | Leaderboard = 'leaderboard', 13 | } 14 | 15 | export const IPFS_URLS = { 16 | project: 'https://ipfs.subquery.network/ipfs/api/v0', 17 | metadata: 'https://unauthipfs.subquery.network/ipfs/api/v0', 18 | }; 19 | 20 | export const RPC_ENDPOINTS = { 21 | [SQNetworks.MAINNET]: 'https://mainnet.base.org/', 22 | [SQNetworks.TESTNET]: 'https://sepolia.base.org', 23 | [SQNetworks.LOCAL]: 'https://sepolia.base.org', 24 | }; 25 | 26 | export const NETWORK_SUBQL_ENDPOINTS = { 27 | [SQNetworks.MAINNET]: 'https://api.subquery.network/sq/subquery/subquery-mainnet', 28 | [SQNetworks.LOCAL]: 'https://api.subquery.network/sq/subquery/subquery-mainnet', 29 | [SQNetworks.TESTNET]: 'https://api.subquery.network/sq/subquery/base-testnet', 30 | }; 31 | 32 | export const LEADERBOARD_SUBQL_ENDPOINTS = { 33 | [SQNetworks.MAINNET]: 'https://lb-api.subquery.network/graphql', 34 | [SQNetworks.LOCAL]: 'https://lb-api.subquery.network/graphql', 35 | [SQNetworks.TESTNET]: 'https://leaderboard-api.thechaindata.com/graphql', 36 | }; 37 | 38 | export const STABLE_COIN_ADDRESSES = { 39 | [SQNetworks.MAINNET]: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', 40 | [SQNetworks.TESTNET]: '0x3148eb6A6689a5a8A64B50ea8f845231d4617f9B', 41 | [SQNetworks.LOCAL]: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', 42 | } as const; 43 | 44 | export const STABLE_COIN_SYMBOLS = { 45 | [SQNetworks.MAINNET]: 'USDC', 46 | [SQNetworks.TESTNET]: 'USDC', 47 | [SQNetworks.LOCAL]: 'USDC', 48 | } as const; 49 | 50 | export const TOKEN_SYMBOLS = { 51 | [SQNetworks.MAINNET]: 'SQT', 52 | [SQNetworks.TESTNET]: 'SQT', 53 | [SQNetworks.LOCAL]: 'SQT', 54 | } as const; 55 | 56 | export const STABLE_COIN_DECIMAL = 6; 57 | export const SQT_DECIMAL = 18; 58 | 59 | export function gqlEndpoints(network: SQNetworks) { 60 | return { 61 | [GQLEndpoint.Network]: NETWORK_SUBQL_ENDPOINTS[network], 62 | [GQLEndpoint.Leaderboard]: LEADERBOARD_SUBQL_ENDPOINTS[network], 63 | }; 64 | } 65 | 66 | export const NETWORKS_CONFIG_INFO = { 67 | [SQNetworks.TESTNET]: { 68 | chainId: '0x14a34', 69 | chainName: 'Base Sepolia Testnet', 70 | rpcUrls: ['https://sepolia.base.org'], 71 | iconUrls: ['https://base.org/document/apple-touch-icon.png'], 72 | blockExplorerUrls: ['https://sepolia.basescan.org/'], 73 | nativeCurrency: { 74 | name: 'Ether', 75 | symbol: 'ETH', 76 | decimals: 18, 77 | }, 78 | }, 79 | [SQNetworks.MAINNET]: { 80 | chainId: '0x2105', 81 | chainName: 'Base', 82 | rpcUrls: ['https://mainnet.base.org'], 83 | iconUrls: ['https://base.org/document/apple-touch-icon.png'], 84 | blockExplorerUrls: ['https://basescan.org/'], 85 | nativeCurrency: { 86 | name: 'Ether', 87 | symbol: 'ETH', 88 | decimals: 18, 89 | }, 90 | }, 91 | [SQNetworks.LOCAL]: { 92 | chainId: '0x14a34', 93 | chainName: 'Base Sepolia Testnet', 94 | rpcUrls: ['https://sepolia.base.org'], 95 | iconUrls: ['https://base.org/document/apple-touch-icon.png'], 96 | blockExplorerUrls: ['https://sepolia.basescan.org/'], 97 | nativeCurrency: { 98 | name: 'Ether', 99 | symbol: 'ETH', 100 | decimals: 18, 101 | }, 102 | }, 103 | }; 104 | -------------------------------------------------------------------------------- /packages/network-config/src/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | export * from './constants'; 5 | export * from './config'; 6 | -------------------------------------------------------------------------------- /packages/network-config/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "target": "es2017", 5 | "sourceMap": true, 6 | "resolveJsonModule": true, 7 | "rootDir": "./src", 8 | "outDir": "./dist" 9 | }, 10 | "include": ["src/**/*", "test/**/*"] 11 | } 12 | -------------------------------------------------------------------------------- /packages/network-query/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [Unreleased] 9 | 10 | ## [1.1.1] - 2024-02-27 11 | 12 | ## [1.1.0] - 2024-02-21 13 | 14 | ## [1.0.0] - 2024-02-21 15 | 16 | ## [0.112.0] - 2023-12-19 17 | 18 | ## [0.111.0] - 2023-12-15 19 | 20 | ## [0.100.2] - 2023-11-24 21 | 22 | ## [0.100.0] - 2023-11-01 23 | 24 | ## [0.3.15] - 2023-07-21 25 | 26 | ## [0.3.11] - 2023-07-04 27 | 28 | ## [0.3.9] - 2023-06-29 29 | 30 | ## [0.3.8] - 2023-06-29 31 | 32 | ## [0.3.7] - 2023-06-21 33 | 34 | ## [0.3.6] - 2023-06-21 35 | 36 | Add `leaderboard`. 37 | 38 | ## [0.3.4] - 2023-06-15 39 | 40 | ### Changed 41 | 42 | - Upgrade Contract SDK to `v0.13.4` (#131) 43 | 44 | ### Added 45 | 46 | - Release first version 47 | 48 | [unreleased]: https://github.com/subquery/network-clients/compare/v1.1.1...HEAD 49 | [1.1.1]: https://github.com/subquery/network-clients/compare/v1.1.0...v1.1.1 50 | [1.1.0]: https://github.com/subquery/network-clients/compare/v1.0.0...v1.1.0 51 | [1.0.0]: https://github.com/subquery/network-clients/compare/v0.112.0...v1.0.0 52 | [0.112.0]: https://github.com/subquery/network-clients/compare/v0.111.0...v0.112.0 53 | [0.111.0]: https://github.com/subquery/network-clients/compare/v0.100.2...v0.111.0 54 | [0.100.2]: https://github.com/subquery/network-clients/compare/v0.100.0...v0.100.2 55 | [0.100.0]: https://github.com/subquery/network-clients/compare/v0.3.13...v0.100.0 56 | [0.3.13]: https://github.com/subquery/network-clients/compare/v0.3.11...v0.3.13 57 | [0.3.11]: https://github.com/subquery/network-clients/compare/v0.3.9...v0.3.11 58 | [0.3.9]: https://github.com/subquery/network-clients/compare/v0.3.7...v0.3.9 59 | [0.3.7]: https://github.com/subquery/network-clients/compare/v0.3.4...v0.3.7 60 | [0.3.4]: https://github.com/subquery/network-clients/compare/v0.2.0...v0.3.4 61 | -------------------------------------------------------------------------------- /packages/network-query/README.md: -------------------------------------------------------------------------------- 1 | # @subql/network-query 2 | 3 | # Description 4 | 5 | The package contains all the graphql queries for our dapps. This package will then generate the typescript types and queries using [codegen](https://the-guild.dev/graphql/codegen). 6 | 7 | The queries are split into folders which map to subquery project endpoints that are used to perform codegen. 8 | 9 | The react-hooks package will use the queries and types from this package to generate react-hooks. 10 | 11 | # Usage 12 | 13 | To use queries and types from this package: 14 | 15 | ```TS 16 | import { GetIndexer, GetIndexerQuery, GetIndexerQueryVariables} from '@subql/network-query' 17 | 18 | //example of querying using apollo client 19 | apolloClient.query({ 20 | query: GetIndexer, 21 | variables: { address }, 22 | }) 23 | ``` 24 | 25 | To add graphql queries: 26 | 27 | - Add the query to correct file in `/queries` directory. 28 | 29 | - Run `yarn codegen-gql` to ensure the query is correct. This will output code into `src/__graphql__` 30 | 31 | - Create pull request 32 | 33 | - 34 | 35 | # ChangeLogs 36 | 37 | [CHANGELOG.md](./CHANGELOG.md) 38 | -------------------------------------------------------------------------------- /packages/network-query/leaderboard.codegen.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { CodegenConfig } from '@graphql-codegen/cli'; 5 | import { NETWORK_CONFIGS } from '@subql/network-config'; 6 | 7 | const config: CodegenConfig = { 8 | schema: NETWORK_CONFIGS.mainnet.gql.leaderboard, 9 | documents: './queries/leaderboard/*.gql', 10 | config: { 11 | preResolveTypes: true, 12 | namingConvention: 'keep', 13 | avoidOptionals: true, 14 | nonOptionalTypename: true, 15 | skipTypeNameForRoot: true, 16 | immutableTypes: true, 17 | scalars: { 18 | Date: 'Date', 19 | Datetime: 'Date', 20 | BigFloat: 'bigint' || 'string', 21 | BigInt: 'bigint', 22 | Cursor: 'string', 23 | }, 24 | }, 25 | generates: { 26 | 'src/': { 27 | preset: 'near-operation-file', 28 | presetConfig: { 29 | folder: '../../src/__graphql__/leaderboard', 30 | extensions: '.generated.ts', 31 | baseTypesPath: '__graphql__/base-types.ts', 32 | }, 33 | config: { 34 | importOperationTypesFrom: 'Types', 35 | }, 36 | plugins: ['typescript-document-nodes'], 37 | }, 38 | }, 39 | }; 40 | 41 | export default config; 42 | -------------------------------------------------------------------------------- /packages/network-query/network.codegen.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { CodegenConfig } from '@graphql-codegen/cli'; 5 | import { NETWORK_CONFIGS } from '@subql/network-config'; 6 | 7 | const config: CodegenConfig = { 8 | schema: NETWORK_CONFIGS.mainnet.gql.network, 9 | documents: './queries/network/*.gql', 10 | config: { 11 | preResolveTypes: true, 12 | namingConvention: 'keep', 13 | avoidOptionals: true, 14 | nonOptionalTypename: true, 15 | skipTypeNameForRoot: true, 16 | immutableTypes: true, 17 | scalars: { 18 | Date: 'Date', 19 | Datetime: 'Date', 20 | BigFloat: 'bigint' || 'string', 21 | BigInt: 'bigint', 22 | Cursor: 'string', 23 | }, 24 | }, 25 | generates: { 26 | 'src/': { 27 | preset: 'near-operation-file', 28 | presetConfig: { 29 | folder: '../../src/__graphql__/network', 30 | extensions: '.generated.ts', 31 | baseTypesPath: '__graphql__/base-types.ts', 32 | }, 33 | config: { 34 | importOperationTypesFrom: 'Types', 35 | }, 36 | plugins: ['typescript-document-nodes'], 37 | }, 38 | }, 39 | }; 40 | 41 | export default config; 42 | -------------------------------------------------------------------------------- /packages/network-query/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@subql/network-query", 3 | "version": "1.1.2-9", 4 | "main": "dist/index.js", 5 | "description": "SubQuery package containing all gql queries for network dapps", 6 | "author": "SubQuery Pte Limited", 7 | "license": "Apache-2.0", 8 | "scripts": { 9 | "codegen-gql": "sh ./scripts/codegen.sh", 10 | "build": "yarn codegen-gql && yarn tsc -b" 11 | }, 12 | "dependencies": { 13 | "graphql": "^16.5.0" 14 | }, 15 | "devDependencies": { 16 | "@graphql-codegen/cli": "^2.13.1", 17 | "@graphql-codegen/introspection": "^2.2.1", 18 | "@graphql-codegen/near-operation-file-preset": "^2.4.1", 19 | "@graphql-codegen/typescript": "^2.7.3", 20 | "@graphql-codegen/typescript-document-nodes": "^2.3.3", 21 | "@graphql-codegen/typescript-operations": "^2.5.3", 22 | "@subql/network-config": "workspace:*", 23 | "ctix": "^1.5.4", 24 | "prettier": "^2.7.1", 25 | "typescript": "^4.8.4" 26 | }, 27 | "stableVersion": "1.1.2-8" 28 | } 29 | -------------------------------------------------------------------------------- /packages/network-query/queries/leaderboard/topIndexer.gql: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | fragment indexerProgramsFields on IndexerProgram { 5 | id 6 | delegated 7 | ownStaked 8 | rewardCollection 9 | socialCredibility 10 | sslEnabled 11 | uptime 12 | totalPoints 13 | currICR 14 | nextICR 15 | rank 16 | } 17 | 18 | query GetTopIndexers { 19 | indexerPrograms { 20 | ...indexerProgramsFields 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/network-query/queries/network/agreements.gql: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | fragment ServiceAgreementFields on ServiceAgreement { 5 | id 6 | deploymentId 7 | indexerAddress 8 | consumerAddress 9 | period 10 | lockedAmount 11 | startTime 12 | endTime 13 | deployment { 14 | id 15 | metadata 16 | project { 17 | id 18 | type 19 | metadata 20 | } 21 | } 22 | planTemplate { 23 | priceToken 24 | } 25 | } 26 | 27 | query GetIndexerServiceAgreementsCount($address: String!) { 28 | serviceAgreements(filter: { indexerAddress: { equalTo: $address } }) { 29 | totalCount 30 | } 31 | } 32 | 33 | query GetConsumerServiceAgreementsCount($address: String!) { 34 | serviceAgreements(filter: { consumerAddress: { equalTo: $address } }) { 35 | totalCount 36 | } 37 | } 38 | 39 | # Ongoing Service Agreement Queries 40 | 41 | query GetOngoingServiceAgreements($address: String!, $now: Datetime!) { 42 | serviceAgreements( 43 | filter: { 44 | or: [{ indexerAddress: { equalTo: $address } }, { consumerAddress: { equalTo: $address } }] 45 | endTime: { greaterThanOrEqualTo: $now } 46 | } 47 | orderBy: END_TIME_ASC 48 | ) { 49 | totalCount 50 | nodes { 51 | ...ServiceAgreementFields 52 | } 53 | } 54 | } 55 | 56 | query GetIndexerOngoingServiceAgreements($address: String!, $now: Datetime!) { 57 | serviceAgreements( 58 | filter: { indexerAddress: { equalTo: $address }, endTime: { greaterThanOrEqualTo: $now } } 59 | orderBy: END_TIME_ASC 60 | ) { 61 | totalCount 62 | nodes { 63 | ...ServiceAgreementFields 64 | } 65 | } 66 | } 67 | 68 | query GetConsumerOngoingServiceAgreements($address: String!, $now: Datetime!) { 69 | serviceAgreements( 70 | filter: { consumerAddress: { equalTo: $address }, endTime: { greaterThanOrEqualTo: $now } } 71 | orderBy: END_TIME_ASC 72 | ) { 73 | totalCount 74 | nodes { 75 | ...ServiceAgreementFields 76 | } 77 | } 78 | } 79 | 80 | # Expired Service Agreement Queries 81 | 82 | query GetExpiredServiceAgreements($address: String!, $now: Datetime!) { 83 | serviceAgreements( 84 | filter: { 85 | or: [{ indexerAddress: { equalTo: $address } }, { consumerAddress: { equalTo: $address } }] 86 | endTime: { lessThan: $now } 87 | } 88 | orderBy: END_TIME_ASC 89 | ) { 90 | totalCount 91 | nodes { 92 | ...ServiceAgreementFields 93 | } 94 | } 95 | } 96 | 97 | query GetIndexerExpiredServiceAgreements($address: String!, $now: Datetime!) { 98 | serviceAgreements( 99 | filter: { indexerAddress: { equalTo: $address }, endTime: { lessThan: $now } } 100 | orderBy: END_TIME_ASC 101 | ) { 102 | totalCount 103 | nodes { 104 | ...ServiceAgreementFields 105 | } 106 | } 107 | } 108 | 109 | query GetConsumerExpiredServiceAgreements($address: String!, $now: Datetime!) { 110 | serviceAgreements( 111 | filter: { consumerAddress: { equalTo: $address }, endTime: { lessThan: $now } } 112 | orderBy: END_TIME_ASC 113 | ) { 114 | totalCount 115 | nodes { 116 | ...ServiceAgreementFields 117 | } 118 | } 119 | } 120 | 121 | # Project Service Agreement Queries 122 | 123 | query GetProjectOngoingServiceAgreements($deploymentId: String!, $now: Datetime!) { 124 | serviceAgreements( 125 | filter: { deploymentId: { equalTo: $deploymentId }, endTime: { greaterThanOrEqualTo: $now } } 126 | orderBy: END_TIME_ASC 127 | ) { 128 | totalCount 129 | nodes { 130 | ...ServiceAgreementFields 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /packages/network-query/queries/network/dashboard.gql: -------------------------------------------------------------------------------- 1 | query GetDashboard { 2 | eraRewards { 3 | aggregates { 4 | sum { 5 | amount 6 | } 7 | } 8 | } 9 | 10 | indexerRewards { 11 | aggregates { 12 | sum { 13 | amount 14 | } 15 | } 16 | } 17 | 18 | rewardsToIndexer: eraRewards(filter: { isIndexer: { equalTo: true } }) { 19 | totalCount 20 | aggregates { 21 | sum { 22 | amount 23 | } 24 | } 25 | } 26 | 27 | rewardsToDelegation: eraRewards(filter: { isIndexer: { equalTo: false } }) { 28 | totalCount 29 | aggregates { 30 | sum { 31 | amount 32 | } 33 | } 34 | } 35 | 36 | indexerStakeSummary(id: "0x00") { 37 | indexerStake 38 | nextDelegatorStake 39 | nextIndexerStake 40 | nextTotalStake 41 | totalStake 42 | delegatorStake 43 | eraIdx 44 | eraId 45 | } 46 | 47 | sqtokens { 48 | aggregates { 49 | sum { 50 | circulatingSupply 51 | totalSupply 52 | } 53 | } 54 | } 55 | 56 | indexers(filter: { active: { equalTo: true } }) { 57 | totalCount 58 | } 59 | 60 | delegations { 61 | aggregates { 62 | distinctCount { 63 | delegatorId 64 | } 65 | } 66 | } 67 | } 68 | 69 | query GetDashboardApy($currentEra: Int! = 0, $currentEraIdx: String! = "0x00") { 70 | eraRewards(filter: { eraIdx: { lessThan: $currentEra } }) { 71 | groupedAggregates(groupBy: ERA_IDX) { 72 | sum { 73 | amount 74 | } 75 | keys 76 | } 77 | } 78 | 79 | indexerEraReward: eraRewards( 80 | filter: { eraIdx: { lessThan: $currentEra }, isIndexer: { equalTo: true } } 81 | ) { 82 | groupedAggregates(groupBy: ERA_IDX) { 83 | sum { 84 | amount 85 | } 86 | keys 87 | } 88 | } 89 | 90 | delegationEraReward: eraRewards( 91 | filter: { eraIdx: { lessThan: $currentEra }, isIndexer: { equalTo: false } } 92 | ) { 93 | groupedAggregates(groupBy: ERA_IDX) { 94 | sum { 95 | amount 96 | } 97 | keys 98 | } 99 | } 100 | indexerStakes(filter: { id: { equalTo: $currentEraIdx } }) { 101 | groupedAggregates(groupBy: ERA_IDX) { 102 | keys 103 | sum { 104 | delegatorStake 105 | indexerStake 106 | totalStake 107 | } 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /packages/network-query/queries/network/delegations.gql: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | fragment DelegationFields on Delegation { 5 | id 6 | delegatorId 7 | indexerId 8 | amount 9 | } 10 | 11 | query GetIndexerDelegators($id: String!, $offset: Int, $eraId: Int = 0, $first: Int = 10) { 12 | indexer(id: $id) { 13 | delegations( 14 | offset: $offset 15 | first: $first 16 | filter: { 17 | delegatorId: { notEqualTo: $id } 18 | or: [{ exitEra: { isNull: true } }, { exitEra: { equalTo: $eraId } }] 19 | } 20 | orderBy: AMOUNT_DESC 21 | ) { 22 | totalCount 23 | nodes { 24 | ...DelegationFields 25 | } 26 | } 27 | } 28 | } 29 | 30 | query GetDelegation($id: String!) { 31 | delegation(id: $id) { 32 | amount 33 | } 34 | } 35 | 36 | query GetAllDelegations($offset: Int) { 37 | delegations(offset: $offset) { 38 | totalCount 39 | nodes { 40 | ...DelegationFields 41 | } 42 | } 43 | } 44 | 45 | query GetDelegator($address: String!) { 46 | delegator(id: $address) { 47 | id 48 | totalDelegations 49 | } 50 | } 51 | 52 | query GetDelegations($delegator: String!, $offset: Int) { 53 | delegations(filter: { delegatorId: { equalTo: $delegator } }, offset: $offset) { 54 | totalCount 55 | nodes { 56 | ...DelegationFields 57 | indexer { 58 | active 59 | metadata 60 | } 61 | } 62 | } 63 | } 64 | 65 | query GetFilteredDelegations($delegator: String!, $filterIndexer: String!, $offset: Int) { 66 | delegations( 67 | filter: { delegatorId: { equalTo: $delegator }, indexerId: { notEqualTo: $filterIndexer } } 68 | offset: $offset 69 | ) { 70 | totalCount 71 | nodes { 72 | ...DelegationFields 73 | indexer { 74 | metadata 75 | active 76 | commission 77 | capacity 78 | selfStake 79 | totalStake 80 | } 81 | } 82 | } 83 | } 84 | 85 | query GetFilteredDelegation($delegator: String!, $indexer: String!, $offset: Int) { 86 | delegations( 87 | filter: { delegatorId: { equalTo: $delegator }, indexerId: { equalTo: $indexer } } 88 | offset: $offset 89 | ) { 90 | totalCount 91 | nodes { 92 | ...DelegationFields 93 | indexer { 94 | metadata 95 | active 96 | } 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /packages/network-query/queries/network/delegatorApr.gql: -------------------------------------------------------------------------------- 1 | query GetSpecifyDelegatorsIndexerApy($delegator: String!, $indexers: [String!] = [], $era: Int!) { 2 | eraDelegatorIndexerApies( 3 | filter: { 4 | delegatorId: { equalTo: $delegator } 5 | indexerId: { in: $indexers, notEqualTo: $delegator } 6 | eraIdx: { equalTo: $era } 7 | } 8 | ) { 9 | nodes { 10 | apy 11 | eraIdx 12 | indexerId 13 | } 14 | } 15 | } 16 | 17 | query GetDelegatorApies($delegator: String!, $era: Int!) { 18 | eraDelegatorApies(filter: { delegatorId: { equalTo: $delegator }, eraIdx: { equalTo: $era } }) { 19 | nodes { 20 | apy 21 | eraIdx 22 | delegatorId 23 | } 24 | } 25 | } 26 | 27 | query GetDelegatorTotalAndLastEraDistictiveRewardsByIndexer( 28 | $delegator: String! 29 | $indexers: [String!] = [] 30 | $era: Int! 31 | ) { 32 | totalRewards: eraDelegatorIndexerApies( 33 | filter: { 34 | delegatorId: { equalTo: $delegator } 35 | indexerId: { in: $indexers, notEqualTo: $delegator } 36 | } 37 | ) { 38 | groupedAggregates(groupBy: INDEXER_ID) { 39 | keys 40 | sum { 41 | reward 42 | } 43 | } 44 | } 45 | 46 | lastEraCollectRewards: eraDelegatorIndexerApies( 47 | filter: { 48 | delegatorId: { equalTo: $delegator } 49 | indexerId: { in: $indexers, notEqualTo: $delegator } 50 | eraIdx: { equalTo: $era } 51 | } 52 | ) { 53 | groupedAggregates(groupBy: INDEXER_ID) { 54 | keys 55 | sum { 56 | reward 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /packages/network-query/queries/network/deploymentBooster.gql: -------------------------------------------------------------------------------- 1 | query GetDeploymentBoosterTotalAmountByDeploymentId($deploymentId: String!, $consumer: String!) { 2 | deploymentBoosterSummaries(filter: { deploymentId: { equalTo: $deploymentId } }) { 3 | aggregates { 4 | sum { 5 | totalAmount 6 | } 7 | } 8 | } 9 | 10 | deploymentBoosterSummariesByConsumer: deploymentBoosterSummaries( 11 | filter: { deploymentId: { equalTo: $deploymentId }, consumer: { equalTo: $consumer } } 12 | ) { 13 | aggregates { 14 | sum { 15 | totalAmount 16 | } 17 | } 18 | } 19 | } 20 | 21 | query GetDeploymentBoosterProjectsAndTotalByConsumer( 22 | $offset: Int = 0 23 | $first: Int = 10 24 | $consumer: String! 25 | ) { 26 | deploymentBoosterSummaries( 27 | filter: { consumer: { equalTo: $consumer } } 28 | offset: $offset 29 | first: $first 30 | orderBy: ID_DESC 31 | ) { 32 | nodes { 33 | consumer 34 | deploymentId 35 | totalAmount 36 | projectId 37 | project { 38 | metadata 39 | } 40 | } 41 | totalCount 42 | } 43 | 44 | totalBoostedAmount: deploymentBoosterSummaries(filter: { consumer: { equalTo: $consumer } }) { 45 | aggregates { 46 | sum { 47 | totalAmount 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /packages/network-query/queries/network/deployments.gql: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | fragment IndexerDeploymentFields on IndexerDeployment { 5 | id 6 | indexerId 7 | deploymentId 8 | timestamp 9 | status 10 | indexer { 11 | metadata 12 | } 13 | } 14 | 15 | fragment IndexerDeploymentNodeFields on IndexerDeployment { 16 | ...IndexerDeploymentFields 17 | deployment { 18 | id 19 | project { 20 | id 21 | metadata 22 | } 23 | } 24 | } 25 | 26 | query GetDeployment($deploymentId: String!) { 27 | deployment(id: $deploymentId) { 28 | id 29 | metadata 30 | project { 31 | id 32 | metadata 33 | } 34 | } 35 | } 36 | 37 | query GetDeploymentIndexers( 38 | $first: Int = 20 39 | $offset: Int 40 | $deploymentId: String! 41 | $orderby: [IndexerDeploymentsOrderBy!] = LAST_EVENT_ASC 42 | ) { 43 | indexerDeployments( 44 | first: $first 45 | offset: $offset 46 | orderBy: $orderby 47 | filter: { deploymentId: { equalTo: $deploymentId }, status: { notEqualTo: TERMINATED } } 48 | ) { 49 | totalCount 50 | nodes { 51 | ...IndexerDeploymentFields 52 | } 53 | } 54 | } 55 | 56 | query GetDeploymentIndexersBySearch( 57 | $first: Int = 20 58 | $offset: Int 59 | $deploymentId: String! 60 | $orderby: [IndexerDeploymentsOrderBy!] = LAST_EVENT_ASC 61 | $indexerId: String! = "" 62 | ) { 63 | indexerDeployments( 64 | first: $first 65 | offset: $offset 66 | orderBy: $orderby 67 | filter: { 68 | deploymentId: { equalTo: $deploymentId } 69 | status: { notEqualTo: TERMINATED } 70 | indexerId: { equalTo: $indexerId } 71 | } 72 | ) { 73 | totalCount 74 | nodes { 75 | ...IndexerDeploymentFields 76 | } 77 | } 78 | } 79 | 80 | query GetIndexerDeployment($indexerAddress: String!, $deploymentId: String!) { 81 | indexerDeployments( 82 | filter: { indexerId: { equalTo: $indexerAddress }, deploymentId: { equalTo: $deploymentId } } 83 | ) { 84 | totalCount 85 | nodes { 86 | ...IndexerDeploymentFields 87 | } 88 | } 89 | } 90 | 91 | query GetDeploymentIndexersByIndexer($indexerAddress: String!) { 92 | indexerDeployments(filter: { indexerId: { equalTo: $indexerAddress } }, orderBy: ID_DESC) { 93 | totalCount 94 | pageInfo { 95 | startCursor 96 | endCursor 97 | hasNextPage 98 | } 99 | nodes { 100 | ...IndexerDeploymentFields 101 | deployment { 102 | id 103 | project { 104 | id 105 | metadata 106 | } 107 | } 108 | } 109 | } 110 | } 111 | 112 | query GetDeploymentIndexersDeploymentByIndexer($indexerAddress: String!) { 113 | indexerDeployments(filter: { indexerId: { equalTo: $indexerAddress } }) { 114 | nodes { 115 | ...IndexerDeploymentNodeFields 116 | } 117 | } 118 | } 119 | 120 | query GetAcceptedOffers($address: String!, $offerId: String!) { 121 | acceptedOffers(filter: { indexerId: { equalTo: $address }, offerId: { equalTo: $offerId } }) { 122 | totalCount 123 | nodes { 124 | id 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /packages/network-query/queries/network/eraRewards.gql: -------------------------------------------------------------------------------- 1 | query GetAggregatesEraRewards($eraIds: [String!]) { 2 | eraRewards(filter: { eraId: { in: $eraIds } }) { 3 | groupedAggregates(groupBy: ERA_ID) { 4 | sum { 5 | amount 6 | } 7 | keys 8 | } 9 | } 10 | 11 | indexerEraReward: eraRewards(filter: { eraId: { in: $eraIds }, isIndexer: { equalTo: true } }) { 12 | groupedAggregates(groupBy: ERA_ID) { 13 | sum { 14 | amount 15 | } 16 | keys 17 | } 18 | } 19 | 20 | delegationEraReward: eraRewards( 21 | filter: { eraId: { in: $eraIds }, isIndexer: { equalTo: false } } 22 | ) { 23 | groupedAggregates(groupBy: ERA_ID) { 24 | sum { 25 | amount 26 | } 27 | keys 28 | } 29 | } 30 | } 31 | 32 | query GetAggregatesEraRewardsByIndexer($indexerId: String!, $eraIds: [String!]) { 33 | eraRewards(filter: { eraId: { in: $eraIds }, indexerId: { equalTo: $indexerId } }) { 34 | groupedAggregates(groupBy: ERA_ID) { 35 | sum { 36 | amount 37 | } 38 | keys 39 | } 40 | } 41 | 42 | indexerEraReward: eraRewards( 43 | filter: { 44 | eraId: { in: $eraIds } 45 | isIndexer: { equalTo: true } 46 | indexerId: { equalTo: $indexerId } 47 | } 48 | ) { 49 | groupedAggregates(groupBy: ERA_ID) { 50 | sum { 51 | amount 52 | } 53 | keys 54 | } 55 | } 56 | 57 | delegationEraReward: eraRewards( 58 | filter: { 59 | eraId: { in: $eraIds } 60 | isIndexer: { equalTo: false } 61 | indexerId: { equalTo: $indexerId } 62 | } 63 | ) { 64 | groupedAggregates(groupBy: ERA_ID) { 65 | sum { 66 | amount 67 | } 68 | keys 69 | } 70 | } 71 | 72 | delegatorTotalRewards: eraRewards( 73 | filter: { eraId: { in: $eraIds }, delegatorId: { equalTo: $indexerId } } 74 | ) { 75 | groupedAggregates(groupBy: ERA_ID) { 76 | sum { 77 | amount 78 | } 79 | keys 80 | } 81 | } 82 | 83 | delegatorEraReward: eraRewards( 84 | filter: { 85 | eraId: { in: $eraIds } 86 | isIndexer: { equalTo: false } 87 | delegatorId: { equalTo: $indexerId } 88 | } 89 | ) { 90 | groupedAggregates(groupBy: ERA_ID) { 91 | sum { 92 | amount 93 | } 94 | keys 95 | } 96 | } 97 | } 98 | 99 | query GetDelegatorTotalRewards($delegatorId: String!) { 100 | eraRewards(filter: { delegatorId: { equalTo: $delegatorId }, isIndexer: { equalTo: false } }) { 101 | aggregates { 102 | sum { 103 | amount 104 | } 105 | } 106 | } 107 | } 108 | 109 | query GetEraRewardsByIndexerAndPage( 110 | $delegatorId: String! 111 | $offset: Int = 0 112 | $pageSize: Int = 10 113 | $orderBy: [EraRewardsOrderBy!] = CREATED_TIMESTAMP_DESC 114 | ) { 115 | eraRewards( 116 | offset: $offset 117 | first: $pageSize 118 | filter: { delegatorId: { equalTo: $delegatorId } } 119 | orderBy: $orderBy 120 | ) { 121 | nodes { 122 | createdTimestamp 123 | amount 124 | claimed 125 | eraId 126 | indexerId 127 | delegatorId 128 | isCommission 129 | isIndexer 130 | } 131 | totalCount 132 | pageInfo { 133 | hasNextPage 134 | hasPreviousPage 135 | endCursor 136 | startCursor 137 | } 138 | } 139 | unclaimedEraRewards: eraRewards( 140 | filter: { delegatorId: { equalTo: $delegatorId }, claimed: { equalTo: false } } 141 | ) { 142 | totalCount 143 | } 144 | } 145 | 146 | query GetTotalRewardsAndUnclaimRewards($account: String!) { 147 | totalRewards: eraRewards(filter: { delegatorId: { equalTo: $account } }) { 148 | aggregates { 149 | sum { 150 | amount 151 | } 152 | } 153 | } 154 | unclaimTotalRewards: eraRewards( 155 | filter: { delegatorId: { equalTo: $account }, claimed: { equalTo: false } } 156 | ) { 157 | aggregates { 158 | sum { 159 | amount 160 | } 161 | } 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /packages/network-query/queries/network/eraStakes.gql: -------------------------------------------------------------------------------- 1 | query GetEraQuery($account: String!) { 2 | eraStakes(filter: { delegatorId: { equalTo: $account }, indexerId: { notEqualTo: $account } }) { 3 | groupedAggregates(groupBy: ERA_ID) { 4 | sum { 5 | stake 6 | } 7 | keys 8 | } 9 | } 10 | } 11 | 12 | query GetEraDelegatorIndexers($account: String!) { 13 | eraDelegatorIndexers(first: 1, orderBy: ERA_DESC, filter: { delegator: { equalTo: $account } }) { 14 | nodes { 15 | era 16 | totalStake 17 | selfStake 18 | delegator 19 | } 20 | } 21 | } 22 | 23 | query GetEraDelegatorIndexersGraph($account: String!) { 24 | eraDelegatorIndexers( 25 | orderBy: ERA_DESC 26 | filter: { delegator: { equalTo: $account } } 27 | distinct: ERA 28 | ) { 29 | nodes { 30 | era 31 | totalStake 32 | selfStake 33 | delegator 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /packages/network-query/queries/network/indexerAllocation.gql: -------------------------------------------------------------------------------- 1 | # deploymentId:indexerId 2 | query GetIndexerAllocationSummary($id: String!) { 3 | indexerAllocationSummary(id: $id) { 4 | totalAmount 5 | } 6 | } 7 | 8 | query GetIndexerAllocationProjects($id: String!) { 9 | indexerAllocationSummaries( 10 | filter: { indexerId: { equalTo: $id }, totalAmount: { greaterThan: "0" } } 11 | ) { 12 | nodes { 13 | deploymentId 14 | projectId 15 | totalAmount 16 | indexerId 17 | deployment { 18 | project { 19 | metadata 20 | } 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/network-query/queries/network/indexerAllocationRewards.gql: -------------------------------------------------------------------------------- 1 | query GetAllocationRewardsByDeploymentId($deploymentId: String!) { 2 | indexerAllocationRewards(filter: { deploymentId: { equalTo: $deploymentId } }) { 3 | aggregates { 4 | sum { 5 | reward 6 | } 7 | } 8 | } 9 | } 10 | 11 | query GetAllocationRewardsByDeploymentIdAndIndexerId($indexerId: String!) { 12 | indexerAllocationRewards(filter: { indexerId: { equalTo: $indexerId } }) { 13 | groupedAggregates(groupBy: DEPLOYMENT_ID) { 14 | sum { 15 | reward 16 | } 17 | keys 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/network-query/queries/network/indexerApr.gql: -------------------------------------------------------------------------------- 1 | # if two same fragment 2 | fragment IndexerFieldsUsedOnApy on Indexer { 3 | id 4 | controller 5 | commission 6 | totalStake 7 | selfStake 8 | maxUnstakeAmount 9 | capacity 10 | metadata 11 | indexerStakes(orderBy: ERA_ID_DESC) { 12 | nodes { 13 | indexerStake 14 | eraIdx 15 | eraId 16 | } 17 | } 18 | } 19 | 20 | query GetAllIndexerByApy( 21 | $first: Int 22 | $offset: Int 23 | $orderBy: [IndexerApySummariesOrderBy!] = [INDEXER_APY_DESC] 24 | $filter: IndexerApySummaryFilter 25 | ) { 26 | indexerApySummaries(first: $first, offset: $offset, orderBy: $orderBy, filter: $filter) { 27 | nodes { 28 | eraIdx 29 | indexerId 30 | indexerApy 31 | delegatorApy 32 | indexerReward 33 | delegatorReward 34 | indexer { 35 | ...IndexerFieldsUsedOnApy 36 | } 37 | } 38 | totalCount 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /packages/network-query/queries/network/indexerStake.gql: -------------------------------------------------------------------------------- 1 | query GetIndexerStakesByIndexer($indexerId: String!) { 2 | indexerStakes(filter: { id: { includes: $indexerId } }) { 3 | groupedAggregates(groupBy: ERA_ID) { 4 | keys 5 | sum { 6 | delegatorStake 7 | indexerStake 8 | totalStake 9 | } 10 | } 11 | } 12 | } 13 | 14 | query GetIndexerStakesByEras($eraIds: [String!]) { 15 | indexerStakes(filter: { id: { in: $eraIds } }) { 16 | groupedAggregates(groupBy: ERA_ID) { 17 | keys 18 | sum { 19 | delegatorStake 20 | indexerStake 21 | totalStake 22 | } 23 | } 24 | } 25 | } 26 | 27 | query GetIndexerStakesByIndexerAndEra($indexerId: String!, $eraIdx: Int!) { 28 | indexerStakes(filter: { indexerId: { equalTo: $indexerId }, eraIdx: { equalTo: $eraIdx } }) { 29 | nodes { 30 | delegatorStake 31 | indexerStake 32 | totalStake 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /packages/network-query/queries/network/indexers.gql: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | fragment IndexerFields on Indexer { 5 | id 6 | controller 7 | commission 8 | totalStake 9 | selfStake 10 | maxUnstakeAmount 11 | capacity 12 | metadata 13 | indexerStakes(orderBy: ERA_ID_DESC) { 14 | nodes { 15 | indexerStake 16 | eraIdx 17 | eraId 18 | } 19 | } 20 | } 21 | 22 | query GetIndexer($address: String!) { 23 | indexer(id: $address) { 24 | ...IndexerFields 25 | } 26 | } 27 | 28 | query GetIndexers( 29 | $first: Int 30 | $offset: Int 31 | $order: IndexersOrderBy = ID_ASC 32 | $filter: IndexerFilter = { active: { equalTo: true } } 33 | ) { 34 | indexers(first: $first, offset: $offset, orderBy: [$order], filter: $filter) { 35 | totalCount 36 | pageInfo { 37 | startCursor 38 | endCursor 39 | hasNextPage 40 | } 41 | nodes { 42 | ...IndexerFields 43 | } 44 | } 45 | } 46 | 47 | query GetIndexersWithProjects($offset: Int, $order: IndexersOrderBy = ID_ASC) { 48 | indexers(first: 100, offset: $offset, orderBy: [$order], filter: { active: { equalTo: true } }) { 49 | totalCount 50 | nodes { 51 | ...IndexerFields 52 | projects { 53 | nodes { 54 | deploymentId 55 | status 56 | } 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /packages/network-query/queries/network/offers.gql: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | fragment OfferFields on Offer { 5 | id 6 | consumer 7 | deployment { 8 | id 9 | project { 10 | id 11 | metadata 12 | } 13 | } 14 | planTemplate { 15 | id 16 | period 17 | dailyReqCap 18 | active 19 | rateLimit 20 | } 21 | deposit 22 | minimumAcceptHeight 23 | minimumStakingAmount 24 | expireDate 25 | limit # indexer cap 26 | accepted # accepted indexer amount 27 | reachLimit # whether reach limit 28 | withdrawn # withdraw by cancel event 29 | } 30 | 31 | query GetOwnOpenOffers( 32 | $consumer: String! 33 | $now: Datetime! 34 | $offset: Int 35 | $reachLimit: Boolean = false 36 | ) { 37 | offers( 38 | filter: { 39 | consumer: { equalTo: $consumer } 40 | expireDate: { greaterThan: $now } 41 | reachLimit: { equalTo: $reachLimit } 42 | } 43 | first: 10 44 | offset: $offset 45 | ) { 46 | totalCount 47 | nodes { 48 | ...OfferFields 49 | } 50 | } 51 | } 52 | 53 | query GetOwnFinishedOffers( 54 | $consumer: String! 55 | $now: Datetime! 56 | $offset: Int 57 | $reachLimit: Boolean = true 58 | ) { 59 | offers( 60 | filter: { 61 | consumer: { equalTo: $consumer } 62 | expireDate: { greaterThan: $now } 63 | reachLimit: { equalTo: $reachLimit } 64 | } 65 | first: 10 66 | offset: $offset 67 | ) { 68 | totalCount 69 | nodes { 70 | ...OfferFields 71 | } 72 | } 73 | } 74 | 75 | query GetOwnExpiredOffers( 76 | $consumer: String! 77 | $now: Datetime! 78 | $offset: Int 79 | $reachLimit: Boolean = false 80 | ) { 81 | offers( 82 | filter: { 83 | consumer: { equalTo: $consumer } 84 | expireDate: { lessThan: $now } 85 | reachLimit: { equalTo: $reachLimit } 86 | } 87 | first: 10 88 | offset: $offset 89 | ) { 90 | totalCount 91 | nodes { 92 | ...OfferFields 93 | } 94 | } 95 | } 96 | 97 | query GetAllOpenOffers($now: Datetime!, $offset: Int, $reachLimit: Boolean = false) { 98 | offers( 99 | filter: { expireDate: { greaterThan: $now }, reachLimit: { equalTo: $reachLimit } } 100 | first: 10 101 | offset: $offset 102 | ) { 103 | totalCount 104 | nodes { 105 | ...OfferFields 106 | } 107 | } 108 | } 109 | 110 | query GetSpecificOpenOffers( 111 | $deploymentId: String! 112 | $now: Datetime! 113 | $offset: Int 114 | $reachLimit: Boolean = false 115 | ) { 116 | offers( 117 | filter: { 118 | expireDate: { greaterThan: $now } 119 | reachLimit: { equalTo: $reachLimit } 120 | deploymentId: { equalTo: $deploymentId } 121 | } 122 | first: 10 123 | offset: $offset 124 | ) { 125 | totalCount 126 | nodes { 127 | ...OfferFields 128 | } 129 | } 130 | } 131 | 132 | query GetOfferCount($consumer: String!, $reachLimit: Boolean = false) { 133 | offers(filter: { consumer: { equalTo: $consumer }, reachLimit: { equalTo: $reachLimit } }) { 134 | totalCount 135 | } 136 | } 137 | 138 | query GetOfferCountByDeploymentId($deploymentId: String!) { 139 | offers(filter: { deploymentId: { equalTo: $deploymentId } }) { 140 | totalCount 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /packages/network-query/queries/network/orders.gql: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | query GetOrders($swapFrom: String!) { 5 | orders( 6 | orderBy: UPDATE_AT_DESC 7 | filter: { status: { equalTo: ACTIVE }, tokenGive: { equalTo: $swapFrom } } 8 | ) { 9 | totalCount 10 | nodes { 11 | id 12 | status 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/network-query/queries/network/plans.gql: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | fragment PlanTemplateFields on PlanTemplate { 5 | id 6 | period 7 | dailyReqCap 8 | rateLimit 9 | metadata 10 | active 11 | priceToken 12 | } 13 | 14 | fragment PlanFields on Plan { 15 | id 16 | active 17 | creator 18 | deploymentId 19 | price 20 | } 21 | 22 | fragment PlansNodeFields on Plan { 23 | id 24 | active 25 | creator 26 | deploymentId 27 | price 28 | planTemplate { 29 | id 30 | period 31 | dailyReqCap 32 | rateLimit 33 | metadata 34 | active 35 | priceToken 36 | } 37 | } 38 | 39 | query GetDeploymentPlans($address: String!, $deploymentId: String!) { 40 | plans( 41 | filter: { 42 | creator: { equalTo: $address } 43 | and: [ 44 | { active: { equalTo: true } } 45 | { or: [{ deploymentId: { isNull: true } }, { deploymentId: { equalTo: $deploymentId } }] } 46 | ] 47 | } 48 | ) { 49 | totalCount 50 | nodes { 51 | ...PlanFields 52 | planTemplate { 53 | ...PlanTemplateFields 54 | } 55 | } 56 | } 57 | } 58 | 59 | query GetPlanTemplates($offset: Int) { 60 | planTemplates(first: 10, offset: $offset, filter: { active: { equalTo: true } }) { 61 | totalCount 62 | nodes { 63 | ...PlanTemplateFields 64 | } 65 | } 66 | } 67 | 68 | query GetPlans($address: String!) { 69 | plans( 70 | filter: { 71 | creator: { equalTo: $address } 72 | and: { deploymentId: { isNull: true } } 73 | active: { equalTo: true } 74 | } 75 | ) { 76 | totalCount 77 | nodes { 78 | ...PlanFields 79 | planTemplate { 80 | ...PlanTemplateFields 81 | } 82 | } 83 | } 84 | } 85 | 86 | query GetSpecificPlans($address: String) { 87 | indexerDeployments(filter: { indexerId: { equalTo: $address } }) { 88 | totalCount 89 | nodes { 90 | deployment { 91 | id 92 | project { 93 | id 94 | metadata 95 | } 96 | plans(filter: { creator: { equalTo: $address }, and: { active: { equalTo: true } } }) { 97 | nodes { 98 | ...PlanFields 99 | planTemplate { 100 | ...PlanTemplateFields 101 | } 102 | } 103 | } 104 | } 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /packages/network-query/queries/network/project.gql: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | fragment ProjectFields on Project { 5 | id 6 | owner 7 | metadata 8 | deploymentMetadata 9 | deploymentId 10 | updatedTimestamp 11 | createdTimestamp 12 | type 13 | deployments { 14 | nodes { 15 | id 16 | serviceAgreements { 17 | aggregates { 18 | sum { 19 | lockedAmount 20 | } 21 | } 22 | totalCount 23 | } 24 | serviceAgreementsActive: serviceAgreements( 25 | filter: { endTime: { greaterThanOrEqualTo: $now } } 26 | ) { 27 | totalCount 28 | } 29 | indexers( 30 | filter: { indexer: { active: { equalTo: true } }, status: { notEqualTo: TERMINATED } } 31 | ) { 32 | totalCount 33 | } 34 | deploymentBoosterSummaries { 35 | groupedAggregates(groupBy: PROJECT_ID) { 36 | sum { 37 | totalAmount 38 | } 39 | } 40 | } 41 | 42 | deploymentBoosterSummariesByDeploymentId: deploymentBoosterSummaries { 43 | groupedAggregates(groupBy: DEPLOYMENT_ID) { 44 | sum { 45 | totalAmount 46 | } 47 | keys 48 | } 49 | } 50 | } 51 | } 52 | totalReward 53 | } 54 | 55 | fragment ProjectUpdateField on Project { 56 | id 57 | owner 58 | metadata 59 | updatedTimestamp 60 | totalReward 61 | deployments { 62 | nodes { 63 | serviceAgreements { 64 | aggregates { 65 | sum { 66 | lockedAmount 67 | } 68 | } 69 | totalCount 70 | } 71 | serviceAgreementsActive: serviceAgreements( 72 | filter: { endTime: { greaterThanOrEqualTo: $now } } 73 | ) { 74 | totalCount 75 | } 76 | indexers( 77 | filter: { indexer: { active: { equalTo: true } }, status: { notEqualTo: TERMINATED } } 78 | ) { 79 | totalCount 80 | } 81 | } 82 | } 83 | } 84 | 85 | query GetProject($id: String!, $now: Datetime = "1970-01-01T00:00:00") { 86 | project(id: $id) { 87 | ...ProjectFields 88 | } 89 | } 90 | 91 | query GetProjects( 92 | $offset: Int 93 | $type: [ProjectType!] = [SUBQUERY, RPC] 94 | $orderBy: [ProjectsOrderBy!] = ID_ASC 95 | $ids: [String!] = [""] 96 | $now: Datetime = "1970-01-01T00:00:00" 97 | ) { 98 | projects( 99 | first: 10 100 | offset: $offset 101 | orderBy: $orderBy 102 | filter: { id: { notIn: $ids }, type: { in: $type } } 103 | ) { 104 | totalCount 105 | nodes { 106 | ...ProjectFields 107 | } 108 | } 109 | } 110 | 111 | query GetProjectsAll($now: Datetime = "1970-01-01T00:00:00") { 112 | projects(orderBy: ID_ASC) { 113 | nodes { 114 | ...ProjectUpdateField 115 | } 116 | } 117 | } 118 | 119 | query GetProjectDeployments($projectId: String!) { 120 | project(id: $projectId) { 121 | deployments { 122 | totalCount 123 | nodes { 124 | id 125 | metadata 126 | createdTimestamp 127 | } 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /packages/network-query/queries/network/staking.gql: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | fragment WithdrawalFields on Withdrawl { 5 | id 6 | index 7 | delegator 8 | indexer 9 | startTime 10 | amount 11 | status 12 | type 13 | } 14 | 15 | fragment RewardFields on Reward { 16 | id 17 | delegatorAddress 18 | indexerAddress 19 | amount 20 | claimedTime 21 | } 22 | 23 | fragment UnclaimedRewardFields on UnclaimedReward { 24 | id 25 | delegatorAddress 26 | indexerAddress 27 | amount 28 | } 29 | 30 | fragment IndexerRewardFields on IndexerReward { 31 | id 32 | indexerId 33 | eraIdx 34 | amount 35 | } 36 | 37 | query GetWithdrawls($delegator: String!, $status: WithdrawalStatus!, $offset: Int) { 38 | withdrawls( 39 | filter: { delegator: { equalTo: $delegator }, status: { equalTo: $status } } 40 | offset: $offset 41 | ) { 42 | totalCount 43 | nodes { 44 | ...WithdrawalFields 45 | } 46 | } 47 | } 48 | 49 | query GetTotalDelegationWithdrawls($delegator: String!) { 50 | withdrawls(filter: { delegator: { equalTo: $delegator }, type: { equalTo: UNDELEGATION } }) { 51 | aggregates { 52 | sum { 53 | amount 54 | } 55 | } 56 | } 57 | } 58 | 59 | query GetRewards($address: String!) { 60 | rewards(orderBy: CLAIMED_TIME_DESC, filter: { delegatorAddress: { equalTo: $address } }) { 61 | totalCount 62 | nodes { 63 | ...RewardFields 64 | } 65 | } 66 | unclaimedRewards( 67 | filter: { delegatorAddress: { equalTo: $address }, amount: { greaterThan: "0" } } 68 | ) { 69 | totalCount 70 | nodes { 71 | ...UnclaimedRewardFields 72 | } 73 | } 74 | } 75 | 76 | query GetIndexerRewards($address: String!, $era1: String!, $era2: String!) { 77 | indexerRewards( 78 | filter: { 79 | indexerId: { equalTo: $address } 80 | and: { eraIdx: { equalTo: $era1 } } 81 | or: { eraIdx: { equalTo: $era2 } } 82 | } 83 | ) { 84 | totalCount 85 | nodes { 86 | ...IndexerRewardFields 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /packages/network-query/queries/network/statechannel.gql: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | fragment StateChannelFields on StateChannel { 5 | id 6 | indexer 7 | consumer 8 | status 9 | agent 10 | total 11 | spent 12 | price 13 | isFinal 14 | expiredAt 15 | terminatedAt 16 | deployment { 17 | id 18 | project { 19 | id 20 | type 21 | metadata 22 | } 23 | } 24 | terminateByIndexer 25 | } 26 | 27 | query GetFlexPlan($id: String!) { 28 | stateChannel(id: $id) { 29 | ...StateChannelFields 30 | } 31 | } 32 | 33 | query GetPaygPlans($indexer: String!, $deploymentId: String!, $status: ChannelStatus!) { 34 | stateChannels( 35 | filter: { 36 | indexer: { equalTo: $indexer } 37 | status: { equalTo: $status } 38 | deploymentId: { equalTo: $deploymentId } 39 | } 40 | ) { 41 | totalCount 42 | nodes { 43 | ...StateChannelFields 44 | } 45 | } 46 | } 47 | 48 | query GetStateChannels($status: ChannelStatus!) { 49 | stateChannels(filter: { status: { equalTo: $status } }) { 50 | totalCount 51 | nodes { 52 | ...StateChannelFields 53 | } 54 | } 55 | } 56 | 57 | # CONSUMER STATE CHANNEL QUERIES 58 | 59 | query GetConsumerOngoingFlexPlans( 60 | $consumer: String! 61 | $now: Datetime! 62 | $first: Int = 0 63 | $offset: Int 64 | ) { 65 | stateChannels( 66 | filter: { 67 | consumer: { equalTo: $consumer } 68 | status: { equalTo: OPEN } 69 | expiredAt: { greaterThan: $now } 70 | } 71 | first: $first 72 | offset: $offset 73 | ) { 74 | totalCount 75 | nodes { 76 | ...StateChannelFields 77 | } 78 | } 79 | } 80 | 81 | query GetConsumerClosedFlexPlans($consumer: String!, $now: Datetime!, $offset: Int) { 82 | stateChannels( 83 | filter: { 84 | consumer: { equalTo: $consumer } 85 | or: [{ status: { equalTo: FINALIZED } }, { expiredAt: { lessThan: $now } }] 86 | } 87 | offset: $offset 88 | ) { 89 | totalCount 90 | nodes { 91 | ...StateChannelFields 92 | } 93 | } 94 | } 95 | 96 | query GetConsumerFlexPlansByDeploymentId( 97 | $consumer: String! 98 | $now: Datetime! 99 | $first: Int = 0 100 | $offset: Int 101 | $deploymentId: String! 102 | ) { 103 | stateChannels( 104 | filter: { 105 | consumer: { equalTo: $consumer } 106 | deploymentId: { equalTo: $deploymentId } 107 | expiredAt: { greaterThan: $now } 108 | } 109 | first: $first 110 | offset: $offset 111 | ) { 112 | totalCount 113 | nodes { 114 | ...StateChannelFields 115 | } 116 | } 117 | } 118 | 119 | # INDEXER STATE CHANNEL QUERIES 120 | 121 | query GetIndexerOngoingFlexPlans( 122 | $indexer: String! 123 | $deploymentId: String! 124 | $now: Datetime! 125 | $offset: Int 126 | ) { 127 | stateChannels( 128 | filter: { 129 | indexer: { equalTo: $indexer } 130 | status: { equalTo: OPEN } 131 | expiredAt: { greaterThan: $now } 132 | deploymentId: { equalTo: $deploymentId } 133 | } 134 | offset: $offset 135 | ) { 136 | totalCount 137 | nodes { 138 | ...StateChannelFields 139 | } 140 | } 141 | } 142 | 143 | query GetIndexerClosedFlexPlans( 144 | $indexer: String! 145 | $deploymentId: String! 146 | $now: Datetime! 147 | $offset: Int 148 | ) { 149 | stateChannels( 150 | filter: { 151 | indexer: { equalTo: $indexer } 152 | deploymentId: { equalTo: $deploymentId } 153 | or: [{ status: { equalTo: FINALIZED } }, { expiredAt: { lessThan: $now } }] 154 | } 155 | offset: $offset 156 | ) { 157 | totalCount 158 | nodes { 159 | ...StateChannelFields 160 | } 161 | } 162 | } 163 | 164 | query GetIndexerUnfinalisedPlans($indexer: String!, $now: Datetime!) { 165 | stateChannels( 166 | filter: { 167 | indexer: { equalTo: $indexer } 168 | status: { notEqualTo: FINALIZED } 169 | expiredAt: { lessThan: $now } 170 | } 171 | ) { 172 | totalCount 173 | nodes { 174 | ...StateChannelFields 175 | } 176 | } 177 | } 178 | 179 | query GetConsumerFlexPlan($id: String!) { 180 | stateChannel(id: $id) { 181 | ...StateChannelFields 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /packages/network-query/queries/network/totalLock.gql: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | fragment TotalLockFields on TotalLock { 5 | id 6 | totalStake 7 | totalDelegation 8 | } 9 | 10 | query GetTotalLock { 11 | totalLocks { 12 | totalCount 13 | nodes { 14 | ...TotalLockFields 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/network-query/scripts/codegen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # base types 4 | graphql-codegen --config types.codegen.ts 5 | 6 | # network 7 | graphql-codegen --config network.codegen.ts 8 | 9 | # leaderboard 10 | graphql-codegen --config leaderboard.codegen.ts 11 | 12 | yarn prettier --write . 13 | 14 | # creating export files 15 | yarn ctix create --startAt ./src/__graphql__ --overwrite --noBackup 16 | -------------------------------------------------------------------------------- /packages/network-query/src/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | export * from './__graphql__'; 5 | -------------------------------------------------------------------------------- /packages/network-query/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "target": "es2017", 5 | "sourceMap": true, 6 | "resolveJsonModule": true, 7 | "rootDir": "./src", 8 | "outDir": "./dist" 9 | }, 10 | "include": ["src/**/*", "test/**/*"] 11 | } 12 | -------------------------------------------------------------------------------- /packages/network-query/types.codegen.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { CodegenConfig } from '@graphql-codegen/cli'; 5 | import { NETWORK_CONFIGS } from '@subql/network-config'; 6 | 7 | const config: CodegenConfig = { 8 | schema: [`${NETWORK_CONFIGS.mainnet.gql.network}`, `${NETWORK_CONFIGS.mainnet.gql.leaderboard}`], 9 | documents: ['./queries/network/*.gql', './queries/leaderboard/*.gql'], 10 | config: { 11 | preResolveTypes: true, 12 | namingConvention: 'keep', 13 | avoidOptionals: { 14 | field: true, 15 | object: false, 16 | inputValue: false, 17 | defaultValue: false, 18 | }, 19 | nonOptionalTypename: true, 20 | skipTypeNameForRoot: true, 21 | immutableTypes: true, 22 | scalars: { 23 | Date: 'Date', 24 | Datetime: 'Date', 25 | BigFloat: 'bigint' || 'string', 26 | BigInt: 'bigint', 27 | Cursor: 'string', 28 | }, 29 | }, 30 | generates: { 31 | 'src/__graphql__/base-types.ts': { 32 | plugins: ['typescript', 'typescript-operations'], 33 | }, 34 | }, 35 | }; 36 | 37 | export default config; 38 | -------------------------------------------------------------------------------- /packages/network-support/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [Unreleased] 9 | 10 | ## [1.2.6] 2024-05-20 11 | 12 | ## [1.2.5] 2024-05-16 13 | 14 | ## [1.2.4] 2024-05-13 15 | 16 | ## [1.2.3] 2024-05-12 17 | 18 | ## [1.2.2] 2024-05-01 19 | 20 | ## [1.2.1] 2024-04-30 21 | 22 | ## [1.2.0] 2024-04-29 23 | 24 | ## [1.1.2] 2024-04-08 25 | 26 | ## [1.1.1] 2024-03-22 27 | 28 | ## [1.1.0] 2024-03-15 29 | 30 | ## [1.0.0] 2024-03-07 31 | 32 | ## [0.2.0] 2024-01-12 33 | 34 | ## [0.1.1] 2024-01-11 35 | 36 | ## [0.1.0] 2023-11-27 37 | 38 | ### Added 39 | 40 | - It's a internal library. 41 | 42 | [unreleased]: https://github.com/subquery/network-support/compare/v1.2.6...HEAD 43 | [1.2.6]: https://github.com/subquery/network-support/releases/tag/v1.2.6 44 | [1.2.5]: https://github.com/subquery/network-support/releases/tag/v1.2.5 45 | [1.2.4]: https://github.com/subquery/network-support/releases/tag/v1.2.4 46 | [1.2.3]: https://github.com/subquery/network-support/releases/tag/v1.2.3 47 | [1.2.2]: https://github.com/subquery/network-support/releases/tag/v1.2.2 48 | [1.2.1]: https://github.com/subquery/network-support/releases/tag/v1.2.1 49 | [1.2.0]: https://github.com/subquery/network-support/releases/tag/v1.2.0 50 | [1.1.2]: https://github.com/subquery/network-support/releases/tag/v1.1.2 51 | [1.1.1]: https://github.com/subquery/network-support/releases/tag/v1.1.1 52 | [1.1.0]: https://github.com/subquery/network-support/releases/tag/v1.1.0 53 | [1.0.0]: https://github.com/subquery/network-support/releases/tag/v1.0.0 54 | [0.2.0]: https://github.com/subquery/network-support/releases/tag/v0.2.0 55 | [0.1.1]: https://github.com/subquery/network-support/releases/tag/v0.1.1 56 | [0.1.0]: https://github.com/subquery/network-support/releases/tag/v0.1.0 57 | -------------------------------------------------------------------------------- /packages/network-support/README.md: -------------------------------------------------------------------------------- 1 | # network-support 2 | -------------------------------------------------------------------------------- /packages/network-support/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@subql/network-support", 3 | "version": "1.2.7-1", 4 | "main": "dist/index.js", 5 | "author": "SubQuery Pte Limited", 6 | "license": "Apache-2.0", 7 | "scripts": { 8 | "build": "tsc -b" 9 | }, 10 | "packageManager": "yarn@3.2.4", 11 | "dependencies": { 12 | "@metamask/eth-sig-util": "^7.0.0", 13 | "cross-fetch": "^4.0.0", 14 | "crypto-js": "^4.2.0", 15 | "js-base64": "^3.7.5", 16 | "jwt-decode": "^3.1.2", 17 | "lru-cache": "^10.0.1", 18 | "semver": "^7.6.0" 19 | }, 20 | "devDependencies": { 21 | "@types/crypto-js": "^4.2.2", 22 | "@types/node": "18", 23 | "typescript": "^4.6.4" 24 | }, 25 | "browser": { 26 | "node-fetch": false 27 | }, 28 | "stableVersion": "1.2.7-0" 29 | } 30 | -------------------------------------------------------------------------------- /packages/network-support/src/fetch.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { OrderManager } from './orderManager'; 5 | import { customFetch, generateUniqueId, Logger, safeJSONParse } from './utils'; 6 | import { OrderType } from './types'; 7 | import { ScoreType } from './scoreManager'; 8 | import { Base64 } from 'js-base64'; 9 | 10 | interface SystemError extends Error { 11 | code?: string | undefined; 12 | } 13 | 14 | export class FetchError extends Error { 15 | public override name = 'FetchError'; 16 | public type: string; 17 | public code?: string | undefined; 18 | public errno?: string | undefined; 19 | 20 | constructor(message: string, type: string, systemError?: SystemError) { 21 | super(message); 22 | this.type = type; 23 | if (systemError) { 24 | this.code = this.errno = systemError.code; 25 | } 26 | Error.captureStackTrace(this, this.constructor); 27 | } 28 | } 29 | 30 | // FetchError.prototype = Object.create(Error.prototype); 31 | // FetchError.prototype.constructor = FetchError; 32 | 33 | export function createFetch( 34 | orderManager: OrderManager, 35 | maxRetries = 5, 36 | logger?: Logger, 37 | overrideFetch?: typeof fetch 38 | ): (init: RequestInit) => Promise { 39 | let retries = 0; 40 | let triedFallback = false; 41 | let errorMsg = ''; 42 | return async function fetch(init: RequestInit): Promise { 43 | const requestId = generateUniqueId(); 44 | const requestResult: () => Promise = async () => { 45 | if (init.method?.toLowerCase() !== 'post') { 46 | throw new FetchError(`method not supported`, 'sqn'); 47 | } 48 | let requestParams; 49 | if (retries < maxRetries) { 50 | requestParams = await orderManager.getRequestParams(requestId); 51 | } 52 | if (!requestParams) { 53 | if (orderManager.fallbackServiceUrl && !triedFallback) { 54 | triedFallback = true; 55 | requestParams = { 56 | url: orderManager.fallbackServiceUrl, 57 | headers: {}, 58 | type: OrderType.fallback, 59 | runner: 'fallback', 60 | channelId: 'fallback', 61 | }; 62 | logger?.warn(`fallback to ${orderManager.fallbackServiceUrl}`); 63 | } else { 64 | throw new FetchError( 65 | `no available order. retries: ${retries}.${errorMsg ? ' error: ' + errorMsg : ''}`, 66 | 'sqn' 67 | ); 68 | } 69 | } 70 | const { url, headers, type, runner, channelId } = requestParams; 71 | let httpVersion = 1; 72 | 73 | try { 74 | const _res = await customFetch( 75 | url, 76 | { 77 | headers: { 78 | ...(init.headers || {}), 79 | ...headers, 80 | }, 81 | method: 'post', 82 | body: init.body, 83 | }, 84 | overrideFetch 85 | ); 86 | 87 | httpVersion = Number(_res.headers.get('httpVersion')) || 1; 88 | 89 | let res: object; 90 | if (type === OrderType.flexPlan) { 91 | [res] = orderManager.extractChannelState( 92 | await _res.text(), 93 | new Headers(_res.headers), 94 | channelId 95 | ); 96 | } 97 | if (type === OrderType.agreement) { 98 | const data = await _res.json(); 99 | // todo: need to confirm 100 | res = { 101 | ...data, 102 | ...JSON.parse(Base64.decode(data.result)), 103 | }; 104 | } 105 | if (type === OrderType.fallback) { 106 | res = await _res.json(); 107 | } 108 | 109 | orderManager.updateScore(runner, ScoreType.SUCCESS, httpVersion); 110 | 111 | return { 112 | status: _res.status, 113 | headers: _res.headers, 114 | ok: _res.ok, 115 | body: null, 116 | json: () => res, 117 | text: () => undefined, 118 | } as unknown as Response; 119 | } catch (e) { 120 | logger?.warn(e); 121 | errorMsg = (e as Error)?.message || ''; 122 | if (retries < maxRetries || (orderManager.fallbackServiceUrl && !triedFallback)) { 123 | const errorObj = safeJSONParse(errorMsg); 124 | if (!(errorObj?.code === 1140 && errorObj?.error === 'Invalid request')) { 125 | orderManager.updateScore(runner, ScoreType.RPC); 126 | } 127 | retries += 1; 128 | return requestResult(); 129 | } 130 | throw new FetchError(`reach max retries.${errorMsg ? ' error: ' + errorMsg : ''}`, 'SQN'); 131 | } 132 | }; 133 | 134 | return requestResult(); 135 | }; 136 | } 137 | -------------------------------------------------------------------------------- /packages/network-support/src/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2023 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | export * from './types'; 5 | export * from './orderManager'; 6 | export * from './scoreManager'; 7 | export * from './stateManager'; 8 | export * from './utils'; 9 | export * from './fetch'; 10 | -------------------------------------------------------------------------------- /packages/network-support/src/scoreManager.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2023 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { Logger } from './utils'; 5 | import { IStore, createStore } from './utils/store'; 6 | 7 | type Options = { 8 | logger: Logger; 9 | projectId: string; 10 | fallbackServiceUrl?: string; 11 | scoreStore?: IStore; 12 | }; 13 | 14 | export enum ScoreType { 15 | GRAPHQL = 'Graphql', 16 | NETWORK = 'network', 17 | RPC = 'RPC', 18 | SUCCESS = 'success', 19 | } 20 | 21 | const scoresDelta = { 22 | [ScoreType.GRAPHQL]: -50, 23 | [ScoreType.NETWORK]: -30, 24 | [ScoreType.RPC]: -10, 25 | [ScoreType.SUCCESS]: 50, 26 | }; 27 | 28 | type ScoreStoreType = { 29 | score: number; 30 | httpVersion?: number; 31 | lastUpdate: number; 32 | lastFailed: number; 33 | }; 34 | 35 | const HTTP2_BONUS = 1.5; 36 | 37 | export class ScoreManager { 38 | private logger: Logger; 39 | private scoreStore: IStore; 40 | private minScore: number; 41 | private projectId: string; 42 | 43 | constructor(options: Options) { 44 | this.logger = options.logger; 45 | this.scoreStore = options.scoreStore ?? createStore({ ttl: 86_400_000 }); 46 | this.minScore = options.fallbackServiceUrl ? 0 : 1; 47 | this.projectId = options.projectId; 48 | } 49 | 50 | async getScore(runner: string) { 51 | const key = this.getCacheKey(runner); 52 | const score = (await this.scoreStore.get(key)) || { 53 | score: 100, 54 | httpVersion: 1, 55 | lastUpdate: 0, 56 | lastFailed: 0, 57 | }; 58 | return this.calculatedScore(score); 59 | } 60 | 61 | private calculatedScore(score: ScoreStoreType) { 62 | return Math.min(score.score + Math.floor((Date.now() - score.lastUpdate) / 600_000), 100); 63 | } 64 | 65 | async getBonusScore(runner: string) { 66 | const base = await this.getScore(runner); 67 | const http2 = (await this.getHttpVersion(runner)) == 2 ? HTTP2_BONUS : 1; 68 | const manual = await this.getManualScore(runner); 69 | return base * http2 * manual; 70 | } 71 | 72 | async getManualScore(runner: string) { 73 | const key = this.getManualScoreKey(); 74 | const manualScore = (await this.scoreStore.get>(key)) || {}; 75 | return manualScore[runner] || 1; 76 | } 77 | 78 | async updateScore(runner: string, errorType: ScoreType, httpVersion?: number) { 79 | if (!runner) { 80 | this.logger?.debug('updateScore: runner is empty'); 81 | return; 82 | } 83 | 84 | const key = this.getCacheKey(runner); 85 | const score = (await this.scoreStore.get(key)) || { 86 | score: 100, 87 | httpVersion, 88 | lastUpdate: 0, 89 | lastFailed: 0, 90 | }; 91 | 92 | if (errorType !== ScoreType.SUCCESS) { 93 | this.logger?.debug(`updateScore type: ${runner} ${errorType}`); 94 | } 95 | this.logger?.debug(`updateScore before: ${runner} ${JSON.stringify(score)}`); 96 | 97 | const delta = scoresDelta[errorType]; 98 | 99 | score.score = Math.min(Math.max(score.score + delta, this.minScore), 100); 100 | score.httpVersion = httpVersion || score.httpVersion; 101 | score.lastUpdate = Date.now(); 102 | score.lastFailed = errorType === ScoreType.SUCCESS ? 0 : Date.now(); 103 | 104 | this.logger?.debug(`updateScore after: ${runner} ${JSON.stringify(score)}`); 105 | 106 | this.scoreStore.set(key, score); 107 | } 108 | 109 | async getHttpVersion(runner: string) { 110 | const key = this.getCacheKey(runner); 111 | return (await this.scoreStore.get(key))?.httpVersion || 1; 112 | } 113 | 114 | private getCacheKey(runner: string): string { 115 | return `$query-score-${runner}-${this.projectId}`; 116 | } 117 | 118 | private getManualScoreKey(): string { 119 | return 'score:manual'; 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /packages/network-support/src/types.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | export enum ProjectType { 5 | dictionary = 'dictionary', 6 | deployment = 'deployment', 7 | } 8 | 9 | export enum OrderType { 10 | agreement = 'agreement', 11 | flexPlan = 'flexPlan', 12 | fallback = 'fallback', 13 | } 14 | 15 | export type OrderWithType = (Order | ServiceAgreementOrder) & { type: OrderType }; 16 | 17 | export interface IndexingMetadata { 18 | subqueryHealthy: boolean; 19 | coordinatorVersion: string; 20 | proxyVersion: string; 21 | lastHeight: number; 22 | targetHeight: number; 23 | } 24 | 25 | export interface Order { 26 | id: string; 27 | indexer: string; 28 | url: string; 29 | metadata: IndexingMetadata; 30 | } 31 | 32 | export interface ServiceAgreementOrder extends Order { 33 | token: string; 34 | } 35 | 36 | export type FlexPlanOrder = Order; 37 | 38 | export type ChannelState = { 39 | channelId: string; 40 | indexer: string; 41 | consumer: string; 42 | spent: string; 43 | remote: string; 44 | isFinal: boolean; 45 | indexerSign: string; 46 | consumerSign: string; 47 | }; 48 | 49 | export type ChannelAuth = { 50 | authorization: string; 51 | }; 52 | 53 | export type RequestParam = { 54 | url: string; 55 | headers: { [key: string]: string }; 56 | type: OrderType; 57 | runner: string; 58 | channelId?: string; 59 | }; 60 | 61 | export class RequestParamError extends Error { 62 | constructor(message: string, public runner: string) { 63 | super(message); 64 | } 65 | } 66 | 67 | export interface WrappedResponse { 68 | result: string; // base64 encoded 69 | signature: string; // indexer signature 70 | state: string; // base64 encoded channel state 71 | } 72 | 73 | export interface RunnerSelector { 74 | runnerAddresses?: string[]; 75 | agreements?: string[]; 76 | channelIds?: string[]; 77 | } 78 | -------------------------------------------------------------------------------- /packages/network-support/src/utils/auth.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import jwt_decode from 'jwt-decode'; 5 | 6 | export function isTokenExpired(token: string): boolean { 7 | if (!token) return true; 8 | 9 | try { 10 | const { exp }: { exp: number } = jwt_decode(token); 11 | const currentDate = new Date().getTime(); 12 | return exp < currentDate; 13 | } catch { 14 | return true; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/network-support/src/utils/common.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2024 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | export function safeJSONParse(json: string) { 5 | try { 6 | return JSON.parse(json); 7 | } catch (e) { 8 | return undefined; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/network-support/src/utils/hash.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2024 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import md5 from 'crypto-js/md5'; 5 | 6 | export function computeMD5(input: string) { 7 | return md5(input).toString(); 8 | } 9 | -------------------------------------------------------------------------------- /packages/network-support/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2023 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | export * from './logger'; 5 | export * from './query'; 6 | export * from './store'; 7 | export * from './auth'; 8 | export * from './uniqueId'; 9 | export * from './common'; 10 | -------------------------------------------------------------------------------- /packages/network-support/src/utils/logger.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | export interface LogFn { 5 | /* tslint:disable:no-unnecessary-generics */ 6 | (obj: T, msg?: string, ...args: any[]): void; 7 | (obj: unknown, msg?: string, ...args: any[]): void; 8 | (msg: string, ...args: any[]): void; 9 | } 10 | 11 | export type Logger = { 12 | error: LogFn; 13 | warn: LogFn; 14 | info: LogFn; 15 | debug: LogFn; 16 | }; 17 | 18 | export function silentLogger(): Logger { 19 | const logfn = (): void => undefined; 20 | return { 21 | debug: logfn, 22 | info: logfn, 23 | warn: logfn, 24 | error: logfn, 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /packages/network-support/src/utils/query.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import fetch from 'cross-fetch'; 5 | import { ServiceAgreementOrder, FlexPlanOrder, ProjectType } from '../types'; 6 | 7 | let timeout = 10_000; 8 | 9 | export const setFetchTimeout = (newVal: number) => { 10 | timeout = newVal; 11 | }; 12 | 13 | export const timeoutController = () => { 14 | const abort = new AbortController(); 15 | 16 | setTimeout(() => abort.abort(), timeout); 17 | 18 | return abort; 19 | }; 20 | 21 | export const customFetch = ( 22 | input: URL | RequestInfo, 23 | init?: RequestInit | undefined, 24 | overrideFetch?: typeof fetch 25 | ): Promise => { 26 | overrideFetch = overrideFetch ?? fetch; 27 | return overrideFetch(input, { 28 | signal: timeoutController().signal, 29 | ...init, 30 | }); 31 | }; 32 | 33 | export async function POST( 34 | url: string, 35 | body: Record, 36 | headers?: Record 37 | ): Promise { 38 | if (!headers) { 39 | headers = {}; 40 | } 41 | headers['Content-Type'] = 'application/json'; 42 | const res = await customFetch(url, { 43 | body: JSON.stringify(body), 44 | method: 'post', 45 | headers, 46 | }); 47 | if (res.status >= 400) { 48 | throw new Error('Bad response from server'); 49 | } 50 | return res.json(); 51 | } 52 | 53 | export async function GET(url: string): Promise { 54 | const headers = { 'Content-Type': 'application/json' }; 55 | const res = await customFetch(url, { 56 | method: 'get', 57 | headers, 58 | }); 59 | if (res.status >= 400) { 60 | throw new Error('Bad response from server'); 61 | } 62 | return res.json(); 63 | } 64 | 65 | interface OrdersResponse { 66 | agreements: ServiceAgreementOrder[]; 67 | plans: FlexPlanOrder[]; 68 | } 69 | 70 | export async function fetchOrders( 71 | authUrl: string, 72 | projectId: string, 73 | projectType: ProjectType, 74 | apikey?: string 75 | ) { 76 | try { 77 | const ordersURL = new URL(`/orders/${projectType}/${projectId}`, authUrl); 78 | if (apikey) { 79 | ordersURL.searchParams.append('apikey', apikey); 80 | } 81 | return await GET(ordersURL.toString()); 82 | } catch { 83 | return { agreements: [], plans: [] }; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /packages/network-support/src/utils/store.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2023 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { LRUCache as LRU } from 'lru-cache'; 5 | 6 | export interface IStore { 7 | get(key: string): Promise; 8 | set(key: string, value: T): Promise; // ttl in milliseconds 9 | remove(key: string): Promise; 10 | } 11 | 12 | interface Options { 13 | ttl: number; 14 | } 15 | 16 | export class LocalStorageCache implements IStore { 17 | private ttl: number; 18 | 19 | constructor(options: Options) { 20 | this.ttl = options.ttl; 21 | } 22 | 23 | async get(key: string): Promise { 24 | const data = localStorage.getItem(key); 25 | if (!data) return undefined; 26 | 27 | try { 28 | const parsed = JSON.parse(data); 29 | if (parsed.expiry && parsed.expiry < Date.now()) { 30 | localStorage.removeItem(key); 31 | return undefined; 32 | } 33 | 34 | return parsed.value; 35 | } catch { 36 | return undefined; 37 | } 38 | } 39 | 40 | async set(key: string, value: T): Promise { 41 | const data = { 42 | value, 43 | expiry: this.ttl ? Date.now() + this.ttl : undefined, 44 | }; 45 | localStorage.setItem(key, JSON.stringify(data)); 46 | } 47 | 48 | async remove(key: string): Promise { 49 | localStorage.removeItem(key); 50 | } 51 | } 52 | 53 | export class LRUCache implements IStore { 54 | private cache: LRU; 55 | 56 | constructor(options: Options) { 57 | this.cache = new LRU({ max: 1000, ttl: options.ttl }); 58 | } 59 | 60 | async get(key: string): Promise { 61 | return this.cache.get(key); 62 | } 63 | 64 | async set(key: string, value: T, ttl?: number): Promise { 65 | // If ttl is defined, it is passed in milliseconds. 66 | // lru-cache expects ttl in milliseconds as well, so it aligns perfectly. 67 | this.cache.set(key, value, { ttl }); 68 | } 69 | 70 | async remove(key: string): Promise { 71 | this.cache.delete(key); 72 | } 73 | } 74 | 75 | export function createStore(options: Options): IStore { 76 | if (typeof window !== 'undefined' && typeof localStorage !== 'undefined') { 77 | return new LocalStorageCache(options); 78 | } 79 | 80 | return new LRUCache(options); 81 | } 82 | 83 | export function createMemoryStore(options: Options): IStore { 84 | return new LRUCache(options); 85 | } 86 | 87 | export function createLocalStorageStore(options: Options): IStore { 88 | if (typeof window !== 'undefined' && typeof localStorage !== 'undefined') { 89 | return new LocalStorageCache(options); 90 | } 91 | 92 | throw new Error('localstorage is not available.'); 93 | } 94 | -------------------------------------------------------------------------------- /packages/network-support/src/utils/uniqueId.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2023 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | export function generateUniqueId(length = 32) { 5 | return Array.from(Array(length), () => Math.floor(Math.random() * 36).toString(36)).join(''); 6 | } 7 | -------------------------------------------------------------------------------- /packages/network-support/src/utils/version.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2024 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { SemVer } from 'semver'; 5 | 6 | export class Version { 7 | static parse(version: string): SemVer { 8 | return new SemVer(version); 9 | } 10 | 11 | static gte(version1: string, version2: string): boolean { 12 | return new SemVer(version1).compare(version2) >= 0; 13 | } 14 | 15 | static lte(version1: string, version2: string): boolean { 16 | return new SemVer(version1).compare(version2) <= -1; 17 | } 18 | 19 | static lt(version1: string, version2: string): boolean { 20 | return new SemVer(version1).compare(version2) === -1; 21 | } 22 | 23 | static gt(version1: string, version2: string): boolean { 24 | return new SemVer(version1).compare(version2) === 0; 25 | } 26 | 27 | static eq(version1: string, version2: string): boolean { 28 | return new SemVer(version1).compare(version2) === 0; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /packages/network-support/test/fetch.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2023 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { Logger } from '@subql/apollo-links/dist/utils/logger'; 5 | import { createFetch } from '../src/fetch'; 6 | import { OrderManager, ProjectType, ResponseFormat } from '../src'; 7 | 8 | const mockLogger: Logger = { 9 | debug: jest.fn(console.log), 10 | error: jest.fn(console.log), 11 | warn: jest.fn(console.log), 12 | info: jest.fn(console.log), 13 | }; 14 | describe('eth provider', () => { 15 | it('can send rpc without network option', async () => { 16 | const orderManager = new OrderManager({ 17 | authUrl: 'https://auth.subquery.network', 18 | projectId: 'Qmf6uZkxuNzpcNvnhReXrz1BTzMWgmtkdFQrSNByPytkuk', 19 | projectType: ProjectType.deployment, 20 | logger: mockLogger, 21 | responseFormat: ResponseFormat.Wrapped, 22 | }); 23 | const fetch = createFetch(orderManager, 3, mockLogger); 24 | 25 | for (let i = 0; i < 10; i++) { 26 | const res = await fetch({ 27 | body: JSON.stringify({ jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 }), 28 | headers: { 'Content-Type': 'application/json' }, 29 | method: 'post', 30 | }); 31 | expect(res).toBeTruthy(); 32 | expect(await res.json()).toBeTruthy(); 33 | } 34 | }, 30000); 35 | }); 36 | -------------------------------------------------------------------------------- /packages/network-support/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "target": "es2017", 5 | "sourceMap": true, 6 | "resolveJsonModule": true, 7 | "rootDir": "./src", 8 | "outDir": "./dist" 9 | }, 10 | "include": ["src/**/*"] 11 | } 12 | -------------------------------------------------------------------------------- /packages/react-hooks/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [Unreleased] 9 | 10 | ## [1.1.1] - 2024-02-27 11 | 12 | ## [1.1.0] - 2024-02-21 13 | 14 | ## [1.0.0] - 2024-01-23 15 | 16 | ## [0.114.0] - 2024-01-23 17 | 18 | ## [0.112.0] - 2023-12-19 19 | 20 | Upgrade sdk 21 | 22 | ## [0.111.0] - 2023-12-15 23 | 24 | Upgrade sdk 25 | 26 | ## [0.100.2] - 2023-11-24 27 | 28 | ## [0.100.0] - 2023-11-01 29 | 30 | ## [0.3.15] - 2023-07-21 31 | 32 | ## [0.3.11] - 2023-07-04 33 | 34 | ## [0.3.9] - 2023-06-29 35 | 36 | ## [0.3.8] - 2023-06-29 37 | 38 | ## [0.3.7] - 2023-06-21 39 | 40 | ## [0.3.6] - 2023-06-21 41 | 42 | Add `leaderboard`. 43 | 44 | ## [0.3.4] - 2023-06-15 45 | 46 | ### Changed 47 | 48 | - Upgrade Contract SDK to `v0.100.2` (#215) 49 | 50 | ### Added 51 | 52 | - Release first version 53 | 54 | [unreleased]: https://github.com/subquery/network-clients/compare/v1.1.1...HEAD 55 | [1.1.1]: https://github.com/subquery/network-clients/compare/v1.1.0...v1.1.1 56 | [1.1.0]: https://github.com/subquery/network-clients/compare/v1.0.0...v1.1.0 57 | [1.0.0]: https://github.com/subquery/network-clients/compare/v0.114.0...v1.0.0 58 | [0.114.0]: https://github.com/subquery/network-clients/compare/v0.112.0...v0.114.0 59 | [0.112.0]: https://github.com/subquery/network-clients/compare/v0.111.0...v0.112.0 60 | [0.111.0]: https://github.com/subquery/network-clients/compare/v0.100.2...v0.111.0 61 | [0.100.2]: https://github.com/subquery/network-clients/compare/v0.100.0...v0.100.2 62 | [0.100.0]: https://github.com/subquery/network-clients/compare/v0.3.15...v0.100.0 63 | [0.3.15]: https://github.com/subquery/network-clients/compare/v0.3.13...v0.3.15 64 | [0.3.13]: https://github.com/subquery/network-clients/compare/v0.3.11...v0.3.13 65 | [0.3.11]: https://github.com/subquery/network-clients/compare/v0.3.9...v0.3.11 66 | [0.3.9]: https://github.com/subquery/network-clients/compare/v0.3.7...v0.3.9 67 | [0.3.7]: https://github.com/subquery/network-clients/compare/v0.3.4...v0.3.7 68 | [0.3.4]: https://github.com/subquery/network-clients/compare/v0.2.0...v0.3.4 69 | -------------------------------------------------------------------------------- /packages/react-hooks/README.md: -------------------------------------------------------------------------------- 1 | # @subql/react-hooks 2 | 3 | ## Description 4 | 5 | React Hooks Client, which exports various useful hooks. 6 | 7 | This package will generate React useQuery hooks by using the queries and types from the @subql/network-query package. 8 | 9 | ## Usage 10 | 11 | - To see generated hooks run `yarn codegen-gql` or `yarn build` from root of monorepo. 12 | 13 | - If you need a useQuery hook that isn't avaliable in `src/__hooks__` follow instructions in @subql/network-query README.md to add queries which this package can use to generate hooks. 14 | 15 | ## Example 16 | 17 | - Note: full examples on how to use all hooks are included in the generated files under `src/__hooks__` directory. 18 | 19 | ```TS 20 | import { useGetDeploymentIndexersQuery } from '@subql/react-hooks'; 21 | const { data, loading, error } = useGetDeploymentIndexersQuery({ 22 | variables: { 23 | offset: // value for 'offset ' 24 | deploymentId: // value for 'deploymentId' 25 | }, 26 | }); 27 | ``` 28 | 29 | ## ChangeLogs 30 | 31 | [CHANGELOG.md](./CHANGELOG.md) 32 | -------------------------------------------------------------------------------- /packages/react-hooks/leaderboard.codegen.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { CodegenConfig } from '@graphql-codegen/cli'; 5 | import { NETWORK_CONFIGS } from '@subql/network-config'; 6 | 7 | const config: CodegenConfig = { 8 | schema: NETWORK_CONFIGS.mainnet.gql.leaderboard, 9 | documents: '../network-query/queries/leaderboard/*.gql', 10 | config: { 11 | preResolveTypes: true, 12 | namingConvention: 'keep', 13 | avoidOptionals: true, 14 | nonOptionalTypename: true, 15 | skipTypeNameForRoot: true, 16 | immutableTypes: true, 17 | scalars: { 18 | Date: 'Date', 19 | Datetime: 'Date', 20 | BigFloat: 'bigint' || 'string', 21 | BigInt: 'bigint', 22 | Cursor: 'string', 23 | }, 24 | }, 25 | generates: { 26 | 'src/': { 27 | preset: 'near-operation-file', 28 | presetConfig: { 29 | folder: '../../../react-hooks/src/__hooks__/leaderboard', // defines a folder, (Relative to the source files) where the generated files will be created 30 | extensions: '.generated.ts', 31 | baseTypesPath: 'graphql', 32 | importTypesNamespace: 'Graphql', 33 | }, 34 | config: { 35 | importOperationTypesFrom: 'Graphql', 36 | }, 37 | plugins: ['typescript-react-apollo'], 38 | }, 39 | }, 40 | }; 41 | 42 | export default config; 43 | -------------------------------------------------------------------------------- /packages/react-hooks/network.codegen.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { CodegenConfig } from '@graphql-codegen/cli'; 5 | import { NETWORK_CONFIGS } from '@subql/network-config'; 6 | 7 | const config: CodegenConfig = { 8 | schema: NETWORK_CONFIGS.mainnet.gql.network, 9 | documents: '../network-query/queries/network/*.gql', 10 | config: { 11 | preResolveTypes: true, 12 | namingConvention: 'keep', 13 | avoidOptionals: true, 14 | nonOptionalTypename: true, 15 | skipTypeNameForRoot: true, 16 | immutableTypes: true, 17 | scalars: { 18 | Date: 'Date', 19 | Datetime: 'Date', 20 | BigFloat: 'bigint' || 'string', 21 | BigInt: 'bigint', 22 | Cursor: 'string', 23 | }, 24 | }, 25 | generates: { 26 | 'src/': { 27 | preset: 'near-operation-file', 28 | presetConfig: { 29 | folder: '../../../react-hooks/src/__hooks__/network', // defines a folder, (Relative to the source files) where the generated files will be created 30 | extensions: '.generated.ts', 31 | baseTypesPath: 'graphql', 32 | importTypesNamespace: 'Graphql', 33 | }, 34 | config: { 35 | importOperationTypesFrom: 'Graphql', 36 | }, 37 | plugins: ['typescript-react-apollo'], 38 | }, 39 | }, 40 | }; 41 | 42 | export default config; 43 | -------------------------------------------------------------------------------- /packages/react-hooks/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@subql/react-hooks", 3 | "version": "1.1.2-10", 4 | "description": "SubQuery client sdk for react hooks", 5 | "main": "dist/index.js", 6 | "author": "SubQuery Pte Limited", 7 | "license": "Apache-2.0", 8 | "scripts": { 9 | "codegen-gql": "sh ./scripts/codegen.sh", 10 | "build": "yarn codegen-gql && tsc -b" 11 | }, 12 | "dependencies": { 13 | "@graphql-tools/code-file-loader": "^7.3.6", 14 | "@graphql-tools/graphql-tag-pluck": "^7.3.6", 15 | "@graphql-tools/load": "^7.7.7", 16 | "@subql/network-query": "workspace:*", 17 | "ahooks": "^3.7.8", 18 | "bignumber.js": "^9.1.2", 19 | "class-transformer": "^0.5.1", 20 | "class-validator": "^0.14.0", 21 | "ethereum-checksum-address": "^0.0.8" 22 | }, 23 | "devDependencies": { 24 | "@graphql-codegen/cli": "^2.13.1", 25 | "@graphql-codegen/introspection": "^2.2.1", 26 | "@graphql-codegen/near-operation-file-preset": "^2.4.1", 27 | "@graphql-codegen/typescript": "^2.7.3", 28 | "@graphql-codegen/typescript-operations": "^2.5.3", 29 | "@graphql-codegen/typescript-react-apollo": "^3.3.3", 30 | "@subql/network-config": "workspace:*", 31 | "@types/ethereum-checksum-address": "^0.0.0", 32 | "create-ts-index": "^1.14.0", 33 | "ctix": "^1.5.4", 34 | "prettier": "^2.7.1", 35 | "typescript": "^4.6.4" 36 | }, 37 | "peerDependencies": { 38 | "@subql/contract-sdk": "^1.0.3", 39 | "graphql": "^16.5.0", 40 | "react": "^18" 41 | }, 42 | "stableVersion": "1.1.2-9" 43 | } 44 | -------------------------------------------------------------------------------- /packages/react-hooks/scripts/codegen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | # network 5 | graphql-codegen --require dotenv/config --config network.codegen.ts 6 | 7 | # leaderboard 8 | graphql-codegen --require dotenv/config --config leaderboard.codegen.ts 9 | 10 | yarn prettier --write . 11 | 12 | # creating export files 13 | yarn ctix create --startAt ./src/__hooks__ --overwrite --noBackup -------------------------------------------------------------------------------- /packages/react-hooks/src/graphql.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //includes graphql types and queries 5 | export * from '@subql/network-query'; 6 | -------------------------------------------------------------------------------- /packages/react-hooks/src/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | export * from './useAsyncMemo'; 5 | export * from './renderAsync'; 6 | export * from './types'; 7 | export * from './__hooks__'; 8 | export * from './useStableCoin'; 9 | export * from './utils'; 10 | -------------------------------------------------------------------------------- /packages/react-hooks/src/renderAsync.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { AsyncData } from './types'; 5 | import { Handlers, HandlersArray, RenderResult } from './utils'; 6 | 7 | export function renderAsync(data: AsyncData, handlers: Handlers): RenderResult { 8 | if (data.error) { 9 | return handlers.error(data.error); 10 | } else if (data.loading) { 11 | return handlers.loading(); 12 | } else if (data.data !== undefined) { 13 | try { 14 | return handlers.data(data.data, data); 15 | } catch (e) { 16 | // TODO not sure this is desired behaviour 17 | return handlers.error(e as Error); 18 | } 19 | } 20 | 21 | return null; 22 | } 23 | 24 | export function renderAsyncArray( 25 | data: AsyncData, 26 | handlers: HandlersArray 27 | ): RenderResult { 28 | if (data.error) { 29 | return handlers.error(data.error); 30 | } else if (data.loading) { 31 | return handlers.loading(); 32 | } 33 | if (data.data !== undefined) { 34 | try { 35 | if (data.data === null || (Array.isArray(data.data) && !data.data.length)) { 36 | return handlers.empty(); 37 | } 38 | return handlers.data(data.data, data); 39 | } catch (e) { 40 | // TODO not sure this is desired behaviour 41 | return handlers.error(e as Error); 42 | } 43 | } 44 | 45 | return null; 46 | } 47 | -------------------------------------------------------------------------------- /packages/react-hooks/src/types.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | /** 5 | * Shared types 6 | */ 7 | export type AsyncData = Readonly<{ data?: T; loading: boolean; error?: Error }>; 8 | -------------------------------------------------------------------------------- /packages/react-hooks/src/useAsyncMemo.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { DependencyList, useEffect, useState, useCallback } from 'react'; 5 | import { AsyncData } from '.'; 6 | 7 | export interface AsyncMemoReturn extends AsyncData { 8 | refetch: (retainCurrent?: boolean) => void; 9 | } 10 | 11 | export function useAsyncMemo( 12 | factory: () => Promise | undefined | null, 13 | deps: DependencyList, 14 | initial: T | undefined = undefined 15 | ): AsyncMemoReturn { 16 | const [result, setResult] = useState>({ data: initial, loading: false }); 17 | 18 | useEffect(() => { 19 | const promise = factory(); 20 | if (promise === undefined || promise === null) return; 21 | 22 | let isSubscribed = true; 23 | setResult({ loading: true }); 24 | 25 | promise 26 | .then((data) => isSubscribed && setResult({ data, loading: false })) 27 | .catch((error) => isSubscribed && setResult({ error, loading: false })); 28 | 29 | return () => { 30 | isSubscribed = false; 31 | }; 32 | }, deps); 33 | 34 | const refetch = useCallback( 35 | async (retainCurrent?: boolean) => { 36 | const promise = factory(); 37 | if (promise === undefined || promise === null) return; 38 | setResult((current) => ({ loading: true, data: retainCurrent ? current.data : undefined })); 39 | 40 | promise 41 | .then((data) => setResult({ data, loading: false })) 42 | .catch((error) => setResult({ error, loading: false })); 43 | }, 44 | [factory] 45 | ); 46 | 47 | return { 48 | ...result, 49 | refetch, 50 | }; 51 | } 52 | -------------------------------------------------------------------------------- /packages/react-hooks/src/useStableCoin.tsx: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { useMemo, useState } from 'react'; 5 | import { useInterval } from 'ahooks'; 6 | import BigNumber from 'bignumber.js'; 7 | import dayjs from 'dayjs'; 8 | import { formatUnits } from 'ethers/lib/utils'; 9 | import { ContractSDK } from '@subql/contract-sdk/sdk'; 10 | import { 11 | SQNetworks, 12 | STABLE_COIN_ADDRESSES, 13 | STABLE_COIN_DECIMAL, 14 | STABLE_COIN_SYMBOLS, 15 | TOKEN_SYMBOLS, 16 | } from '@subql/network-config'; 17 | import { toChecksumAddress } from 'ethereum-checksum-address'; 18 | 19 | import { formatEther, formatSQT } from './utils'; 20 | 21 | export const useStableCoin = (contracts: ContractSDK | undefined, network: SQNetworks) => { 22 | const [rates, setRates] = useState({ 23 | usdcToSqt: 0, 24 | sqtToUsdc: 0, 25 | }); 26 | const { STABLE_COIN_ADDRESS, STABLE_TOKEN, TOKEN } = useMemo( 27 | () => ({ 28 | STABLE_COIN_ADDRESS: STABLE_COIN_ADDRESSES[network], 29 | STABLE_TOKEN: STABLE_COIN_SYMBOLS[network], 30 | TOKEN: TOKEN_SYMBOLS[network], 31 | }), 32 | [network] 33 | ); 34 | const [now, setNow] = useState(); 35 | const coinsAddressDict = useMemo<{ [key: string]: 'USDC' | 'SQT' }>(() => { 36 | if (!contracts?.sqToken) 37 | return { 38 | [toChecksumAddress(STABLE_COIN_ADDRESS)]: STABLE_TOKEN, 39 | }; 40 | return { 41 | [toChecksumAddress(STABLE_COIN_ADDRESS)]: STABLE_TOKEN, 42 | [toChecksumAddress(contracts.sqToken.address)]: TOKEN, 43 | }; 44 | }, [contracts]); 45 | 46 | const getPriceOracle = async () => { 47 | if (!contracts) return; 48 | const assetPrice = await contracts.priceOracle.convertPrice( 49 | toChecksumAddress(STABLE_COIN_ADDRESS), 50 | toChecksumAddress(contracts.sqToken.address), 51 | 10 ** STABLE_COIN_DECIMAL 52 | ); 53 | 54 | const oneUsdcToOneSqt = +formatEther(assetPrice.toString()); 55 | 56 | setRates({ 57 | usdcToSqt: BigNumber(oneUsdcToOneSqt).decimalPlaces(2).toNumber(), 58 | sqtToUsdc: BigNumber(1 / oneUsdcToOneSqt) 59 | .decimalPlaces(2) 60 | .toNumber(), 61 | }); 62 | }; 63 | 64 | const transPrice = (fromAddress: string | undefined, price: string | number | bigint) => { 65 | if (!contracts?.sqToken.address || !fromAddress) 66 | return { 67 | usdcPrice: '0', 68 | sqtPrice: '0', 69 | }; 70 | 71 | try { 72 | const isSQT = 73 | toChecksumAddress(fromAddress) === toChecksumAddress(contracts?.sqToken.address); 74 | const isUSDC = toChecksumAddress(fromAddress) === toChecksumAddress(STABLE_COIN_ADDRESS); 75 | 76 | if (!isSQT && !isUSDC) { 77 | return { 78 | usdcPrice: '0', 79 | sqtPrice: '0', 80 | }; 81 | } 82 | const sortedPrice = isSQT 83 | ? formatSQT(price.toString()) 84 | : formatUnits(price, STABLE_COIN_DECIMAL); 85 | 86 | const resultCalc = BigNumber(sortedPrice).multipliedBy( 87 | isSQT ? rates.sqtToUsdc : rates.usdcToSqt 88 | ); 89 | return { 90 | usdcPrice: (isSQT ? resultCalc.toFixed() : sortedPrice).toString(), 91 | sqtPrice: (isSQT ? sortedPrice : resultCalc.toFixed()).toString(), 92 | }; 93 | } catch (e) { 94 | console.error(e); 95 | return { 96 | usdcPrice: '0', 97 | sqtPrice: '0', 98 | }; 99 | } 100 | }; 101 | 102 | const pricePreview = (fromAddress: string | undefined, price: string | number | bigint) => { 103 | if (!contracts?.sqToken.address || !fromAddress) return Error: address is invalid; 104 | 105 | try { 106 | const sqtTokenAddress = toChecksumAddress(contracts?.sqToken.address); 107 | const prices = transPrice(toChecksumAddress(fromAddress), price); 108 | 109 | if (sqtTokenAddress === toChecksumAddress(fromAddress)) { 110 | return ( 111 | 120 | {prices.sqtPrice} {TOKEN} 121 | 122 | ); 123 | } 124 | 125 | return ( 126 | 135 | {prices.usdcPrice} {STABLE_TOKEN}

136 | 145 | = {prices.sqtPrice} {TOKEN} | {now?.format('HH:mm:ss A')} 146 | 147 |
148 | ); 149 | } catch (e) { 150 | console.error(e); 151 | return Error: address is invalid; 152 | } 153 | }; 154 | 155 | useInterval( 156 | async () => { 157 | await getPriceOracle(); 158 | setNow(dayjs()); 159 | }, 160 | 30000, 161 | { 162 | immediate: true, 163 | } 164 | ); 165 | 166 | return { 167 | coinsAddressDict, 168 | rates, 169 | fetchedTime: now, 170 | pricePreview, 171 | transPrice, 172 | }; 173 | }; 174 | -------------------------------------------------------------------------------- /packages/react-hooks/src/utils.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { AsyncData } from './types'; 5 | import BigNumberJs from 'bignumber.js'; 6 | import { SQT_DECIMAL } from '@subql/network-config'; 7 | import { BigNumberish, BigNumber, utils } from 'ethers'; 8 | import { ReactElement } from 'react'; 9 | 10 | export function mergeAsync( 11 | v1: AsyncData, 12 | v2: AsyncData, 13 | v3?: AsyncData, 14 | v4?: AsyncData 15 | ): AsyncData<[T1 | undefined, T2 | undefined, T3 | undefined, T4 | undefined]> { 16 | return { 17 | loading: v1.loading || v2.loading || !!v3?.loading || !!v4?.loading, 18 | error: v1.error || v2.error || v3?.error || v4?.error, 19 | data: [v1.data, v2.data, v3?.data, v4?.data], 20 | }; 21 | } 22 | 23 | export function mergeAsyncLast(v1: AsyncData, v2: AsyncData): AsyncData { 24 | return { 25 | loading: v1.loading || v2.loading, 26 | error: v1.error || v2.error, 27 | data: v2.data, 28 | }; 29 | } 30 | 31 | export function mapAsync(scope: (t: T) => O, data: AsyncData): AsyncData { 32 | return { ...data, data: data.data ? scope(data.data) : undefined }; 33 | } 34 | 35 | export type RenderResult = ReactElement | React.ReactNode | null; 36 | 37 | export type Handlers = { 38 | loading: () => RenderResult; 39 | error: (error: Error) => RenderResult; 40 | data: (data: T, asyncData: AsyncData) => RenderResult; 41 | }; 42 | 43 | export type HandlersArray = { 44 | loading: () => RenderResult; 45 | error: (error: Error) => RenderResult; 46 | data: (data: T, asyncData: AsyncData) => RenderResult; 47 | empty: () => RenderResult; 48 | }; 49 | 50 | export const formatSQT = (val: string | bigint) => { 51 | const transVal = typeof val === 'bigint' ? val.toString() : val; 52 | return BigNumberJs(transVal) 53 | .div(10 ** SQT_DECIMAL) 54 | .toString(); 55 | }; 56 | 57 | export function truncFormatEtherStr(value: string, decimalPlaces = 4): string { 58 | const [wholeNumberStr, decimalPlacesStr] = value.split('.'); 59 | if (!decimalPlacesStr) return wholeNumberStr; 60 | 61 | const subStrLength = 62 | decimalPlacesStr.length > decimalPlaces ? decimalPlaces : decimalPlacesStr.length; 63 | const sortedDecimalPlaceStr = decimalPlacesStr.substring(0, subStrLength); 64 | return wholeNumberStr.concat('.', sortedDecimalPlaceStr); 65 | } 66 | 67 | export function formatEther(value: BigNumberish | bigint | undefined, toFixed?: number): string { 68 | const formattedEther = utils.formatEther(BigNumber.from(value ?? 0).toString()); 69 | return toFixed ? truncFormatEtherStr(formattedEther, toFixed) : formattedEther; 70 | } 71 | -------------------------------------------------------------------------------- /packages/react-hooks/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "target": "es2017", 5 | "sourceMap": true, 6 | "rootDir": "./src", 7 | "outDir": "./dist", 8 | "jsx": "react-jsx" 9 | }, 10 | "include": ["src/**/*"], 11 | "exclude": ["**/*spec.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /test/jest-setup.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zikc2023/network-clients/e8cc36aa249735ba82a783f8ef7e6af165d6b986/test/jest-setup.ts -------------------------------------------------------------------------------- /test/networkClient.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2022 SubQuery Pte Ltd authors & contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { SQNetworks } from '../packages/network-config/src'; 5 | import { NetworkClient } from '../packages/network-clients/src'; 6 | 7 | const TEST_INDEXER = '0xCef192586b70e3Fc2FAD76Dd1D77983a30d38D04'; 8 | 9 | describe('network client', () => { 10 | let client: NetworkClient; 11 | beforeAll(() => { 12 | client = NetworkClient.create(SQNetworks.TESTNET); 13 | }); 14 | 15 | it('can get indexer detail', async () => { 16 | const indexer = await client.getIndexer(TEST_INDEXER); 17 | expect(indexer?.metadata).toBeTruthy(); 18 | }); 19 | 20 | it('can get indexer metadata', async () => { 21 | const metadata = await client.getIndexerMetadata(TEST_INDEXER); 22 | expect(metadata?.name).toBeTruthy(); 23 | expect(metadata?.url).toBeTruthy(); 24 | }); 25 | 26 | it('can get delegating value', async () => { 27 | const delegating = await client.getDelegating(TEST_INDEXER); 28 | expect(delegating).toBeTruthy(); 29 | }); 30 | 31 | it('can get maxUnstakeAmount value', async () => { 32 | const amount = await client.maxUnstakeAmount(TEST_INDEXER); 33 | expect(amount).toBeTruthy(); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /test/react-hooks.test.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @jest-environment jsdom 3 | */ 4 | /* eslint-disable header/header */ 5 | // Copyright 2020-2023 SubQuery Pte Ltd authors & contributors 6 | // SPDX-License-Identifier: Apache-2.0 7 | 8 | import { act, render, screen } from '@testing-library/react'; 9 | import { useStableCoin } from '../packages/react-hooks/src'; 10 | import { ContractSDK } from '@subql/contract-sdk'; 11 | import { SQNetworks, STABLE_COIN_ADDRESSES, STABLE_COIN_DECIMAL } from '@subql/network-config/src'; 12 | import { BigNumber } from 'ethers'; 13 | import { useEffect } from 'react'; 14 | 15 | test('useStableCoin should work', async () => { 16 | let calledTimes = 0; 17 | const contracts = { 18 | sqToken: { 19 | address: '0xed3bb617dbC128095f8b0A00B9498C2Ef5c3D04a', 20 | }, 21 | priceOracle: { 22 | convertPrice: async (fromAddress, toAddress, decimal) => { 23 | calledTimes = 1; 24 | expect(fromAddress).toEqual(STABLE_COIN_ADDRESSES[SQNetworks.TESTNET]); 25 | expect(toAddress).toEqual('0xed3bb617dbC128095f8b0A00B9498C2Ef5c3D04a'); 26 | expect(decimal).toEqual(10 ** STABLE_COIN_DECIMAL); 27 | 28 | return BigNumber.from('50000000000000000000'); 29 | }, 30 | }, 31 | } as ContractSDK; 32 | 33 | function Setup() { 34 | const { rates, pricePreview, transPrice } = useStableCoin(contracts, SQNetworks.TESTNET); 35 | 36 | const testRates = () => { 37 | expect(rates.sqtToUsdc).toEqual(0.02); 38 | expect(rates.usdcToSqt).toEqual(50); 39 | 40 | expect( 41 | transPrice('0xed3bb617dbC128095f8b0A00B9498C2Ef5c3D04a', '50000000000000000000').sqtPrice 42 | ).toEqual('50'); 43 | expect( 44 | transPrice('0xed3bb617dbC128095f8b0A00B9498C2Ef5c3D04a', '50000000000000000000').usdcPrice 45 | ).toEqual('1'); 46 | 47 | expect(transPrice(STABLE_COIN_ADDRESSES[SQNetworks.TESTNET], '1000000').sqtPrice).toEqual( 48 | '50' 49 | ); 50 | 51 | expect(transPrice(STABLE_COIN_ADDRESSES[SQNetworks.TESTNET], '1000000').usdcPrice).toEqual( 52 | '1.0' 53 | ); 54 | 55 | expect(transPrice('', '50000000000000000000').sqtPrice).toEqual('0'); 56 | expect(transPrice('0x000', '50000000000000000000').sqtPrice).toEqual('0'); 57 | expect( 58 | transPrice('0x0000000000000000000000000000000000000000', '50000000000000000000').sqtPrice 59 | ).toEqual('0'); 60 | }; 61 | 62 | useEffect(() => { 63 | if (rates.sqtToUsdc !== 0) { 64 | testRates(); 65 | } 66 | }, [rates]); 67 | 68 | return ( 69 |
70 | 71 | {pricePreview('0xed3bb617dbC128095f8b0A00B9498C2Ef5c3D04a', '50000000000000000000')} 72 | 73 | 74 | {pricePreview(STABLE_COIN_ADDRESSES[SQNetworks.TESTNET], '1000000')} 75 |
76 | ); 77 | } 78 | 79 | await act(async () => await render()); 80 | 81 | expect(await screen.getByRole('sqtPrice').textContent?.includes('50')); 82 | expect(await screen.getByRole('usdcPrice').textContent?.includes('1')); 83 | expect(calledTimes).toEqual(1); 84 | }); 85 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 4 | "target": "es2017", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 5 | "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ 6 | "module": "commonjs", /* Specify what module code is generated. */ 7 | "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 8 | "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 9 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */ 10 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 11 | "strict": true, /* Enable all strict type-checking options. */ 12 | "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */ 13 | "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */ 14 | "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 15 | "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */ 16 | "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ 17 | "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */ 18 | "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 19 | "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 20 | "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 21 | "skipLibCheck": true, /* Skip type checking all .d.ts files. */ 22 | "allowSyntheticDefaultImports": true, 23 | "resolveJsonModule": true, 24 | "types": ["node", "jest"], 25 | "jsx": "react-jsx" 26 | 27 | }, 28 | "include": ["packages/**/*","test"], 29 | "exclude": ["**/node_modules/**"] 30 | } 31 | -------------------------------------------------------------------------------- /tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": [ 4 | "**/node_modules/**", 5 | "**/*.spec.ts", 6 | "**/*.test.ts" 7 | ] 8 | } --------------------------------------------------------------------------------