├── .dockerignore
├── .github
└── workflows
│ └── docker-publish.yml
├── .gitignore
├── .kubernetes.prod
└── deployment.yaml
├── .kubernetes
└── deployment.yaml
├── CONTRIBUTING.md
├── Dockerfile
├── LICENSE.md
├── new-readme.md
├── package-lock.json
├── package.json
├── readme.md
├── src
├── artifacts
│ ├── example-contract-alternative.yaml
│ ├── example-contract.yaml
│ └── indexes.yaml
├── dao
│ ├── EventDAOImpl.ts
│ ├── OptimisticContractDAOImpl.ts
│ └── interface
│ │ ├── EventDAO.ts
│ │ └── OptimisticContractDAO.ts
├── helpers
│ ├── ContractRegistrationHelper.ts
│ ├── ContractRegistrationServiceLocalImpl.ts
│ └── ContractRegistrationServiceRemoteImpl.ts
├── indexer.ts
├── models
│ ├── OptimisticContract.ts
│ ├── OptimisticEventDBO.ts
│ └── ReconcilerType.ts
├── queue
│ └── queue.service.ts
└── services
│ ├── ChainServiceImpl.ts
│ ├── EventReconciliationServiceImpl.ts
│ ├── EventServiceImpl.ts
│ ├── IndexManagerImpl.ts
│ ├── OptimisticContractServiceImpl.ts
│ ├── PointToPointIndexerServiceImpl.ts
│ ├── SweepingIndexerServiceImpl.ts
│ └── interfaces
│ ├── ChainService.ts
│ ├── EventReconciliationService.ts
│ ├── EventService.ts
│ ├── IndexManager.ts
│ ├── OptimisticContractService.ts
│ ├── PointToPointIndexerService.ts
│ └── SweepingIndexerService.ts
└── tsconfig.json
/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | npm-debug.log
3 |
--------------------------------------------------------------------------------
/.github/workflows/docker-publish.yml:
--------------------------------------------------------------------------------
1 | name: Build and Push to GHCR
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | tags:
8 | - v*
9 |
10 | env:
11 | IMAGE_NAME: intergalactic_indexer
12 |
13 | jobs:
14 | push:
15 | runs-on: ubuntu-latest
16 | permissions:
17 | packages: write
18 | contents: read
19 |
20 | steps:
21 | - uses: actions/checkout@v2
22 |
23 | - name: Build image
24 | run: docker build . --file Dockerfile --tag $IMAGE_NAME --label "runnumber=${GITHUB_RUN_ID}"
25 |
26 | - name: Log in to registry
27 | # This is where you will update the PAT to GITHUB_TOKEN
28 | run: echo "${{ secrets.CR_PAT }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
29 |
30 | - name: Push image
31 | run: |
32 | IMAGE_ID=ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME
33 | # Change all uppercase to lowercase
34 | IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]')
35 | VERSION=${GITHUB_SHA:0:6}
36 |
37 | echo IMAGE_ID=$IMAGE_ID
38 | echo VERSION=$VERSION
39 | docker tag $IMAGE_NAME $IMAGE_ID:$VERSION
40 | docker push $IMAGE_ID:$VERSION
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dest
3 | .env
4 | .idea
5 | build
6 | .env.test
7 | .kubernetes/secrets/*
8 | .kubernetes.prod/secrets/*
9 | **/.DS_Store
--------------------------------------------------------------------------------
/.kubernetes.prod/deployment.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: indexer
5 | namespace: polynomial-prod
6 | labels:
7 | app: indexer
8 | spec:
9 | replicas: 1
10 | selector:
11 | matchLabels:
12 | app: indexer
13 | template:
14 | metadata:
15 | labels:
16 | app: indexer
17 | spec:
18 | containers:
19 | - name: indexer
20 | image: ghcr.io/polynomial-protocol/intergalactic_indexer:cf542b
21 | resources:
22 | requests:
23 | memory: "300Mi"
24 | cpu: "300m"
25 | limits:
26 | memory: "600Mi"
27 | cpu: "500m"
28 | ports:
29 | - containerPort: 80
30 | env:
31 | - name: MONGO_URI
32 | valueFrom:
33 | secretKeyRef:
34 | name: indexer-env
35 | key: MONGO_URI
36 | - name: APP_NAME
37 | valueFrom:
38 | secretKeyRef:
39 | name: indexer-env
40 | key: APP_NAME
41 | - name: CONTRACTS_RELATIVE_PATH
42 | valueFrom:
43 | secretKeyRef:
44 | name: indexer-env
45 | key: CONTRACTS_RELATIVE_PATH
46 | - name: NETWORK
47 | valueFrom:
48 | secretKeyRef:
49 | name: indexer-env
50 | key: NETWORK
51 | - name: INDEXES_RELATIVE_PATH
52 | valueFrom:
53 | secretKeyRef:
54 | name: indexer-env
55 | key: INDEXES_RELATIVE_PATH
56 | - name: DB_NAME
57 | valueFrom:
58 | secretKeyRef:
59 | name: indexer-env
60 | key: DB_NAME
61 | - name: ALCHEMY_API_KEY_FOR_INDEXER
62 | valueFrom:
63 | secretKeyRef:
64 | name: indexer-env
65 | key: ALCHEMY_API_KEY_FOR_INDEXER
66 | - name: ALCHEMY_API_KEY_FOR_RECONCILIATION
67 | valueFrom:
68 | secretKeyRef:
69 | name: indexer-env
70 | key: ALCHEMY_API_KEY_FOR_RECONCILIATION
71 |
72 | imagePullSecrets:
73 | - name: ghcr-secret
--------------------------------------------------------------------------------
/.kubernetes/deployment.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: indexer
5 | namespace: polynomial
6 | labels:
7 | app: indexer
8 | spec:
9 | replicas: 1
10 | selector:
11 | matchLabels:
12 | app: indexer
13 | template:
14 | metadata:
15 | labels:
16 | app: indexer
17 | spec:
18 | containers:
19 | - name: indexer
20 | image: ghcr.io/polynomial-protocol/intergalactic_indexer:fb03d4
21 | resources:
22 | requests:
23 | memory: "300Mi"
24 | cpu: "300m"
25 | limits:
26 | memory: "600Mi"
27 | cpu: "500m"
28 | ports:
29 | - containerPort: 80
30 | env:
31 | - name: MONGO_URI
32 | valueFrom:
33 | secretKeyRef:
34 | name: indexer-env
35 | key: MONGO_URI
36 | - name: APP_NAME
37 | valueFrom:
38 | secretKeyRef:
39 | name: indexer-env
40 | key: APP_NAME
41 | - name: CONTRACTS_RELATIVE_PATH
42 | valueFrom:
43 | secretKeyRef:
44 | name: indexer-env
45 | key: CONTRACTS_RELATIVE_PATH
46 | - name: NETWORK
47 | valueFrom:
48 | secretKeyRef:
49 | name: indexer-env
50 | key: NETWORK
51 | - name: INDEXES_RELATIVE_PATH
52 | valueFrom:
53 | secretKeyRef:
54 | name: indexer-env
55 | key: INDEXES_RELATIVE_PATH
56 | - name: DB_NAME
57 | valueFrom:
58 | secretKeyRef:
59 | name: indexer-env
60 | key: DB_NAME
61 | - name: ALCHEMY_API_KEY_FOR_INDEXER
62 | valueFrom:
63 | secretKeyRef:
64 | name: indexer-env
65 | key: ALCHEMY_API_KEY_FOR_INDEXER
66 | - name: ALCHEMY_API_KEY_FOR_RECONCILIATION
67 | valueFrom:
68 | secretKeyRef:
69 | name: indexer-env
70 | key: ALCHEMY_API_KEY_FOR_RECONCILIATION
71 |
72 | imagePullSecrets:
73 | - name: ghcr-secret
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ## Contributing to Optimistic Indexer
2 |
3 | Thanks for your interest in improving Optimistic Indexer!
4 |
5 | There are multiple opportunities to contribute at any level. It doesn't matter if you are just getting started with Typescrit or are the most weathered expert, we can use your help.
6 |
7 | **No contribution is too small and all contributions are valued.**
8 |
9 | This document will help you get started. **Do not let the document intimidate you**.
10 | It should be considered as a guide to help you navigate the process.
11 |
12 | The [Polynomial Discord](https://discord.com/invite/polynomial) is available for any concerns you may have that are not covered in this guide.
13 |
14 | If you contribute to this project, your contributions will be made to the project under the MIT license.
15 |
16 | ### Code of Conduct
17 |
18 | The Optimistic Indexer project adheres to the [Typescript Code of Conduct](https://github.com/microsoft/TypeScript/blob/main/CODE_OF_CONDUCT.md). This code of conduct describes the _minimum_ behavior expected from all contributors.
19 |
20 | Instances of violations of the Code of Conduct can be reported by contacting the team at [Polynomial Protocol](https://twitter.com/PolynomialFi).
21 |
22 | ### Ways to contribute
23 |
24 | There are fundamentally three ways an individual can contribute:
25 |
26 | 1. **By opening an issue:** For example, if you believe that you have uncovered a bug
27 | in Optimistic Indexer or see a way to improve it further, creating a new issue in the issue tracker is the way to get started.
28 | 2. **By adding context:** Providing additional context to existing issues,
29 | such as screenshots and code snippets to help resolve issues.
30 | 3. **By resolving issues:** Typically this is done in the form of either
31 | demonstrating that the issue reported is not a problem after all, or more often,
32 | by opening a pull request that fixes the underlying problem, in a concrete and
33 | reviewable manner.
34 |
35 | **Anybody can participate in any stage of contribution**. We urge you to participate in the discussion around bugs and participate in reviewing PRs.
36 |
37 | ### Asking for help
38 |
39 | If you have reviewed existing documentation and still have questions, or you are having problems, you can get help by **opening a discussion**. This repository comes with a discussions board where you can also ask for help. Click the "Discussions" tab at the top.
40 |
41 | ### Submitting a bug report
42 |
43 | When filing a new bug report in the issue tracker, you will be presented with a basic form to fill out.
44 |
45 | If you believe that you have uncovered a bug, please fill out the form to the best of your ability. Do not worry if you cannot answer every detail, just fill in what you can. Contributors will ask follow-up questions if something is unclear.
46 |
47 | In order to rule out the possibility of the bug being in your project, the code snippets should be as minimal as possible. It is better if you can reproduce the bug with a small snippet as opposed to an entire project!
48 |
49 | See [this guide][mcve] on how to create a minimal, complete, and verifiable example.
50 |
51 | ### Submitting a feature request
52 |
53 | When adding a feature request in the issue tracker, you will be presented with a basic form to fill out.
54 |
55 | Please include as detailed of an explanation as possible of the feature you would like, adding additional context if necessary.
56 |
57 | If you have examples of other tools that have the feature you are requesting, please include them as well.
58 |
59 | ### Resolving an issue
60 |
61 | Pull requests are the way concrete changes are made to the code, documentation, and dependencies of Optimistic Indexer.
62 |
63 | Even tiny pull requests, like fixing wording, are greatly appreciated. Before making a large change, it is usually a good idea to first open an issue describing the change to solicit feedback and guidance. This will increase the likelihood of the PR getting merged.
64 |
65 | #### Commits
66 |
67 | It is a recommended best practice to keep your changes as logically grouped as possible within individual commits. There is no limit to the number of commits any single pull request may have, and many contributors find it easier to review changes that are split across multiple commits.
68 |
69 | That said, if you have a number of commits that are "checkpoints" and don't represent a single logical change, please squash those together.
70 |
71 | #### Opening the pull request
72 |
73 | From within GitHub, opening a new pull request will present you with a template that should be filled out. Please try your best at filling out the details, but feel free to skip parts if you're not sure what to put.
74 |
75 | #### Reviewing pull requests
76 |
77 | **Any Optimistic Indexer community member is welcome to review any pull request**.
78 |
79 | All contributors who choose to review and provide feedback on pull requests have a responsibility to both the project and individual making the contribution. Reviews and feedback must be helpful, insightful, and geared towards improving the contribution as opposed to simply blocking it. If there are reasons why you feel the PR should not be merged, explain what those are. Do not expect to be able to block a PR from advancing simply because you say "no" without giving an explanation. Be open to having your mind changed. Be open to working _with_ the contributor to make the pull request better.
80 |
81 | Reviews that are dismissive or disrespectful of the contributor or any other reviewers are strictly counter to the Code of Conduct.
82 |
83 | When reviewing a pull request, the primary goals are for the codebase to improve and for the person submitting the request to succeed. **Even if a pull request is not merged, the submitter should come away from the experience feeling like their effort was not unappreciated**. Every PR from a new contributor is an opportunity to grow the community.
84 |
85 | ##### Be aware of the person behind the code
86 |
87 | Be aware that _how_ you communicate requests and reviews in your feedback can have a significant impact on the success of the pull request. Yes, we may merge a particular change that makes Optimistic Indexer better, but the individual might just not want to have anything to do with Optimistic Indexer ever again. The goal is not just having good code.
88 |
89 | ##### Abandoned or stale pull requests
90 |
91 | If a pull request appears to be abandoned or stalled, it is polite to first check with the contributor to see if they intend to continue the work before checking if they would mind if you took it over (especially if it just has nits left). When doing so, it is courteous to give the original contributor credit for the work they started, either by preserving their name and e-mail address in the commit log, or by using the `Author: ` or `Co-authored-by: ` metadata tag in the commits.
92 |
93 | _Adapted from the [Foundry contributing guide][foundry-contributing]_.
94 |
95 | [foundry-contributing]: https://github.com/foundry-rs/foundry/blob/master/CONTRIBUTING.md
96 | [mcve]: https://stackoverflow.com/help/mcve
97 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:16-alpine3.14
2 | WORKDIR /usr/intergalactic-indexer
3 | COPY package*.json ./
4 | RUN npm install
5 | COPY . ./
6 | RUN npm run build
7 | RUN mkdir -p build/artifacts
8 | COPY src/artifacts/* build/artifacts/
9 | CMD [ "npm", "start" ]
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Optimistic Indexer contributors
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/new-readme.md:
--------------------------------------------------------------------------------
1 | # why an indexer is needed - it’s importance
2 |
3 | An indexer is critical for building the backend (APIs) for an application that runs on the blockchain. This is because
4 | blockchains (e.g.- all EVM chains like Ethereum, Optimism, etc.) emits events in the transaction receipts of each block
5 | mined which contains necessary information about the state change that happened due to the transactions inside the
6 | block.
7 |
8 | e.g. If we submit a transaction to transfer an NFT, the block in which the transaction gets mined emits an event with
9 | the following structure:
10 |
11 | Transfer(address from, address to, uint256 tokenId)
12 |
13 | This event contains information like the sender, receiver, and the id of the token transferred. This information is
14 | useful for any application that wants to take some action for any token transfer for the NFT contract.
15 |
16 | # Limitations of the current indexer
17 |
18 | 1. It only supports Optimism chain for now.
19 | 2. Ordering of events is not guaranteed. This is because it uses websockets to listen for current events and a
20 | reconciliation loop to index events that were missed (due to downtime or disconnected websockets or any other reason)
21 | 3. The current indexer is not optimized for performance. It is a single-threaded application that reads events from
22 | the chain and saves them into the database. This is not scalable for a large number of events.
23 |
24 | # examples of applications in a chain that would benefit the most from an indexer
25 |
26 | Almost all applications that have a smart contract deployed on a blockchain use one of the 2 approaches to index events.
27 | a. Use a decentralised indexer like Graph to index events of the smart contract
28 | b. Run an in-house indexer to index events
29 |
30 | Application that use the second approach will benefit the most from this indexer.
31 |
32 | # how an open sourced model will help all the developers on-chain in their dev process
33 |
34 | An open-source indexer will save significant development time spent in writing an indexer from scratch.
35 |
36 | # if dev using anything other than kubernetes - changes to do
37 |
38 | It has a Dockerfile that can be used to build and run the indexer in any environment which supports containers.
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "intergalatic-indexer",
3 | "version": "1.0.0",
4 | "lockfileVersion": 2,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "intergalatic-indexer",
9 | "version": "1.0.0",
10 | "license": "MIT",
11 | "dependencies": {
12 | "dotenv": "^16.0.0",
13 | "ethers": "^5.5.4",
14 | "js-yaml": "^4.1.0",
15 | "kafkajs": "^1.16.0",
16 | "mongodb": "^4.3.1",
17 | "node-cron": "^3.0.0",
18 | "prettier": "^2.7.1"
19 | },
20 | "devDependencies": {
21 | "ts-node": "^10.4.0",
22 | "typescript": "^4.5.5"
23 | }
24 | },
25 | "node_modules/@cspotcode/source-map-consumer": {
26 | "version": "0.8.0",
27 | "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz",
28 | "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==",
29 | "dev": true,
30 | "engines": {
31 | "node": ">= 12"
32 | }
33 | },
34 | "node_modules/@cspotcode/source-map-support": {
35 | "version": "0.7.0",
36 | "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz",
37 | "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==",
38 | "dev": true,
39 | "dependencies": {
40 | "@cspotcode/source-map-consumer": "0.8.0"
41 | },
42 | "engines": {
43 | "node": ">=12"
44 | }
45 | },
46 | "node_modules/@ethersproject/abi": {
47 | "version": "5.5.0",
48 | "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.5.0.tgz",
49 | "integrity": "sha512-loW7I4AohP5KycATvc0MgujU6JyCHPqHdeoo9z3Nr9xEiNioxa65ccdm1+fsoJhkuhdRtfcL8cfyGamz2AxZ5w==",
50 | "funding": [
51 | {
52 | "type": "individual",
53 | "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
54 | },
55 | {
56 | "type": "individual",
57 | "url": "https://www.buymeacoffee.com/ricmoo"
58 | }
59 | ],
60 | "dependencies": {
61 | "@ethersproject/address": "^5.5.0",
62 | "@ethersproject/bignumber": "^5.5.0",
63 | "@ethersproject/bytes": "^5.5.0",
64 | "@ethersproject/constants": "^5.5.0",
65 | "@ethersproject/hash": "^5.5.0",
66 | "@ethersproject/keccak256": "^5.5.0",
67 | "@ethersproject/logger": "^5.5.0",
68 | "@ethersproject/properties": "^5.5.0",
69 | "@ethersproject/strings": "^5.5.0"
70 | }
71 | },
72 | "node_modules/@ethersproject/abstract-provider": {
73 | "version": "5.5.1",
74 | "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.5.1.tgz",
75 | "integrity": "sha512-m+MA/ful6eKbxpr99xUYeRvLkfnlqzrF8SZ46d/xFB1A7ZVknYc/sXJG0RcufF52Qn2jeFj1hhcoQ7IXjNKUqg==",
76 | "funding": [
77 | {
78 | "type": "individual",
79 | "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
80 | },
81 | {
82 | "type": "individual",
83 | "url": "https://www.buymeacoffee.com/ricmoo"
84 | }
85 | ],
86 | "dependencies": {
87 | "@ethersproject/bignumber": "^5.5.0",
88 | "@ethersproject/bytes": "^5.5.0",
89 | "@ethersproject/logger": "^5.5.0",
90 | "@ethersproject/networks": "^5.5.0",
91 | "@ethersproject/properties": "^5.5.0",
92 | "@ethersproject/transactions": "^5.5.0",
93 | "@ethersproject/web": "^5.5.0"
94 | }
95 | },
96 | "node_modules/@ethersproject/abstract-signer": {
97 | "version": "5.5.0",
98 | "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.5.0.tgz",
99 | "integrity": "sha512-lj//7r250MXVLKI7sVarXAbZXbv9P50lgmJQGr2/is82EwEb8r7HrxsmMqAjTsztMYy7ohrIhGMIml+Gx4D3mA==",
100 | "funding": [
101 | {
102 | "type": "individual",
103 | "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
104 | },
105 | {
106 | "type": "individual",
107 | "url": "https://www.buymeacoffee.com/ricmoo"
108 | }
109 | ],
110 | "dependencies": {
111 | "@ethersproject/abstract-provider": "^5.5.0",
112 | "@ethersproject/bignumber": "^5.5.0",
113 | "@ethersproject/bytes": "^5.5.0",
114 | "@ethersproject/logger": "^5.5.0",
115 | "@ethersproject/properties": "^5.5.0"
116 | }
117 | },
118 | "node_modules/@ethersproject/address": {
119 | "version": "5.5.0",
120 | "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.5.0.tgz",
121 | "integrity": "sha512-l4Nj0eWlTUh6ro5IbPTgbpT4wRbdH5l8CQf7icF7sb/SI3Nhd9Y9HzhonTSTi6CefI0necIw7LJqQPopPLZyWw==",
122 | "funding": [
123 | {
124 | "type": "individual",
125 | "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
126 | },
127 | {
128 | "type": "individual",
129 | "url": "https://www.buymeacoffee.com/ricmoo"
130 | }
131 | ],
132 | "dependencies": {
133 | "@ethersproject/bignumber": "^5.5.0",
134 | "@ethersproject/bytes": "^5.5.0",
135 | "@ethersproject/keccak256": "^5.5.0",
136 | "@ethersproject/logger": "^5.5.0",
137 | "@ethersproject/rlp": "^5.5.0"
138 | }
139 | },
140 | "node_modules/@ethersproject/base64": {
141 | "version": "5.5.0",
142 | "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.5.0.tgz",
143 | "integrity": "sha512-tdayUKhU1ljrlHzEWbStXazDpsx4eg1dBXUSI6+mHlYklOXoXF6lZvw8tnD6oVaWfnMxAgRSKROg3cVKtCcppA==",
144 | "funding": [
145 | {
146 | "type": "individual",
147 | "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
148 | },
149 | {
150 | "type": "individual",
151 | "url": "https://www.buymeacoffee.com/ricmoo"
152 | }
153 | ],
154 | "dependencies": {
155 | "@ethersproject/bytes": "^5.5.0"
156 | }
157 | },
158 | "node_modules/@ethersproject/basex": {
159 | "version": "5.5.0",
160 | "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.5.0.tgz",
161 | "integrity": "sha512-ZIodwhHpVJ0Y3hUCfUucmxKsWQA5TMnavp5j/UOuDdzZWzJlRmuOjcTMIGgHCYuZmHt36BfiSyQPSRskPxbfaQ==",
162 | "funding": [
163 | {
164 | "type": "individual",
165 | "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
166 | },
167 | {
168 | "type": "individual",
169 | "url": "https://www.buymeacoffee.com/ricmoo"
170 | }
171 | ],
172 | "dependencies": {
173 | "@ethersproject/bytes": "^5.5.0",
174 | "@ethersproject/properties": "^5.5.0"
175 | }
176 | },
177 | "node_modules/@ethersproject/bignumber": {
178 | "version": "5.5.0",
179 | "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.5.0.tgz",
180 | "integrity": "sha512-6Xytlwvy6Rn3U3gKEc1vP7nR92frHkv6wtVr95LFR3jREXiCPzdWxKQ1cx4JGQBXxcguAwjA8murlYN2TSiEbg==",
181 | "funding": [
182 | {
183 | "type": "individual",
184 | "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
185 | },
186 | {
187 | "type": "individual",
188 | "url": "https://www.buymeacoffee.com/ricmoo"
189 | }
190 | ],
191 | "dependencies": {
192 | "@ethersproject/bytes": "^5.5.0",
193 | "@ethersproject/logger": "^5.5.0",
194 | "bn.js": "^4.11.9"
195 | }
196 | },
197 | "node_modules/@ethersproject/bytes": {
198 | "version": "5.5.0",
199 | "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.5.0.tgz",
200 | "integrity": "sha512-ABvc7BHWhZU9PNM/tANm/Qx4ostPGadAuQzWTr3doklZOhDlmcBqclrQe/ZXUIj3K8wC28oYeuRa+A37tX9kog==",
201 | "funding": [
202 | {
203 | "type": "individual",
204 | "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
205 | },
206 | {
207 | "type": "individual",
208 | "url": "https://www.buymeacoffee.com/ricmoo"
209 | }
210 | ],
211 | "dependencies": {
212 | "@ethersproject/logger": "^5.5.0"
213 | }
214 | },
215 | "node_modules/@ethersproject/constants": {
216 | "version": "5.5.0",
217 | "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.5.0.tgz",
218 | "integrity": "sha512-2MsRRVChkvMWR+GyMGY4N1sAX9Mt3J9KykCsgUFd/1mwS0UH1qw+Bv9k1UJb3X3YJYFco9H20pjSlOIfCG5HYQ==",
219 | "funding": [
220 | {
221 | "type": "individual",
222 | "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
223 | },
224 | {
225 | "type": "individual",
226 | "url": "https://www.buymeacoffee.com/ricmoo"
227 | }
228 | ],
229 | "dependencies": {
230 | "@ethersproject/bignumber": "^5.5.0"
231 | }
232 | },
233 | "node_modules/@ethersproject/contracts": {
234 | "version": "5.5.0",
235 | "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.5.0.tgz",
236 | "integrity": "sha512-2viY7NzyvJkh+Ug17v7g3/IJC8HqZBDcOjYARZLdzRxrfGlRgmYgl6xPRKVbEzy1dWKw/iv7chDcS83pg6cLxg==",
237 | "funding": [
238 | {
239 | "type": "individual",
240 | "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
241 | },
242 | {
243 | "type": "individual",
244 | "url": "https://www.buymeacoffee.com/ricmoo"
245 | }
246 | ],
247 | "dependencies": {
248 | "@ethersproject/abi": "^5.5.0",
249 | "@ethersproject/abstract-provider": "^5.5.0",
250 | "@ethersproject/abstract-signer": "^5.5.0",
251 | "@ethersproject/address": "^5.5.0",
252 | "@ethersproject/bignumber": "^5.5.0",
253 | "@ethersproject/bytes": "^5.5.0",
254 | "@ethersproject/constants": "^5.5.0",
255 | "@ethersproject/logger": "^5.5.0",
256 | "@ethersproject/properties": "^5.5.0",
257 | "@ethersproject/transactions": "^5.5.0"
258 | }
259 | },
260 | "node_modules/@ethersproject/hash": {
261 | "version": "5.5.0",
262 | "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.5.0.tgz",
263 | "integrity": "sha512-dnGVpK1WtBjmnp3mUT0PlU2MpapnwWI0PibldQEq1408tQBAbZpPidkWoVVuNMOl/lISO3+4hXZWCL3YV7qzfg==",
264 | "funding": [
265 | {
266 | "type": "individual",
267 | "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
268 | },
269 | {
270 | "type": "individual",
271 | "url": "https://www.buymeacoffee.com/ricmoo"
272 | }
273 | ],
274 | "dependencies": {
275 | "@ethersproject/abstract-signer": "^5.5.0",
276 | "@ethersproject/address": "^5.5.0",
277 | "@ethersproject/bignumber": "^5.5.0",
278 | "@ethersproject/bytes": "^5.5.0",
279 | "@ethersproject/keccak256": "^5.5.0",
280 | "@ethersproject/logger": "^5.5.0",
281 | "@ethersproject/properties": "^5.5.0",
282 | "@ethersproject/strings": "^5.5.0"
283 | }
284 | },
285 | "node_modules/@ethersproject/hdnode": {
286 | "version": "5.5.0",
287 | "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.5.0.tgz",
288 | "integrity": "sha512-mcSOo9zeUg1L0CoJH7zmxwUG5ggQHU1UrRf8jyTYy6HxdZV+r0PBoL1bxr+JHIPXRzS6u/UW4mEn43y0tmyF8Q==",
289 | "funding": [
290 | {
291 | "type": "individual",
292 | "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
293 | },
294 | {
295 | "type": "individual",
296 | "url": "https://www.buymeacoffee.com/ricmoo"
297 | }
298 | ],
299 | "dependencies": {
300 | "@ethersproject/abstract-signer": "^5.5.0",
301 | "@ethersproject/basex": "^5.5.0",
302 | "@ethersproject/bignumber": "^5.5.0",
303 | "@ethersproject/bytes": "^5.5.0",
304 | "@ethersproject/logger": "^5.5.0",
305 | "@ethersproject/pbkdf2": "^5.5.0",
306 | "@ethersproject/properties": "^5.5.0",
307 | "@ethersproject/sha2": "^5.5.0",
308 | "@ethersproject/signing-key": "^5.5.0",
309 | "@ethersproject/strings": "^5.5.0",
310 | "@ethersproject/transactions": "^5.5.0",
311 | "@ethersproject/wordlists": "^5.5.0"
312 | }
313 | },
314 | "node_modules/@ethersproject/json-wallets": {
315 | "version": "5.5.0",
316 | "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.5.0.tgz",
317 | "integrity": "sha512-9lA21XQnCdcS72xlBn1jfQdj2A1VUxZzOzi9UkNdnokNKke/9Ya2xA9aIK1SC3PQyBDLt4C+dfps7ULpkvKikQ==",
318 | "funding": [
319 | {
320 | "type": "individual",
321 | "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
322 | },
323 | {
324 | "type": "individual",
325 | "url": "https://www.buymeacoffee.com/ricmoo"
326 | }
327 | ],
328 | "dependencies": {
329 | "@ethersproject/abstract-signer": "^5.5.0",
330 | "@ethersproject/address": "^5.5.0",
331 | "@ethersproject/bytes": "^5.5.0",
332 | "@ethersproject/hdnode": "^5.5.0",
333 | "@ethersproject/keccak256": "^5.5.0",
334 | "@ethersproject/logger": "^5.5.0",
335 | "@ethersproject/pbkdf2": "^5.5.0",
336 | "@ethersproject/properties": "^5.5.0",
337 | "@ethersproject/random": "^5.5.0",
338 | "@ethersproject/strings": "^5.5.0",
339 | "@ethersproject/transactions": "^5.5.0",
340 | "aes-js": "3.0.0",
341 | "scrypt-js": "3.0.1"
342 | }
343 | },
344 | "node_modules/@ethersproject/keccak256": {
345 | "version": "5.5.0",
346 | "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.5.0.tgz",
347 | "integrity": "sha512-5VoFCTjo2rYbBe1l2f4mccaRFN/4VQEYFwwn04aJV2h7qf4ZvI2wFxUE1XOX+snbwCLRzIeikOqtAoPwMza9kg==",
348 | "funding": [
349 | {
350 | "type": "individual",
351 | "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
352 | },
353 | {
354 | "type": "individual",
355 | "url": "https://www.buymeacoffee.com/ricmoo"
356 | }
357 | ],
358 | "dependencies": {
359 | "@ethersproject/bytes": "^5.5.0",
360 | "js-sha3": "0.8.0"
361 | }
362 | },
363 | "node_modules/@ethersproject/logger": {
364 | "version": "5.5.0",
365 | "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.5.0.tgz",
366 | "integrity": "sha512-rIY/6WPm7T8n3qS2vuHTUBPdXHl+rGxWxW5okDfo9J4Z0+gRRZT0msvUdIJkE4/HS29GUMziwGaaKO2bWONBrg==",
367 | "funding": [
368 | {
369 | "type": "individual",
370 | "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
371 | },
372 | {
373 | "type": "individual",
374 | "url": "https://www.buymeacoffee.com/ricmoo"
375 | }
376 | ]
377 | },
378 | "node_modules/@ethersproject/networks": {
379 | "version": "5.5.2",
380 | "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.5.2.tgz",
381 | "integrity": "sha512-NEqPxbGBfy6O3x4ZTISb90SjEDkWYDUbEeIFhJly0F7sZjoQMnj5KYzMSkMkLKZ+1fGpx00EDpHQCy6PrDupkQ==",
382 | "funding": [
383 | {
384 | "type": "individual",
385 | "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
386 | },
387 | {
388 | "type": "individual",
389 | "url": "https://www.buymeacoffee.com/ricmoo"
390 | }
391 | ],
392 | "dependencies": {
393 | "@ethersproject/logger": "^5.5.0"
394 | }
395 | },
396 | "node_modules/@ethersproject/pbkdf2": {
397 | "version": "5.5.0",
398 | "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.5.0.tgz",
399 | "integrity": "sha512-SaDvQFvXPnz1QGpzr6/HToLifftSXGoXrbpZ6BvoZhmx4bNLHrxDe8MZisuecyOziP1aVEwzC2Hasj+86TgWVg==",
400 | "funding": [
401 | {
402 | "type": "individual",
403 | "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
404 | },
405 | {
406 | "type": "individual",
407 | "url": "https://www.buymeacoffee.com/ricmoo"
408 | }
409 | ],
410 | "dependencies": {
411 | "@ethersproject/bytes": "^5.5.0",
412 | "@ethersproject/sha2": "^5.5.0"
413 | }
414 | },
415 | "node_modules/@ethersproject/properties": {
416 | "version": "5.5.0",
417 | "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.5.0.tgz",
418 | "integrity": "sha512-l3zRQg3JkD8EL3CPjNK5g7kMx4qSwiR60/uk5IVjd3oq1MZR5qUg40CNOoEJoX5wc3DyY5bt9EbMk86C7x0DNA==",
419 | "funding": [
420 | {
421 | "type": "individual",
422 | "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
423 | },
424 | {
425 | "type": "individual",
426 | "url": "https://www.buymeacoffee.com/ricmoo"
427 | }
428 | ],
429 | "dependencies": {
430 | "@ethersproject/logger": "^5.5.0"
431 | }
432 | },
433 | "node_modules/@ethersproject/providers": {
434 | "version": "5.5.3",
435 | "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.5.3.tgz",
436 | "integrity": "sha512-ZHXxXXXWHuwCQKrgdpIkbzMNJMvs+9YWemanwp1fA7XZEv7QlilseysPvQe0D7Q7DlkJX/w/bGA1MdgK2TbGvA==",
437 | "funding": [
438 | {
439 | "type": "individual",
440 | "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
441 | },
442 | {
443 | "type": "individual",
444 | "url": "https://www.buymeacoffee.com/ricmoo"
445 | }
446 | ],
447 | "dependencies": {
448 | "@ethersproject/abstract-provider": "^5.5.0",
449 | "@ethersproject/abstract-signer": "^5.5.0",
450 | "@ethersproject/address": "^5.5.0",
451 | "@ethersproject/basex": "^5.5.0",
452 | "@ethersproject/bignumber": "^5.5.0",
453 | "@ethersproject/bytes": "^5.5.0",
454 | "@ethersproject/constants": "^5.5.0",
455 | "@ethersproject/hash": "^5.5.0",
456 | "@ethersproject/logger": "^5.5.0",
457 | "@ethersproject/networks": "^5.5.0",
458 | "@ethersproject/properties": "^5.5.0",
459 | "@ethersproject/random": "^5.5.0",
460 | "@ethersproject/rlp": "^5.5.0",
461 | "@ethersproject/sha2": "^5.5.0",
462 | "@ethersproject/strings": "^5.5.0",
463 | "@ethersproject/transactions": "^5.5.0",
464 | "@ethersproject/web": "^5.5.0",
465 | "bech32": "1.1.4",
466 | "ws": "7.4.6"
467 | }
468 | },
469 | "node_modules/@ethersproject/random": {
470 | "version": "5.5.1",
471 | "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.5.1.tgz",
472 | "integrity": "sha512-YaU2dQ7DuhL5Au7KbcQLHxcRHfgyNgvFV4sQOo0HrtW3Zkrc9ctWNz8wXQ4uCSfSDsqX2vcjhroxU5RQRV0nqA==",
473 | "funding": [
474 | {
475 | "type": "individual",
476 | "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
477 | },
478 | {
479 | "type": "individual",
480 | "url": "https://www.buymeacoffee.com/ricmoo"
481 | }
482 | ],
483 | "dependencies": {
484 | "@ethersproject/bytes": "^5.5.0",
485 | "@ethersproject/logger": "^5.5.0"
486 | }
487 | },
488 | "node_modules/@ethersproject/rlp": {
489 | "version": "5.5.0",
490 | "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.5.0.tgz",
491 | "integrity": "sha512-hLv8XaQ8PTI9g2RHoQGf/WSxBfTB/NudRacbzdxmst5VHAqd1sMibWG7SENzT5Dj3yZ3kJYx+WiRYEcQTAkcYA==",
492 | "funding": [
493 | {
494 | "type": "individual",
495 | "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
496 | },
497 | {
498 | "type": "individual",
499 | "url": "https://www.buymeacoffee.com/ricmoo"
500 | }
501 | ],
502 | "dependencies": {
503 | "@ethersproject/bytes": "^5.5.0",
504 | "@ethersproject/logger": "^5.5.0"
505 | }
506 | },
507 | "node_modules/@ethersproject/sha2": {
508 | "version": "5.5.0",
509 | "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.5.0.tgz",
510 | "integrity": "sha512-B5UBoglbCiHamRVPLA110J+2uqsifpZaTmid2/7W5rbtYVz6gus6/hSDieIU/6gaKIDcOj12WnOdiymEUHIAOA==",
511 | "funding": [
512 | {
513 | "type": "individual",
514 | "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
515 | },
516 | {
517 | "type": "individual",
518 | "url": "https://www.buymeacoffee.com/ricmoo"
519 | }
520 | ],
521 | "dependencies": {
522 | "@ethersproject/bytes": "^5.5.0",
523 | "@ethersproject/logger": "^5.5.0",
524 | "hash.js": "1.1.7"
525 | }
526 | },
527 | "node_modules/@ethersproject/signing-key": {
528 | "version": "5.5.0",
529 | "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.5.0.tgz",
530 | "integrity": "sha512-5VmseH7qjtNmDdZBswavhotYbWB0bOwKIlOTSlX14rKn5c11QmJwGt4GHeo7NrL/Ycl7uo9AHvEqs5xZgFBTng==",
531 | "funding": [
532 | {
533 | "type": "individual",
534 | "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
535 | },
536 | {
537 | "type": "individual",
538 | "url": "https://www.buymeacoffee.com/ricmoo"
539 | }
540 | ],
541 | "dependencies": {
542 | "@ethersproject/bytes": "^5.5.0",
543 | "@ethersproject/logger": "^5.5.0",
544 | "@ethersproject/properties": "^5.5.0",
545 | "bn.js": "^4.11.9",
546 | "elliptic": "6.5.4",
547 | "hash.js": "1.1.7"
548 | }
549 | },
550 | "node_modules/@ethersproject/solidity": {
551 | "version": "5.5.0",
552 | "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.5.0.tgz",
553 | "integrity": "sha512-9NgZs9LhGMj6aCtHXhtmFQ4AN4sth5HuFXVvAQtzmm0jpSCNOTGtrHZJAeYTh7MBjRR8brylWZxBZR9zDStXbw==",
554 | "funding": [
555 | {
556 | "type": "individual",
557 | "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
558 | },
559 | {
560 | "type": "individual",
561 | "url": "https://www.buymeacoffee.com/ricmoo"
562 | }
563 | ],
564 | "dependencies": {
565 | "@ethersproject/bignumber": "^5.5.0",
566 | "@ethersproject/bytes": "^5.5.0",
567 | "@ethersproject/keccak256": "^5.5.0",
568 | "@ethersproject/logger": "^5.5.0",
569 | "@ethersproject/sha2": "^5.5.0",
570 | "@ethersproject/strings": "^5.5.0"
571 | }
572 | },
573 | "node_modules/@ethersproject/strings": {
574 | "version": "5.5.0",
575 | "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.5.0.tgz",
576 | "integrity": "sha512-9fy3TtF5LrX/wTrBaT8FGE6TDJyVjOvXynXJz5MT5azq+E6D92zuKNx7i29sWW2FjVOaWjAsiZ1ZWznuduTIIQ==",
577 | "funding": [
578 | {
579 | "type": "individual",
580 | "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
581 | },
582 | {
583 | "type": "individual",
584 | "url": "https://www.buymeacoffee.com/ricmoo"
585 | }
586 | ],
587 | "dependencies": {
588 | "@ethersproject/bytes": "^5.5.0",
589 | "@ethersproject/constants": "^5.5.0",
590 | "@ethersproject/logger": "^5.5.0"
591 | }
592 | },
593 | "node_modules/@ethersproject/transactions": {
594 | "version": "5.5.0",
595 | "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.5.0.tgz",
596 | "integrity": "sha512-9RZYSKX26KfzEd/1eqvv8pLauCKzDTub0Ko4LfIgaERvRuwyaNV78mJs7cpIgZaDl6RJui4o49lHwwCM0526zA==",
597 | "funding": [
598 | {
599 | "type": "individual",
600 | "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
601 | },
602 | {
603 | "type": "individual",
604 | "url": "https://www.buymeacoffee.com/ricmoo"
605 | }
606 | ],
607 | "dependencies": {
608 | "@ethersproject/address": "^5.5.0",
609 | "@ethersproject/bignumber": "^5.5.0",
610 | "@ethersproject/bytes": "^5.5.0",
611 | "@ethersproject/constants": "^5.5.0",
612 | "@ethersproject/keccak256": "^5.5.0",
613 | "@ethersproject/logger": "^5.5.0",
614 | "@ethersproject/properties": "^5.5.0",
615 | "@ethersproject/rlp": "^5.5.0",
616 | "@ethersproject/signing-key": "^5.5.0"
617 | }
618 | },
619 | "node_modules/@ethersproject/units": {
620 | "version": "5.5.0",
621 | "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.5.0.tgz",
622 | "integrity": "sha512-7+DpjiZk4v6wrikj+TCyWWa9dXLNU73tSTa7n0TSJDxkYbV3Yf1eRh9ToMLlZtuctNYu9RDNNy2USq3AdqSbag==",
623 | "funding": [
624 | {
625 | "type": "individual",
626 | "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
627 | },
628 | {
629 | "type": "individual",
630 | "url": "https://www.buymeacoffee.com/ricmoo"
631 | }
632 | ],
633 | "dependencies": {
634 | "@ethersproject/bignumber": "^5.5.0",
635 | "@ethersproject/constants": "^5.5.0",
636 | "@ethersproject/logger": "^5.5.0"
637 | }
638 | },
639 | "node_modules/@ethersproject/wallet": {
640 | "version": "5.5.0",
641 | "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.5.0.tgz",
642 | "integrity": "sha512-Mlu13hIctSYaZmUOo7r2PhNSd8eaMPVXe1wxrz4w4FCE4tDYBywDH+bAR1Xz2ADyXGwqYMwstzTrtUVIsKDO0Q==",
643 | "funding": [
644 | {
645 | "type": "individual",
646 | "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
647 | },
648 | {
649 | "type": "individual",
650 | "url": "https://www.buymeacoffee.com/ricmoo"
651 | }
652 | ],
653 | "dependencies": {
654 | "@ethersproject/abstract-provider": "^5.5.0",
655 | "@ethersproject/abstract-signer": "^5.5.0",
656 | "@ethersproject/address": "^5.5.0",
657 | "@ethersproject/bignumber": "^5.5.0",
658 | "@ethersproject/bytes": "^5.5.0",
659 | "@ethersproject/hash": "^5.5.0",
660 | "@ethersproject/hdnode": "^5.5.0",
661 | "@ethersproject/json-wallets": "^5.5.0",
662 | "@ethersproject/keccak256": "^5.5.0",
663 | "@ethersproject/logger": "^5.5.0",
664 | "@ethersproject/properties": "^5.5.0",
665 | "@ethersproject/random": "^5.5.0",
666 | "@ethersproject/signing-key": "^5.5.0",
667 | "@ethersproject/transactions": "^5.5.0",
668 | "@ethersproject/wordlists": "^5.5.0"
669 | }
670 | },
671 | "node_modules/@ethersproject/web": {
672 | "version": "5.5.1",
673 | "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.5.1.tgz",
674 | "integrity": "sha512-olvLvc1CB12sREc1ROPSHTdFCdvMh0J5GSJYiQg2D0hdD4QmJDy8QYDb1CvoqD/bF1c++aeKv2sR5uduuG9dQg==",
675 | "funding": [
676 | {
677 | "type": "individual",
678 | "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
679 | },
680 | {
681 | "type": "individual",
682 | "url": "https://www.buymeacoffee.com/ricmoo"
683 | }
684 | ],
685 | "dependencies": {
686 | "@ethersproject/base64": "^5.5.0",
687 | "@ethersproject/bytes": "^5.5.0",
688 | "@ethersproject/logger": "^5.5.0",
689 | "@ethersproject/properties": "^5.5.0",
690 | "@ethersproject/strings": "^5.5.0"
691 | }
692 | },
693 | "node_modules/@ethersproject/wordlists": {
694 | "version": "5.5.0",
695 | "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.5.0.tgz",
696 | "integrity": "sha512-bL0UTReWDiaQJJYOC9sh/XcRu/9i2jMrzf8VLRmPKx58ckSlOJiohODkECCO50dtLZHcGU6MLXQ4OOrgBwP77Q==",
697 | "funding": [
698 | {
699 | "type": "individual",
700 | "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
701 | },
702 | {
703 | "type": "individual",
704 | "url": "https://www.buymeacoffee.com/ricmoo"
705 | }
706 | ],
707 | "dependencies": {
708 | "@ethersproject/bytes": "^5.5.0",
709 | "@ethersproject/hash": "^5.5.0",
710 | "@ethersproject/logger": "^5.5.0",
711 | "@ethersproject/properties": "^5.5.0",
712 | "@ethersproject/strings": "^5.5.0"
713 | }
714 | },
715 | "node_modules/@tsconfig/node10": {
716 | "version": "1.0.8",
717 | "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz",
718 | "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==",
719 | "dev": true
720 | },
721 | "node_modules/@tsconfig/node12": {
722 | "version": "1.0.9",
723 | "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz",
724 | "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==",
725 | "dev": true
726 | },
727 | "node_modules/@tsconfig/node14": {
728 | "version": "1.0.1",
729 | "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz",
730 | "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==",
731 | "dev": true
732 | },
733 | "node_modules/@tsconfig/node16": {
734 | "version": "1.0.2",
735 | "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz",
736 | "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==",
737 | "dev": true
738 | },
739 | "node_modules/@types/node": {
740 | "version": "17.0.5",
741 | "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.5.tgz",
742 | "integrity": "sha512-w3mrvNXLeDYV1GKTZorGJQivK6XLCoGwpnyJFbJVK/aTBQUxOCaa/GlFAAN3OTDFcb7h5tiFG+YXCO2By+riZw=="
743 | },
744 | "node_modules/@types/webidl-conversions": {
745 | "version": "6.1.1",
746 | "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-6.1.1.tgz",
747 | "integrity": "sha512-XAahCdThVuCFDQLT7R7Pk/vqeObFNL3YqRyFZg+AqAP/W1/w3xHaIxuW7WszQqTbIBOPRcItYJIou3i/mppu3Q=="
748 | },
749 | "node_modules/@types/whatwg-url": {
750 | "version": "8.2.1",
751 | "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.1.tgz",
752 | "integrity": "sha512-2YubE1sjj5ifxievI5Ge1sckb9k/Er66HyR2c+3+I6VDUUg1TLPdYYTEbQ+DjRkS4nTxMJhgWfSfMRD2sl2EYQ==",
753 | "dependencies": {
754 | "@types/node": "*",
755 | "@types/webidl-conversions": "*"
756 | }
757 | },
758 | "node_modules/acorn": {
759 | "version": "8.7.0",
760 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz",
761 | "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==",
762 | "dev": true,
763 | "bin": {
764 | "acorn": "bin/acorn"
765 | },
766 | "engines": {
767 | "node": ">=0.4.0"
768 | }
769 | },
770 | "node_modules/acorn-walk": {
771 | "version": "8.2.0",
772 | "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
773 | "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
774 | "dev": true,
775 | "engines": {
776 | "node": ">=0.4.0"
777 | }
778 | },
779 | "node_modules/aes-js": {
780 | "version": "3.0.0",
781 | "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz",
782 | "integrity": "sha1-4h3xCtbCBTKVvLuNq0Cwnb6ofk0="
783 | },
784 | "node_modules/arg": {
785 | "version": "4.1.3",
786 | "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
787 | "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
788 | "dev": true
789 | },
790 | "node_modules/argparse": {
791 | "version": "2.0.1",
792 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
793 | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
794 | },
795 | "node_modules/base64-js": {
796 | "version": "1.5.1",
797 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
798 | "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
799 | "funding": [
800 | {
801 | "type": "github",
802 | "url": "https://github.com/sponsors/feross"
803 | },
804 | {
805 | "type": "patreon",
806 | "url": "https://www.patreon.com/feross"
807 | },
808 | {
809 | "type": "consulting",
810 | "url": "https://feross.org/support"
811 | }
812 | ]
813 | },
814 | "node_modules/bech32": {
815 | "version": "1.1.4",
816 | "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz",
817 | "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ=="
818 | },
819 | "node_modules/bn.js": {
820 | "version": "4.12.0",
821 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
822 | "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
823 | },
824 | "node_modules/brorand": {
825 | "version": "1.1.0",
826 | "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
827 | "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8="
828 | },
829 | "node_modules/bson": {
830 | "version": "4.6.1",
831 | "resolved": "https://registry.npmjs.org/bson/-/bson-4.6.1.tgz",
832 | "integrity": "sha512-I1LQ7Hz5zgwR4QquilLNZwbhPw0Apx7i7X9kGMBTsqPdml/03Q9NBtD9nt/19ahjlphktQImrnderxqpzeVDjw==",
833 | "dependencies": {
834 | "buffer": "^5.6.0"
835 | },
836 | "engines": {
837 | "node": ">=6.9.0"
838 | }
839 | },
840 | "node_modules/buffer": {
841 | "version": "5.7.1",
842 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
843 | "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
844 | "funding": [
845 | {
846 | "type": "github",
847 | "url": "https://github.com/sponsors/feross"
848 | },
849 | {
850 | "type": "patreon",
851 | "url": "https://www.patreon.com/feross"
852 | },
853 | {
854 | "type": "consulting",
855 | "url": "https://feross.org/support"
856 | }
857 | ],
858 | "dependencies": {
859 | "base64-js": "^1.3.1",
860 | "ieee754": "^1.1.13"
861 | }
862 | },
863 | "node_modules/create-require": {
864 | "version": "1.1.1",
865 | "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
866 | "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
867 | "dev": true
868 | },
869 | "node_modules/denque": {
870 | "version": "2.0.1",
871 | "resolved": "https://registry.npmjs.org/denque/-/denque-2.0.1.tgz",
872 | "integrity": "sha512-tfiWc6BQLXNLpNiR5iGd0Ocu3P3VpxfzFiqubLgMfhfOw9WyvgJBd46CClNn9k3qfbjvT//0cf7AlYRX/OslMQ==",
873 | "engines": {
874 | "node": ">=0.10"
875 | }
876 | },
877 | "node_modules/diff": {
878 | "version": "4.0.2",
879 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
880 | "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
881 | "dev": true,
882 | "engines": {
883 | "node": ">=0.3.1"
884 | }
885 | },
886 | "node_modules/dotenv": {
887 | "version": "16.0.0",
888 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.0.tgz",
889 | "integrity": "sha512-qD9WU0MPM4SWLPJy/r2Be+2WgQj8plChsyrCNQzW/0WjvcJQiKQJ9mH3ZgB3fxbUUxgc/11ZJ0Fi5KiimWGz2Q==",
890 | "engines": {
891 | "node": ">=12"
892 | }
893 | },
894 | "node_modules/elliptic": {
895 | "version": "6.5.4",
896 | "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz",
897 | "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==",
898 | "dependencies": {
899 | "bn.js": "^4.11.9",
900 | "brorand": "^1.1.0",
901 | "hash.js": "^1.0.0",
902 | "hmac-drbg": "^1.0.1",
903 | "inherits": "^2.0.4",
904 | "minimalistic-assert": "^1.0.1",
905 | "minimalistic-crypto-utils": "^1.0.1"
906 | }
907 | },
908 | "node_modules/ethers": {
909 | "version": "5.5.4",
910 | "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.5.4.tgz",
911 | "integrity": "sha512-N9IAXsF8iKhgHIC6pquzRgPBJEzc9auw3JoRkaKe+y4Wl/LFBtDDunNe7YmdomontECAcC5APaAgWZBiu1kirw==",
912 | "funding": [
913 | {
914 | "type": "individual",
915 | "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
916 | },
917 | {
918 | "type": "individual",
919 | "url": "https://www.buymeacoffee.com/ricmoo"
920 | }
921 | ],
922 | "dependencies": {
923 | "@ethersproject/abi": "5.5.0",
924 | "@ethersproject/abstract-provider": "5.5.1",
925 | "@ethersproject/abstract-signer": "5.5.0",
926 | "@ethersproject/address": "5.5.0",
927 | "@ethersproject/base64": "5.5.0",
928 | "@ethersproject/basex": "5.5.0",
929 | "@ethersproject/bignumber": "5.5.0",
930 | "@ethersproject/bytes": "5.5.0",
931 | "@ethersproject/constants": "5.5.0",
932 | "@ethersproject/contracts": "5.5.0",
933 | "@ethersproject/hash": "5.5.0",
934 | "@ethersproject/hdnode": "5.5.0",
935 | "@ethersproject/json-wallets": "5.5.0",
936 | "@ethersproject/keccak256": "5.5.0",
937 | "@ethersproject/logger": "5.5.0",
938 | "@ethersproject/networks": "5.5.2",
939 | "@ethersproject/pbkdf2": "5.5.0",
940 | "@ethersproject/properties": "5.5.0",
941 | "@ethersproject/providers": "5.5.3",
942 | "@ethersproject/random": "5.5.1",
943 | "@ethersproject/rlp": "5.5.0",
944 | "@ethersproject/sha2": "5.5.0",
945 | "@ethersproject/signing-key": "5.5.0",
946 | "@ethersproject/solidity": "5.5.0",
947 | "@ethersproject/strings": "5.5.0",
948 | "@ethersproject/transactions": "5.5.0",
949 | "@ethersproject/units": "5.5.0",
950 | "@ethersproject/wallet": "5.5.0",
951 | "@ethersproject/web": "5.5.1",
952 | "@ethersproject/wordlists": "5.5.0"
953 | }
954 | },
955 | "node_modules/hash.js": {
956 | "version": "1.1.7",
957 | "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
958 | "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
959 | "dependencies": {
960 | "inherits": "^2.0.3",
961 | "minimalistic-assert": "^1.0.1"
962 | }
963 | },
964 | "node_modules/hmac-drbg": {
965 | "version": "1.0.1",
966 | "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
967 | "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=",
968 | "dependencies": {
969 | "hash.js": "^1.0.3",
970 | "minimalistic-assert": "^1.0.0",
971 | "minimalistic-crypto-utils": "^1.0.1"
972 | }
973 | },
974 | "node_modules/ieee754": {
975 | "version": "1.2.1",
976 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
977 | "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
978 | "funding": [
979 | {
980 | "type": "github",
981 | "url": "https://github.com/sponsors/feross"
982 | },
983 | {
984 | "type": "patreon",
985 | "url": "https://www.patreon.com/feross"
986 | },
987 | {
988 | "type": "consulting",
989 | "url": "https://feross.org/support"
990 | }
991 | ]
992 | },
993 | "node_modules/inherits": {
994 | "version": "2.0.4",
995 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
996 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
997 | },
998 | "node_modules/ip": {
999 | "version": "1.1.5",
1000 | "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
1001 | "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo="
1002 | },
1003 | "node_modules/js-sha3": {
1004 | "version": "0.8.0",
1005 | "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz",
1006 | "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q=="
1007 | },
1008 | "node_modules/js-yaml": {
1009 | "version": "4.1.0",
1010 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
1011 | "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
1012 | "dependencies": {
1013 | "argparse": "^2.0.1"
1014 | },
1015 | "bin": {
1016 | "js-yaml": "bin/js-yaml.js"
1017 | }
1018 | },
1019 | "node_modules/kafkajs": {
1020 | "version": "1.16.0",
1021 | "resolved": "https://registry.npmjs.org/kafkajs/-/kafkajs-1.16.0.tgz",
1022 | "integrity": "sha512-+Rcfu2hyQ/jv5skqRY8xA7Ra+mmRkDAzCaLDYbkGtgsNKpzxPWiLbk8ub0dgr4EbWrN1Zb4BCXHUkD6+zYfdWg==",
1023 | "engines": {
1024 | "node": ">=10.13.0"
1025 | }
1026 | },
1027 | "node_modules/make-error": {
1028 | "version": "1.3.6",
1029 | "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
1030 | "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
1031 | "dev": true
1032 | },
1033 | "node_modules/memory-pager": {
1034 | "version": "1.5.0",
1035 | "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz",
1036 | "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==",
1037 | "optional": true
1038 | },
1039 | "node_modules/minimalistic-assert": {
1040 | "version": "1.0.1",
1041 | "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
1042 | "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A=="
1043 | },
1044 | "node_modules/minimalistic-crypto-utils": {
1045 | "version": "1.0.1",
1046 | "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
1047 | "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo="
1048 | },
1049 | "node_modules/moment": {
1050 | "version": "2.29.1",
1051 | "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
1052 | "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==",
1053 | "engines": {
1054 | "node": "*"
1055 | }
1056 | },
1057 | "node_modules/moment-timezone": {
1058 | "version": "0.5.34",
1059 | "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.34.tgz",
1060 | "integrity": "sha512-3zAEHh2hKUs3EXLESx/wsgw6IQdusOT8Bxm3D9UrHPQR7zlMmzwybC8zHEM1tQ4LJwP7fcxrWr8tuBg05fFCbg==",
1061 | "dependencies": {
1062 | "moment": ">= 2.9.0"
1063 | },
1064 | "engines": {
1065 | "node": "*"
1066 | }
1067 | },
1068 | "node_modules/mongodb": {
1069 | "version": "4.3.1",
1070 | "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.3.1.tgz",
1071 | "integrity": "sha512-sNa8APSIk+r4x31ZwctKjuPSaeKuvUeNb/fu/3B6dRM02HpEgig7hTHM8A/PJQTlxuC/KFWlDlQjhsk/S43tBg==",
1072 | "dependencies": {
1073 | "bson": "^4.6.1",
1074 | "denque": "^2.0.1",
1075 | "mongodb-connection-string-url": "^2.4.1",
1076 | "socks": "^2.6.1"
1077 | },
1078 | "engines": {
1079 | "node": ">=12.9.0"
1080 | },
1081 | "optionalDependencies": {
1082 | "saslprep": "^1.0.3"
1083 | }
1084 | },
1085 | "node_modules/mongodb-connection-string-url": {
1086 | "version": "2.4.1",
1087 | "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.4.1.tgz",
1088 | "integrity": "sha512-d5Kd2bVsKcSA7YI/yo57fSTtMwRQdFkvc5IZwod1RRxJtECeWPPSo7zqcUGJELifRA//Igs4spVtYAmvFCatug==",
1089 | "dependencies": {
1090 | "@types/whatwg-url": "^8.2.1",
1091 | "whatwg-url": "^11.0.0"
1092 | }
1093 | },
1094 | "node_modules/node-cron": {
1095 | "version": "3.0.0",
1096 | "resolved": "https://registry.npmjs.org/node-cron/-/node-cron-3.0.0.tgz",
1097 | "integrity": "sha512-DDwIvvuCwrNiaU7HEivFDULcaQualDv7KoNlB/UU1wPW0n1tDEmBJKhEIE6DlF2FuoOHcNbLJ8ITL2Iv/3AWmA==",
1098 | "dependencies": {
1099 | "moment-timezone": "^0.5.31"
1100 | },
1101 | "engines": {
1102 | "node": ">=6.0.0"
1103 | }
1104 | },
1105 | "node_modules/prettier": {
1106 | "version": "2.7.1",
1107 | "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
1108 | "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==",
1109 | "bin": {
1110 | "prettier": "bin-prettier.js"
1111 | },
1112 | "engines": {
1113 | "node": ">=10.13.0"
1114 | },
1115 | "funding": {
1116 | "url": "https://github.com/prettier/prettier?sponsor=1"
1117 | }
1118 | },
1119 | "node_modules/punycode": {
1120 | "version": "2.1.1",
1121 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
1122 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
1123 | "engines": {
1124 | "node": ">=6"
1125 | }
1126 | },
1127 | "node_modules/saslprep": {
1128 | "version": "1.0.3",
1129 | "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz",
1130 | "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==",
1131 | "optional": true,
1132 | "dependencies": {
1133 | "sparse-bitfield": "^3.0.3"
1134 | },
1135 | "engines": {
1136 | "node": ">=6"
1137 | }
1138 | },
1139 | "node_modules/scrypt-js": {
1140 | "version": "3.0.1",
1141 | "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz",
1142 | "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA=="
1143 | },
1144 | "node_modules/smart-buffer": {
1145 | "version": "4.2.0",
1146 | "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
1147 | "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
1148 | "engines": {
1149 | "node": ">= 6.0.0",
1150 | "npm": ">= 3.0.0"
1151 | }
1152 | },
1153 | "node_modules/socks": {
1154 | "version": "2.6.1",
1155 | "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.1.tgz",
1156 | "integrity": "sha512-kLQ9N5ucj8uIcxrDwjm0Jsqk06xdpBjGNQtpXy4Q8/QY2k+fY7nZH8CARy+hkbG+SGAovmzzuauCpBlb8FrnBA==",
1157 | "dependencies": {
1158 | "ip": "^1.1.5",
1159 | "smart-buffer": "^4.1.0"
1160 | },
1161 | "engines": {
1162 | "node": ">= 10.13.0",
1163 | "npm": ">= 3.0.0"
1164 | }
1165 | },
1166 | "node_modules/sparse-bitfield": {
1167 | "version": "3.0.3",
1168 | "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
1169 | "integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=",
1170 | "optional": true,
1171 | "dependencies": {
1172 | "memory-pager": "^1.0.2"
1173 | }
1174 | },
1175 | "node_modules/tr46": {
1176 | "version": "3.0.0",
1177 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz",
1178 | "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==",
1179 | "dependencies": {
1180 | "punycode": "^2.1.1"
1181 | },
1182 | "engines": {
1183 | "node": ">=12"
1184 | }
1185 | },
1186 | "node_modules/ts-node": {
1187 | "version": "10.4.0",
1188 | "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.4.0.tgz",
1189 | "integrity": "sha512-g0FlPvvCXSIO1JDF6S232P5jPYqBkRL9qly81ZgAOSU7rwI0stphCgd2kLiCrU9DjQCrJMWEqcNSjQL02s6d8A==",
1190 | "dev": true,
1191 | "dependencies": {
1192 | "@cspotcode/source-map-support": "0.7.0",
1193 | "@tsconfig/node10": "^1.0.7",
1194 | "@tsconfig/node12": "^1.0.7",
1195 | "@tsconfig/node14": "^1.0.0",
1196 | "@tsconfig/node16": "^1.0.2",
1197 | "acorn": "^8.4.1",
1198 | "acorn-walk": "^8.1.1",
1199 | "arg": "^4.1.0",
1200 | "create-require": "^1.1.0",
1201 | "diff": "^4.0.1",
1202 | "make-error": "^1.1.1",
1203 | "yn": "3.1.1"
1204 | },
1205 | "bin": {
1206 | "ts-node": "dist/bin.js",
1207 | "ts-node-cwd": "dist/bin-cwd.js",
1208 | "ts-node-script": "dist/bin-script.js",
1209 | "ts-node-transpile-only": "dist/bin-transpile.js",
1210 | "ts-script": "dist/bin-script-deprecated.js"
1211 | },
1212 | "peerDependencies": {
1213 | "@swc/core": ">=1.2.50",
1214 | "@swc/wasm": ">=1.2.50",
1215 | "@types/node": "*",
1216 | "typescript": ">=2.7"
1217 | },
1218 | "peerDependenciesMeta": {
1219 | "@swc/core": {
1220 | "optional": true
1221 | },
1222 | "@swc/wasm": {
1223 | "optional": true
1224 | }
1225 | }
1226 | },
1227 | "node_modules/typescript": {
1228 | "version": "4.5.5",
1229 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz",
1230 | "integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==",
1231 | "dev": true,
1232 | "bin": {
1233 | "tsc": "bin/tsc",
1234 | "tsserver": "bin/tsserver"
1235 | },
1236 | "engines": {
1237 | "node": ">=4.2.0"
1238 | }
1239 | },
1240 | "node_modules/webidl-conversions": {
1241 | "version": "7.0.0",
1242 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
1243 | "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
1244 | "engines": {
1245 | "node": ">=12"
1246 | }
1247 | },
1248 | "node_modules/whatwg-url": {
1249 | "version": "11.0.0",
1250 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz",
1251 | "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==",
1252 | "dependencies": {
1253 | "tr46": "^3.0.0",
1254 | "webidl-conversions": "^7.0.0"
1255 | },
1256 | "engines": {
1257 | "node": ">=12"
1258 | }
1259 | },
1260 | "node_modules/ws": {
1261 | "version": "7.4.6",
1262 | "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz",
1263 | "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==",
1264 | "engines": {
1265 | "node": ">=8.3.0"
1266 | },
1267 | "peerDependencies": {
1268 | "bufferutil": "^4.0.1",
1269 | "utf-8-validate": "^5.0.2"
1270 | },
1271 | "peerDependenciesMeta": {
1272 | "bufferutil": {
1273 | "optional": true
1274 | },
1275 | "utf-8-validate": {
1276 | "optional": true
1277 | }
1278 | }
1279 | },
1280 | "node_modules/yn": {
1281 | "version": "3.1.1",
1282 | "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
1283 | "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
1284 | "dev": true,
1285 | "engines": {
1286 | "node": ">=6"
1287 | }
1288 | }
1289 | },
1290 | "dependencies": {
1291 | "@cspotcode/source-map-consumer": {
1292 | "version": "0.8.0",
1293 | "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz",
1294 | "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==",
1295 | "dev": true
1296 | },
1297 | "@cspotcode/source-map-support": {
1298 | "version": "0.7.0",
1299 | "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz",
1300 | "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==",
1301 | "dev": true,
1302 | "requires": {
1303 | "@cspotcode/source-map-consumer": "0.8.0"
1304 | }
1305 | },
1306 | "@ethersproject/abi": {
1307 | "version": "5.5.0",
1308 | "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.5.0.tgz",
1309 | "integrity": "sha512-loW7I4AohP5KycATvc0MgujU6JyCHPqHdeoo9z3Nr9xEiNioxa65ccdm1+fsoJhkuhdRtfcL8cfyGamz2AxZ5w==",
1310 | "requires": {
1311 | "@ethersproject/address": "^5.5.0",
1312 | "@ethersproject/bignumber": "^5.5.0",
1313 | "@ethersproject/bytes": "^5.5.0",
1314 | "@ethersproject/constants": "^5.5.0",
1315 | "@ethersproject/hash": "^5.5.0",
1316 | "@ethersproject/keccak256": "^5.5.0",
1317 | "@ethersproject/logger": "^5.5.0",
1318 | "@ethersproject/properties": "^5.5.0",
1319 | "@ethersproject/strings": "^5.5.0"
1320 | }
1321 | },
1322 | "@ethersproject/abstract-provider": {
1323 | "version": "5.5.1",
1324 | "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.5.1.tgz",
1325 | "integrity": "sha512-m+MA/ful6eKbxpr99xUYeRvLkfnlqzrF8SZ46d/xFB1A7ZVknYc/sXJG0RcufF52Qn2jeFj1hhcoQ7IXjNKUqg==",
1326 | "requires": {
1327 | "@ethersproject/bignumber": "^5.5.0",
1328 | "@ethersproject/bytes": "^5.5.0",
1329 | "@ethersproject/logger": "^5.5.0",
1330 | "@ethersproject/networks": "^5.5.0",
1331 | "@ethersproject/properties": "^5.5.0",
1332 | "@ethersproject/transactions": "^5.5.0",
1333 | "@ethersproject/web": "^5.5.0"
1334 | }
1335 | },
1336 | "@ethersproject/abstract-signer": {
1337 | "version": "5.5.0",
1338 | "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.5.0.tgz",
1339 | "integrity": "sha512-lj//7r250MXVLKI7sVarXAbZXbv9P50lgmJQGr2/is82EwEb8r7HrxsmMqAjTsztMYy7ohrIhGMIml+Gx4D3mA==",
1340 | "requires": {
1341 | "@ethersproject/abstract-provider": "^5.5.0",
1342 | "@ethersproject/bignumber": "^5.5.0",
1343 | "@ethersproject/bytes": "^5.5.0",
1344 | "@ethersproject/logger": "^5.5.0",
1345 | "@ethersproject/properties": "^5.5.0"
1346 | }
1347 | },
1348 | "@ethersproject/address": {
1349 | "version": "5.5.0",
1350 | "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.5.0.tgz",
1351 | "integrity": "sha512-l4Nj0eWlTUh6ro5IbPTgbpT4wRbdH5l8CQf7icF7sb/SI3Nhd9Y9HzhonTSTi6CefI0necIw7LJqQPopPLZyWw==",
1352 | "requires": {
1353 | "@ethersproject/bignumber": "^5.5.0",
1354 | "@ethersproject/bytes": "^5.5.0",
1355 | "@ethersproject/keccak256": "^5.5.0",
1356 | "@ethersproject/logger": "^5.5.0",
1357 | "@ethersproject/rlp": "^5.5.0"
1358 | }
1359 | },
1360 | "@ethersproject/base64": {
1361 | "version": "5.5.0",
1362 | "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.5.0.tgz",
1363 | "integrity": "sha512-tdayUKhU1ljrlHzEWbStXazDpsx4eg1dBXUSI6+mHlYklOXoXF6lZvw8tnD6oVaWfnMxAgRSKROg3cVKtCcppA==",
1364 | "requires": {
1365 | "@ethersproject/bytes": "^5.5.0"
1366 | }
1367 | },
1368 | "@ethersproject/basex": {
1369 | "version": "5.5.0",
1370 | "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.5.0.tgz",
1371 | "integrity": "sha512-ZIodwhHpVJ0Y3hUCfUucmxKsWQA5TMnavp5j/UOuDdzZWzJlRmuOjcTMIGgHCYuZmHt36BfiSyQPSRskPxbfaQ==",
1372 | "requires": {
1373 | "@ethersproject/bytes": "^5.5.0",
1374 | "@ethersproject/properties": "^5.5.0"
1375 | }
1376 | },
1377 | "@ethersproject/bignumber": {
1378 | "version": "5.5.0",
1379 | "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.5.0.tgz",
1380 | "integrity": "sha512-6Xytlwvy6Rn3U3gKEc1vP7nR92frHkv6wtVr95LFR3jREXiCPzdWxKQ1cx4JGQBXxcguAwjA8murlYN2TSiEbg==",
1381 | "requires": {
1382 | "@ethersproject/bytes": "^5.5.0",
1383 | "@ethersproject/logger": "^5.5.0",
1384 | "bn.js": "^4.11.9"
1385 | }
1386 | },
1387 | "@ethersproject/bytes": {
1388 | "version": "5.5.0",
1389 | "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.5.0.tgz",
1390 | "integrity": "sha512-ABvc7BHWhZU9PNM/tANm/Qx4ostPGadAuQzWTr3doklZOhDlmcBqclrQe/ZXUIj3K8wC28oYeuRa+A37tX9kog==",
1391 | "requires": {
1392 | "@ethersproject/logger": "^5.5.0"
1393 | }
1394 | },
1395 | "@ethersproject/constants": {
1396 | "version": "5.5.0",
1397 | "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.5.0.tgz",
1398 | "integrity": "sha512-2MsRRVChkvMWR+GyMGY4N1sAX9Mt3J9KykCsgUFd/1mwS0UH1qw+Bv9k1UJb3X3YJYFco9H20pjSlOIfCG5HYQ==",
1399 | "requires": {
1400 | "@ethersproject/bignumber": "^5.5.0"
1401 | }
1402 | },
1403 | "@ethersproject/contracts": {
1404 | "version": "5.5.0",
1405 | "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.5.0.tgz",
1406 | "integrity": "sha512-2viY7NzyvJkh+Ug17v7g3/IJC8HqZBDcOjYARZLdzRxrfGlRgmYgl6xPRKVbEzy1dWKw/iv7chDcS83pg6cLxg==",
1407 | "requires": {
1408 | "@ethersproject/abi": "^5.5.0",
1409 | "@ethersproject/abstract-provider": "^5.5.0",
1410 | "@ethersproject/abstract-signer": "^5.5.0",
1411 | "@ethersproject/address": "^5.5.0",
1412 | "@ethersproject/bignumber": "^5.5.0",
1413 | "@ethersproject/bytes": "^5.5.0",
1414 | "@ethersproject/constants": "^5.5.0",
1415 | "@ethersproject/logger": "^5.5.0",
1416 | "@ethersproject/properties": "^5.5.0",
1417 | "@ethersproject/transactions": "^5.5.0"
1418 | }
1419 | },
1420 | "@ethersproject/hash": {
1421 | "version": "5.5.0",
1422 | "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.5.0.tgz",
1423 | "integrity": "sha512-dnGVpK1WtBjmnp3mUT0PlU2MpapnwWI0PibldQEq1408tQBAbZpPidkWoVVuNMOl/lISO3+4hXZWCL3YV7qzfg==",
1424 | "requires": {
1425 | "@ethersproject/abstract-signer": "^5.5.0",
1426 | "@ethersproject/address": "^5.5.0",
1427 | "@ethersproject/bignumber": "^5.5.0",
1428 | "@ethersproject/bytes": "^5.5.0",
1429 | "@ethersproject/keccak256": "^5.5.0",
1430 | "@ethersproject/logger": "^5.5.0",
1431 | "@ethersproject/properties": "^5.5.0",
1432 | "@ethersproject/strings": "^5.5.0"
1433 | }
1434 | },
1435 | "@ethersproject/hdnode": {
1436 | "version": "5.5.0",
1437 | "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.5.0.tgz",
1438 | "integrity": "sha512-mcSOo9zeUg1L0CoJH7zmxwUG5ggQHU1UrRf8jyTYy6HxdZV+r0PBoL1bxr+JHIPXRzS6u/UW4mEn43y0tmyF8Q==",
1439 | "requires": {
1440 | "@ethersproject/abstract-signer": "^5.5.0",
1441 | "@ethersproject/basex": "^5.5.0",
1442 | "@ethersproject/bignumber": "^5.5.0",
1443 | "@ethersproject/bytes": "^5.5.0",
1444 | "@ethersproject/logger": "^5.5.0",
1445 | "@ethersproject/pbkdf2": "^5.5.0",
1446 | "@ethersproject/properties": "^5.5.0",
1447 | "@ethersproject/sha2": "^5.5.0",
1448 | "@ethersproject/signing-key": "^5.5.0",
1449 | "@ethersproject/strings": "^5.5.0",
1450 | "@ethersproject/transactions": "^5.5.0",
1451 | "@ethersproject/wordlists": "^5.5.0"
1452 | }
1453 | },
1454 | "@ethersproject/json-wallets": {
1455 | "version": "5.5.0",
1456 | "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.5.0.tgz",
1457 | "integrity": "sha512-9lA21XQnCdcS72xlBn1jfQdj2A1VUxZzOzi9UkNdnokNKke/9Ya2xA9aIK1SC3PQyBDLt4C+dfps7ULpkvKikQ==",
1458 | "requires": {
1459 | "@ethersproject/abstract-signer": "^5.5.0",
1460 | "@ethersproject/address": "^5.5.0",
1461 | "@ethersproject/bytes": "^5.5.0",
1462 | "@ethersproject/hdnode": "^5.5.0",
1463 | "@ethersproject/keccak256": "^5.5.0",
1464 | "@ethersproject/logger": "^5.5.0",
1465 | "@ethersproject/pbkdf2": "^5.5.0",
1466 | "@ethersproject/properties": "^5.5.0",
1467 | "@ethersproject/random": "^5.5.0",
1468 | "@ethersproject/strings": "^5.5.0",
1469 | "@ethersproject/transactions": "^5.5.0",
1470 | "aes-js": "3.0.0",
1471 | "scrypt-js": "3.0.1"
1472 | }
1473 | },
1474 | "@ethersproject/keccak256": {
1475 | "version": "5.5.0",
1476 | "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.5.0.tgz",
1477 | "integrity": "sha512-5VoFCTjo2rYbBe1l2f4mccaRFN/4VQEYFwwn04aJV2h7qf4ZvI2wFxUE1XOX+snbwCLRzIeikOqtAoPwMza9kg==",
1478 | "requires": {
1479 | "@ethersproject/bytes": "^5.5.0",
1480 | "js-sha3": "0.8.0"
1481 | }
1482 | },
1483 | "@ethersproject/logger": {
1484 | "version": "5.5.0",
1485 | "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.5.0.tgz",
1486 | "integrity": "sha512-rIY/6WPm7T8n3qS2vuHTUBPdXHl+rGxWxW5okDfo9J4Z0+gRRZT0msvUdIJkE4/HS29GUMziwGaaKO2bWONBrg=="
1487 | },
1488 | "@ethersproject/networks": {
1489 | "version": "5.5.2",
1490 | "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.5.2.tgz",
1491 | "integrity": "sha512-NEqPxbGBfy6O3x4ZTISb90SjEDkWYDUbEeIFhJly0F7sZjoQMnj5KYzMSkMkLKZ+1fGpx00EDpHQCy6PrDupkQ==",
1492 | "requires": {
1493 | "@ethersproject/logger": "^5.5.0"
1494 | }
1495 | },
1496 | "@ethersproject/pbkdf2": {
1497 | "version": "5.5.0",
1498 | "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.5.0.tgz",
1499 | "integrity": "sha512-SaDvQFvXPnz1QGpzr6/HToLifftSXGoXrbpZ6BvoZhmx4bNLHrxDe8MZisuecyOziP1aVEwzC2Hasj+86TgWVg==",
1500 | "requires": {
1501 | "@ethersproject/bytes": "^5.5.0",
1502 | "@ethersproject/sha2": "^5.5.0"
1503 | }
1504 | },
1505 | "@ethersproject/properties": {
1506 | "version": "5.5.0",
1507 | "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.5.0.tgz",
1508 | "integrity": "sha512-l3zRQg3JkD8EL3CPjNK5g7kMx4qSwiR60/uk5IVjd3oq1MZR5qUg40CNOoEJoX5wc3DyY5bt9EbMk86C7x0DNA==",
1509 | "requires": {
1510 | "@ethersproject/logger": "^5.5.0"
1511 | }
1512 | },
1513 | "@ethersproject/providers": {
1514 | "version": "5.5.3",
1515 | "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.5.3.tgz",
1516 | "integrity": "sha512-ZHXxXXXWHuwCQKrgdpIkbzMNJMvs+9YWemanwp1fA7XZEv7QlilseysPvQe0D7Q7DlkJX/w/bGA1MdgK2TbGvA==",
1517 | "requires": {
1518 | "@ethersproject/abstract-provider": "^5.5.0",
1519 | "@ethersproject/abstract-signer": "^5.5.0",
1520 | "@ethersproject/address": "^5.5.0",
1521 | "@ethersproject/basex": "^5.5.0",
1522 | "@ethersproject/bignumber": "^5.5.0",
1523 | "@ethersproject/bytes": "^5.5.0",
1524 | "@ethersproject/constants": "^5.5.0",
1525 | "@ethersproject/hash": "^5.5.0",
1526 | "@ethersproject/logger": "^5.5.0",
1527 | "@ethersproject/networks": "^5.5.0",
1528 | "@ethersproject/properties": "^5.5.0",
1529 | "@ethersproject/random": "^5.5.0",
1530 | "@ethersproject/rlp": "^5.5.0",
1531 | "@ethersproject/sha2": "^5.5.0",
1532 | "@ethersproject/strings": "^5.5.0",
1533 | "@ethersproject/transactions": "^5.5.0",
1534 | "@ethersproject/web": "^5.5.0",
1535 | "bech32": "1.1.4",
1536 | "ws": "7.4.6"
1537 | }
1538 | },
1539 | "@ethersproject/random": {
1540 | "version": "5.5.1",
1541 | "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.5.1.tgz",
1542 | "integrity": "sha512-YaU2dQ7DuhL5Au7KbcQLHxcRHfgyNgvFV4sQOo0HrtW3Zkrc9ctWNz8wXQ4uCSfSDsqX2vcjhroxU5RQRV0nqA==",
1543 | "requires": {
1544 | "@ethersproject/bytes": "^5.5.0",
1545 | "@ethersproject/logger": "^5.5.0"
1546 | }
1547 | },
1548 | "@ethersproject/rlp": {
1549 | "version": "5.5.0",
1550 | "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.5.0.tgz",
1551 | "integrity": "sha512-hLv8XaQ8PTI9g2RHoQGf/WSxBfTB/NudRacbzdxmst5VHAqd1sMibWG7SENzT5Dj3yZ3kJYx+WiRYEcQTAkcYA==",
1552 | "requires": {
1553 | "@ethersproject/bytes": "^5.5.0",
1554 | "@ethersproject/logger": "^5.5.0"
1555 | }
1556 | },
1557 | "@ethersproject/sha2": {
1558 | "version": "5.5.0",
1559 | "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.5.0.tgz",
1560 | "integrity": "sha512-B5UBoglbCiHamRVPLA110J+2uqsifpZaTmid2/7W5rbtYVz6gus6/hSDieIU/6gaKIDcOj12WnOdiymEUHIAOA==",
1561 | "requires": {
1562 | "@ethersproject/bytes": "^5.5.0",
1563 | "@ethersproject/logger": "^5.5.0",
1564 | "hash.js": "1.1.7"
1565 | }
1566 | },
1567 | "@ethersproject/signing-key": {
1568 | "version": "5.5.0",
1569 | "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.5.0.tgz",
1570 | "integrity": "sha512-5VmseH7qjtNmDdZBswavhotYbWB0bOwKIlOTSlX14rKn5c11QmJwGt4GHeo7NrL/Ycl7uo9AHvEqs5xZgFBTng==",
1571 | "requires": {
1572 | "@ethersproject/bytes": "^5.5.0",
1573 | "@ethersproject/logger": "^5.5.0",
1574 | "@ethersproject/properties": "^5.5.0",
1575 | "bn.js": "^4.11.9",
1576 | "elliptic": "6.5.4",
1577 | "hash.js": "1.1.7"
1578 | }
1579 | },
1580 | "@ethersproject/solidity": {
1581 | "version": "5.5.0",
1582 | "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.5.0.tgz",
1583 | "integrity": "sha512-9NgZs9LhGMj6aCtHXhtmFQ4AN4sth5HuFXVvAQtzmm0jpSCNOTGtrHZJAeYTh7MBjRR8brylWZxBZR9zDStXbw==",
1584 | "requires": {
1585 | "@ethersproject/bignumber": "^5.5.0",
1586 | "@ethersproject/bytes": "^5.5.0",
1587 | "@ethersproject/keccak256": "^5.5.0",
1588 | "@ethersproject/logger": "^5.5.0",
1589 | "@ethersproject/sha2": "^5.5.0",
1590 | "@ethersproject/strings": "^5.5.0"
1591 | }
1592 | },
1593 | "@ethersproject/strings": {
1594 | "version": "5.5.0",
1595 | "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.5.0.tgz",
1596 | "integrity": "sha512-9fy3TtF5LrX/wTrBaT8FGE6TDJyVjOvXynXJz5MT5azq+E6D92zuKNx7i29sWW2FjVOaWjAsiZ1ZWznuduTIIQ==",
1597 | "requires": {
1598 | "@ethersproject/bytes": "^5.5.0",
1599 | "@ethersproject/constants": "^5.5.0",
1600 | "@ethersproject/logger": "^5.5.0"
1601 | }
1602 | },
1603 | "@ethersproject/transactions": {
1604 | "version": "5.5.0",
1605 | "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.5.0.tgz",
1606 | "integrity": "sha512-9RZYSKX26KfzEd/1eqvv8pLauCKzDTub0Ko4LfIgaERvRuwyaNV78mJs7cpIgZaDl6RJui4o49lHwwCM0526zA==",
1607 | "requires": {
1608 | "@ethersproject/address": "^5.5.0",
1609 | "@ethersproject/bignumber": "^5.5.0",
1610 | "@ethersproject/bytes": "^5.5.0",
1611 | "@ethersproject/constants": "^5.5.0",
1612 | "@ethersproject/keccak256": "^5.5.0",
1613 | "@ethersproject/logger": "^5.5.0",
1614 | "@ethersproject/properties": "^5.5.0",
1615 | "@ethersproject/rlp": "^5.5.0",
1616 | "@ethersproject/signing-key": "^5.5.0"
1617 | }
1618 | },
1619 | "@ethersproject/units": {
1620 | "version": "5.5.0",
1621 | "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.5.0.tgz",
1622 | "integrity": "sha512-7+DpjiZk4v6wrikj+TCyWWa9dXLNU73tSTa7n0TSJDxkYbV3Yf1eRh9ToMLlZtuctNYu9RDNNy2USq3AdqSbag==",
1623 | "requires": {
1624 | "@ethersproject/bignumber": "^5.5.0",
1625 | "@ethersproject/constants": "^5.5.0",
1626 | "@ethersproject/logger": "^5.5.0"
1627 | }
1628 | },
1629 | "@ethersproject/wallet": {
1630 | "version": "5.5.0",
1631 | "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.5.0.tgz",
1632 | "integrity": "sha512-Mlu13hIctSYaZmUOo7r2PhNSd8eaMPVXe1wxrz4w4FCE4tDYBywDH+bAR1Xz2ADyXGwqYMwstzTrtUVIsKDO0Q==",
1633 | "requires": {
1634 | "@ethersproject/abstract-provider": "^5.5.0",
1635 | "@ethersproject/abstract-signer": "^5.5.0",
1636 | "@ethersproject/address": "^5.5.0",
1637 | "@ethersproject/bignumber": "^5.5.0",
1638 | "@ethersproject/bytes": "^5.5.0",
1639 | "@ethersproject/hash": "^5.5.0",
1640 | "@ethersproject/hdnode": "^5.5.0",
1641 | "@ethersproject/json-wallets": "^5.5.0",
1642 | "@ethersproject/keccak256": "^5.5.0",
1643 | "@ethersproject/logger": "^5.5.0",
1644 | "@ethersproject/properties": "^5.5.0",
1645 | "@ethersproject/random": "^5.5.0",
1646 | "@ethersproject/signing-key": "^5.5.0",
1647 | "@ethersproject/transactions": "^5.5.0",
1648 | "@ethersproject/wordlists": "^5.5.0"
1649 | }
1650 | },
1651 | "@ethersproject/web": {
1652 | "version": "5.5.1",
1653 | "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.5.1.tgz",
1654 | "integrity": "sha512-olvLvc1CB12sREc1ROPSHTdFCdvMh0J5GSJYiQg2D0hdD4QmJDy8QYDb1CvoqD/bF1c++aeKv2sR5uduuG9dQg==",
1655 | "requires": {
1656 | "@ethersproject/base64": "^5.5.0",
1657 | "@ethersproject/bytes": "^5.5.0",
1658 | "@ethersproject/logger": "^5.5.0",
1659 | "@ethersproject/properties": "^5.5.0",
1660 | "@ethersproject/strings": "^5.5.0"
1661 | }
1662 | },
1663 | "@ethersproject/wordlists": {
1664 | "version": "5.5.0",
1665 | "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.5.0.tgz",
1666 | "integrity": "sha512-bL0UTReWDiaQJJYOC9sh/XcRu/9i2jMrzf8VLRmPKx58ckSlOJiohODkECCO50dtLZHcGU6MLXQ4OOrgBwP77Q==",
1667 | "requires": {
1668 | "@ethersproject/bytes": "^5.5.0",
1669 | "@ethersproject/hash": "^5.5.0",
1670 | "@ethersproject/logger": "^5.5.0",
1671 | "@ethersproject/properties": "^5.5.0",
1672 | "@ethersproject/strings": "^5.5.0"
1673 | }
1674 | },
1675 | "@tsconfig/node10": {
1676 | "version": "1.0.8",
1677 | "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz",
1678 | "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==",
1679 | "dev": true
1680 | },
1681 | "@tsconfig/node12": {
1682 | "version": "1.0.9",
1683 | "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz",
1684 | "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==",
1685 | "dev": true
1686 | },
1687 | "@tsconfig/node14": {
1688 | "version": "1.0.1",
1689 | "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz",
1690 | "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==",
1691 | "dev": true
1692 | },
1693 | "@tsconfig/node16": {
1694 | "version": "1.0.2",
1695 | "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz",
1696 | "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==",
1697 | "dev": true
1698 | },
1699 | "@types/node": {
1700 | "version": "17.0.5",
1701 | "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.5.tgz",
1702 | "integrity": "sha512-w3mrvNXLeDYV1GKTZorGJQivK6XLCoGwpnyJFbJVK/aTBQUxOCaa/GlFAAN3OTDFcb7h5tiFG+YXCO2By+riZw=="
1703 | },
1704 | "@types/webidl-conversions": {
1705 | "version": "6.1.1",
1706 | "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-6.1.1.tgz",
1707 | "integrity": "sha512-XAahCdThVuCFDQLT7R7Pk/vqeObFNL3YqRyFZg+AqAP/W1/w3xHaIxuW7WszQqTbIBOPRcItYJIou3i/mppu3Q=="
1708 | },
1709 | "@types/whatwg-url": {
1710 | "version": "8.2.1",
1711 | "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.1.tgz",
1712 | "integrity": "sha512-2YubE1sjj5ifxievI5Ge1sckb9k/Er66HyR2c+3+I6VDUUg1TLPdYYTEbQ+DjRkS4nTxMJhgWfSfMRD2sl2EYQ==",
1713 | "requires": {
1714 | "@types/node": "*",
1715 | "@types/webidl-conversions": "*"
1716 | }
1717 | },
1718 | "acorn": {
1719 | "version": "8.7.0",
1720 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz",
1721 | "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==",
1722 | "dev": true
1723 | },
1724 | "acorn-walk": {
1725 | "version": "8.2.0",
1726 | "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
1727 | "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
1728 | "dev": true
1729 | },
1730 | "aes-js": {
1731 | "version": "3.0.0",
1732 | "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz",
1733 | "integrity": "sha1-4h3xCtbCBTKVvLuNq0Cwnb6ofk0="
1734 | },
1735 | "arg": {
1736 | "version": "4.1.3",
1737 | "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
1738 | "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
1739 | "dev": true
1740 | },
1741 | "argparse": {
1742 | "version": "2.0.1",
1743 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
1744 | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
1745 | },
1746 | "base64-js": {
1747 | "version": "1.5.1",
1748 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
1749 | "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
1750 | },
1751 | "bech32": {
1752 | "version": "1.1.4",
1753 | "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz",
1754 | "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ=="
1755 | },
1756 | "bn.js": {
1757 | "version": "4.12.0",
1758 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
1759 | "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
1760 | },
1761 | "brorand": {
1762 | "version": "1.1.0",
1763 | "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
1764 | "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8="
1765 | },
1766 | "bson": {
1767 | "version": "4.6.1",
1768 | "resolved": "https://registry.npmjs.org/bson/-/bson-4.6.1.tgz",
1769 | "integrity": "sha512-I1LQ7Hz5zgwR4QquilLNZwbhPw0Apx7i7X9kGMBTsqPdml/03Q9NBtD9nt/19ahjlphktQImrnderxqpzeVDjw==",
1770 | "requires": {
1771 | "buffer": "^5.6.0"
1772 | }
1773 | },
1774 | "buffer": {
1775 | "version": "5.7.1",
1776 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
1777 | "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
1778 | "requires": {
1779 | "base64-js": "^1.3.1",
1780 | "ieee754": "^1.1.13"
1781 | }
1782 | },
1783 | "create-require": {
1784 | "version": "1.1.1",
1785 | "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
1786 | "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
1787 | "dev": true
1788 | },
1789 | "denque": {
1790 | "version": "2.0.1",
1791 | "resolved": "https://registry.npmjs.org/denque/-/denque-2.0.1.tgz",
1792 | "integrity": "sha512-tfiWc6BQLXNLpNiR5iGd0Ocu3P3VpxfzFiqubLgMfhfOw9WyvgJBd46CClNn9k3qfbjvT//0cf7AlYRX/OslMQ=="
1793 | },
1794 | "diff": {
1795 | "version": "4.0.2",
1796 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
1797 | "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
1798 | "dev": true
1799 | },
1800 | "dotenv": {
1801 | "version": "16.0.0",
1802 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.0.tgz",
1803 | "integrity": "sha512-qD9WU0MPM4SWLPJy/r2Be+2WgQj8plChsyrCNQzW/0WjvcJQiKQJ9mH3ZgB3fxbUUxgc/11ZJ0Fi5KiimWGz2Q=="
1804 | },
1805 | "elliptic": {
1806 | "version": "6.5.4",
1807 | "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz",
1808 | "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==",
1809 | "requires": {
1810 | "bn.js": "^4.11.9",
1811 | "brorand": "^1.1.0",
1812 | "hash.js": "^1.0.0",
1813 | "hmac-drbg": "^1.0.1",
1814 | "inherits": "^2.0.4",
1815 | "minimalistic-assert": "^1.0.1",
1816 | "minimalistic-crypto-utils": "^1.0.1"
1817 | }
1818 | },
1819 | "ethers": {
1820 | "version": "5.5.4",
1821 | "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.5.4.tgz",
1822 | "integrity": "sha512-N9IAXsF8iKhgHIC6pquzRgPBJEzc9auw3JoRkaKe+y4Wl/LFBtDDunNe7YmdomontECAcC5APaAgWZBiu1kirw==",
1823 | "requires": {
1824 | "@ethersproject/abi": "5.5.0",
1825 | "@ethersproject/abstract-provider": "5.5.1",
1826 | "@ethersproject/abstract-signer": "5.5.0",
1827 | "@ethersproject/address": "5.5.0",
1828 | "@ethersproject/base64": "5.5.0",
1829 | "@ethersproject/basex": "5.5.0",
1830 | "@ethersproject/bignumber": "5.5.0",
1831 | "@ethersproject/bytes": "5.5.0",
1832 | "@ethersproject/constants": "5.5.0",
1833 | "@ethersproject/contracts": "5.5.0",
1834 | "@ethersproject/hash": "5.5.0",
1835 | "@ethersproject/hdnode": "5.5.0",
1836 | "@ethersproject/json-wallets": "5.5.0",
1837 | "@ethersproject/keccak256": "5.5.0",
1838 | "@ethersproject/logger": "5.5.0",
1839 | "@ethersproject/networks": "5.5.2",
1840 | "@ethersproject/pbkdf2": "5.5.0",
1841 | "@ethersproject/properties": "5.5.0",
1842 | "@ethersproject/providers": "5.5.3",
1843 | "@ethersproject/random": "5.5.1",
1844 | "@ethersproject/rlp": "5.5.0",
1845 | "@ethersproject/sha2": "5.5.0",
1846 | "@ethersproject/signing-key": "5.5.0",
1847 | "@ethersproject/solidity": "5.5.0",
1848 | "@ethersproject/strings": "5.5.0",
1849 | "@ethersproject/transactions": "5.5.0",
1850 | "@ethersproject/units": "5.5.0",
1851 | "@ethersproject/wallet": "5.5.0",
1852 | "@ethersproject/web": "5.5.1",
1853 | "@ethersproject/wordlists": "5.5.0"
1854 | }
1855 | },
1856 | "hash.js": {
1857 | "version": "1.1.7",
1858 | "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
1859 | "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
1860 | "requires": {
1861 | "inherits": "^2.0.3",
1862 | "minimalistic-assert": "^1.0.1"
1863 | }
1864 | },
1865 | "hmac-drbg": {
1866 | "version": "1.0.1",
1867 | "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
1868 | "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=",
1869 | "requires": {
1870 | "hash.js": "^1.0.3",
1871 | "minimalistic-assert": "^1.0.0",
1872 | "minimalistic-crypto-utils": "^1.0.1"
1873 | }
1874 | },
1875 | "ieee754": {
1876 | "version": "1.2.1",
1877 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
1878 | "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
1879 | },
1880 | "inherits": {
1881 | "version": "2.0.4",
1882 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
1883 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
1884 | },
1885 | "ip": {
1886 | "version": "1.1.5",
1887 | "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
1888 | "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo="
1889 | },
1890 | "js-sha3": {
1891 | "version": "0.8.0",
1892 | "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz",
1893 | "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q=="
1894 | },
1895 | "js-yaml": {
1896 | "version": "4.1.0",
1897 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
1898 | "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
1899 | "requires": {
1900 | "argparse": "^2.0.1"
1901 | }
1902 | },
1903 | "kafkajs": {
1904 | "version": "1.16.0",
1905 | "resolved": "https://registry.npmjs.org/kafkajs/-/kafkajs-1.16.0.tgz",
1906 | "integrity": "sha512-+Rcfu2hyQ/jv5skqRY8xA7Ra+mmRkDAzCaLDYbkGtgsNKpzxPWiLbk8ub0dgr4EbWrN1Zb4BCXHUkD6+zYfdWg=="
1907 | },
1908 | "make-error": {
1909 | "version": "1.3.6",
1910 | "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
1911 | "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
1912 | "dev": true
1913 | },
1914 | "memory-pager": {
1915 | "version": "1.5.0",
1916 | "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz",
1917 | "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==",
1918 | "optional": true
1919 | },
1920 | "minimalistic-assert": {
1921 | "version": "1.0.1",
1922 | "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
1923 | "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A=="
1924 | },
1925 | "minimalistic-crypto-utils": {
1926 | "version": "1.0.1",
1927 | "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
1928 | "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo="
1929 | },
1930 | "moment": {
1931 | "version": "2.29.1",
1932 | "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
1933 | "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
1934 | },
1935 | "moment-timezone": {
1936 | "version": "0.5.34",
1937 | "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.34.tgz",
1938 | "integrity": "sha512-3zAEHh2hKUs3EXLESx/wsgw6IQdusOT8Bxm3D9UrHPQR7zlMmzwybC8zHEM1tQ4LJwP7fcxrWr8tuBg05fFCbg==",
1939 | "requires": {
1940 | "moment": ">= 2.9.0"
1941 | }
1942 | },
1943 | "mongodb": {
1944 | "version": "4.3.1",
1945 | "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.3.1.tgz",
1946 | "integrity": "sha512-sNa8APSIk+r4x31ZwctKjuPSaeKuvUeNb/fu/3B6dRM02HpEgig7hTHM8A/PJQTlxuC/KFWlDlQjhsk/S43tBg==",
1947 | "requires": {
1948 | "bson": "^4.6.1",
1949 | "denque": "^2.0.1",
1950 | "mongodb-connection-string-url": "^2.4.1",
1951 | "saslprep": "^1.0.3",
1952 | "socks": "^2.6.1"
1953 | }
1954 | },
1955 | "mongodb-connection-string-url": {
1956 | "version": "2.4.1",
1957 | "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.4.1.tgz",
1958 | "integrity": "sha512-d5Kd2bVsKcSA7YI/yo57fSTtMwRQdFkvc5IZwod1RRxJtECeWPPSo7zqcUGJELifRA//Igs4spVtYAmvFCatug==",
1959 | "requires": {
1960 | "@types/whatwg-url": "^8.2.1",
1961 | "whatwg-url": "^11.0.0"
1962 | }
1963 | },
1964 | "node-cron": {
1965 | "version": "3.0.0",
1966 | "resolved": "https://registry.npmjs.org/node-cron/-/node-cron-3.0.0.tgz",
1967 | "integrity": "sha512-DDwIvvuCwrNiaU7HEivFDULcaQualDv7KoNlB/UU1wPW0n1tDEmBJKhEIE6DlF2FuoOHcNbLJ8ITL2Iv/3AWmA==",
1968 | "requires": {
1969 | "moment-timezone": "^0.5.31"
1970 | }
1971 | },
1972 | "prettier": {
1973 | "version": "2.7.1",
1974 | "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
1975 | "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g=="
1976 | },
1977 | "punycode": {
1978 | "version": "2.1.1",
1979 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
1980 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
1981 | },
1982 | "saslprep": {
1983 | "version": "1.0.3",
1984 | "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz",
1985 | "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==",
1986 | "optional": true,
1987 | "requires": {
1988 | "sparse-bitfield": "^3.0.3"
1989 | }
1990 | },
1991 | "scrypt-js": {
1992 | "version": "3.0.1",
1993 | "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz",
1994 | "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA=="
1995 | },
1996 | "smart-buffer": {
1997 | "version": "4.2.0",
1998 | "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
1999 | "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="
2000 | },
2001 | "socks": {
2002 | "version": "2.6.1",
2003 | "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.1.tgz",
2004 | "integrity": "sha512-kLQ9N5ucj8uIcxrDwjm0Jsqk06xdpBjGNQtpXy4Q8/QY2k+fY7nZH8CARy+hkbG+SGAovmzzuauCpBlb8FrnBA==",
2005 | "requires": {
2006 | "ip": "^1.1.5",
2007 | "smart-buffer": "^4.1.0"
2008 | }
2009 | },
2010 | "sparse-bitfield": {
2011 | "version": "3.0.3",
2012 | "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
2013 | "integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=",
2014 | "optional": true,
2015 | "requires": {
2016 | "memory-pager": "^1.0.2"
2017 | }
2018 | },
2019 | "tr46": {
2020 | "version": "3.0.0",
2021 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz",
2022 | "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==",
2023 | "requires": {
2024 | "punycode": "^2.1.1"
2025 | }
2026 | },
2027 | "ts-node": {
2028 | "version": "10.4.0",
2029 | "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.4.0.tgz",
2030 | "integrity": "sha512-g0FlPvvCXSIO1JDF6S232P5jPYqBkRL9qly81ZgAOSU7rwI0stphCgd2kLiCrU9DjQCrJMWEqcNSjQL02s6d8A==",
2031 | "dev": true,
2032 | "requires": {
2033 | "@cspotcode/source-map-support": "0.7.0",
2034 | "@tsconfig/node10": "^1.0.7",
2035 | "@tsconfig/node12": "^1.0.7",
2036 | "@tsconfig/node14": "^1.0.0",
2037 | "@tsconfig/node16": "^1.0.2",
2038 | "acorn": "^8.4.1",
2039 | "acorn-walk": "^8.1.1",
2040 | "arg": "^4.1.0",
2041 | "create-require": "^1.1.0",
2042 | "diff": "^4.0.1",
2043 | "make-error": "^1.1.1",
2044 | "yn": "3.1.1"
2045 | }
2046 | },
2047 | "typescript": {
2048 | "version": "4.5.5",
2049 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz",
2050 | "integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==",
2051 | "dev": true
2052 | },
2053 | "webidl-conversions": {
2054 | "version": "7.0.0",
2055 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
2056 | "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g=="
2057 | },
2058 | "whatwg-url": {
2059 | "version": "11.0.0",
2060 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz",
2061 | "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==",
2062 | "requires": {
2063 | "tr46": "^3.0.0",
2064 | "webidl-conversions": "^7.0.0"
2065 | }
2066 | },
2067 | "ws": {
2068 | "version": "7.4.6",
2069 | "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz",
2070 | "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==",
2071 | "requires": {}
2072 | },
2073 | "yn": {
2074 | "version": "3.1.1",
2075 | "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
2076 | "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
2077 | "dev": true
2078 | }
2079 | }
2080 | }
2081 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "intergalatic-indexer",
3 | "version": "1.0.0",
4 | "description": "Indexer for blockchain events",
5 | "main": "indexer.js",
6 | "scripts": {
7 | "build": "tsc",
8 | "start": "node build/indexer.js"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "git+https://github.com/Polynomial-Protocol/intergalactic-indexer.git"
13 | },
14 | "author": "phoenikx",
15 | "license": "MIT",
16 | "bugs": {
17 | "url": "https://github.com/Polynomial-Protocol/intergalactic-indexer/issues"
18 | },
19 | "homepage": "https://github.com/Polynomial-Protocol/intergalactic-indexer#readme",
20 | "dependencies": {
21 | "dotenv": "^16.0.0",
22 | "ethers": "^5.5.4",
23 | "js-yaml": "^4.1.0",
24 | "kafkajs": "^1.16.0",
25 | "mongodb": "^4.3.1",
26 | "node-cron": "^3.0.0",
27 | "prettier": "^2.7.1"
28 | },
29 | "devDependencies": {
30 | "ts-node": "^10.4.0",
31 | "typescript": "^4.5.5"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # Optimistic Indexer
2 |
3 | 
4 | 
5 | 
6 | 
7 | 
8 | 
9 |
10 | **Easy-to-Setup, Low Latency Indexer for L2s**
11 |
12 |
13 | ## What is Optimistic Indexer?
14 |
15 | Optimistic Indexer is a Fast, Low Latency event indexer tailored for EVM-based blockchains. Written in TypeScript, it offers two concurrent modes:
16 |
17 | - **Point-to-Point:** Indexes each block as they are added.
18 | - **Reconciliation:** Catches up on any missed blocks.
19 |
20 | The indexer is non-opinionated, exporting events to a MongoDB NOSQL database. It's designed to be part of a larger service architecture that reads these events to serve to end-users.
21 |
22 |
23 |
24 |
25 | ### 🌟 Features
26 |
27 | 1. Registering new contracts and specifying the events to listen to.
28 | 2. Reading past and live events from the chain and storing them in the database for querying.
29 | 3. Optionally pushing events to a Kafka topic.
30 |
31 | ## 🚀 Quick Start
32 |
33 | ### 🔍 Prerequisites
34 | Before running the indexer, make sure to install the following:
35 |
36 | 1. **Node.js** and npm installed or use the docker container
37 | 2. **MongoDB**: Install and run MongoDB 4.2+ or use a hosted MongoDB solution like MongoDB Atlas.
38 | 3. **Kafka (Optional)**: Install and run Kafka or use a hosted solution like Confluent if you wish to push events to a Kafka topic.
39 | 4. **Alchemy API Key**: Create an account on Alchemy to query the blockchain for events. Copy your API keys for both indexer and reconciliation tasks.
40 |
41 | ### 🛠️ Installation
42 |
43 | 1. Clone the repository
44 | ```bash
45 | git clone https://github.com/Polynomial-Protocol/intergalactic-indexer.git
46 | ```
47 |
48 | 2. Navigate to the project directory
49 | ```bash
50 | cd intergalactic-indexer
51 | ```
52 |
53 | 3. Install dependencies
54 | ```bash
55 | npm install
56 | ```
57 |
58 | 4. Create a `.env` file and populate it with your settings. An example is given below:
59 | ```env
60 | MONGO_URI="mongodb://localhost:27017" # uri of mongodb installation
61 | APP_NAME="indexer" # anything that you want
62 | ALCHEMY_API_KEY_FOR_INDEXER="" # alchemy api key that will be used to listen for events using websockets
63 | ALCHEMY_API_KEY_FOR_RECONCILIATION="" # alchemy api key that will be used to run the reconciliation loop, you can use the same API key as above
64 | INDEXES_RELATIVE_PATH="artifacts/indexes.yaml" # this file is used to store all the mongodb indexes that have to be created, do not change it or else indexer will start running slowly due to slow db queries
65 | RECONCILIATION_CRON="*/2 * * * *" # cron expression for reconciliation, change it as needed
66 | DB_NAME="indexer" # name of the database in mongodb
67 | CONTRACTS_RELATIVE_PATH="artifacts/example-contract.yaml" # file where contracts and their index configuration are present
68 | NETWORK="optimism" # network for which the indexer will run
69 | KAFKA_API_KEY="" # kafka api key, only required if you wish to push events to a kafka topic
70 | KAFKA_API_SECRET="" # kafka api secret, only required if you wish to push events to a kafka topic
71 | KAFKA_BOOTSTRAP_SERVER="" # kafka bootstrap server, only required if you wish to push events to a kafka topic
72 | KAFKA_TOPIC=events # change it to point to correct name of topic name
73 | PUSH_EVENTS=false # set it to true if you wish to push events to a kafka topic
74 | ```
75 | 5. Run the indexer
76 | ```bash
77 | npx ts-node src/indexer.ts
78 | ```
79 |
80 | ## 🔧 Configuring Contracts
81 |
82 | Modify the configuration file specified by `CONTRACTS_RELATIVE_PATH` to include the smart contracts and events you wish to index.
83 |
84 | #### `example-contract.yaml` Breakdown
85 |
86 | - `identifier`: A unique name for the contract.
87 | - `abi`: The Application Binary Interface of the contract. It's an array of method and event descriptions. It is taken as string and ABI can be provided in JSON or by formatting it like [this](https://github.com/gnidan/abi-to-sol). Examples for both can be in artifacts folder
88 | - `startIdx`: Starting block number for indexing events.
89 | - `address`: Ethereum address where the contract is deployed.
90 | - `eventsToIndex`: Events your application should listen for.
91 | - `disabled`: Boolean flag indicating if the contract should be ignored.
92 |
93 | ## 💡 Additional Information
94 |
95 | #### 📈 Importance of an Indexer
96 |
97 | An indexer is indispensable for building robust backends for blockchain applications. Events emitted in transaction receipts contain vital information for applications, such as transfers of tokens in an NFT marketplace.
98 |
99 | #### 🚧 Limitations of the Current Indexer
100 |
101 | 1. Only supports the Optimism chain for now.
102 | 2. Event ordering is not guaranteed. The indexer uses websockets to listen for current events and a reconciliation loop to index events that might be missed.
103 | 3. Not optimized for performance; single-threaded. Not scalable for a large number of events
104 |
105 | #### 📗 Examples of Applications
106 |
107 | Almost all applications with a smart contract deployed on a blockchain could benefit from this indexer. Typically, dApps either use a decentralized indexer like The Graph or run an in-house indexer.
108 |
109 | #### 🤝 How an Open-Sourced Model Will Help
110 |
111 | Having an open-source indexer saves developers from reinventing the wheel, significantly cutting down on development time and cost.
112 |
113 | #### 🐳 Non-Kubernetes Deployments
114 |
115 | This project includes a Dockerfile for containerized deployment. Ensure Docker is installed if you're not using Kubernetes.
116 |
117 |
118 | ### 🌐 Community and Contributions
119 |
120 | Open to contributions, please check the CONTRIBUTING.md file for details.
121 |
122 | ### ⚖️ License
123 |
124 | This project is licensed under the MIT License - see the LICENSE.md file for details.
125 |
126 | ---
127 |
128 | Made with 🔴 by Polynomial Protocol.
129 | For any issues or contributions, please refer to our [GitHub repository](https://github.com/Polynomial-Protocol/intergalactic-indexer).
130 |
131 | Credits @phoenikx
132 |
--------------------------------------------------------------------------------
/src/artifacts/example-contract-alternative.yaml:
--------------------------------------------------------------------------------
1 | - identifier: AAVE_L2_POOL
2 | abi:
3 | [
4 | "event Supply( address indexed reserve,address user,address indexed onBehalfOf,uint256 amount,uint16 indexed referralCode )"
5 | ]
6 | startIdx: 109849585
7 | address: "0x794a61358D6845594F94dc1DB02A252b5b4814aD"
8 | eventsToIndex:
9 | - name: Supply
10 | arguments:
11 | - reserve
12 | - user
13 | - onBehalfOf
14 | - amount
15 | - referralCode
16 |
--------------------------------------------------------------------------------
/src/artifacts/example-contract.yaml:
--------------------------------------------------------------------------------
1 | - identifier: OP_TOKEN
2 | abi: [{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"address","name":"fromDelegate","type":"address"},{"indexed":true,"internalType":"address","name":"toDelegate","type":"address"}],"name":"DelegateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegate","type":"address"},{"indexed":false,"internalType":"uint256","name":"previousBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newBalance","type":"uint256"}],"name":"DelegateVotesChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burnFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint32","name":"pos","type":"uint32"}],"name":"checkpoints","outputs":[{"components":[{"internalType":"uint32","name":"fromBlock","type":"uint32"},{"internalType":"uint224","name":"votes","type":"uint224"}],"internalType":"struct ERC20Votes.Checkpoint","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegatee","type":"address"}],"name":"delegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegatee","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"delegateBySig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"delegates","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"getPastTotalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"getPastVotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getVotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"numCheckpoints","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]
3 | startIdx: 109801544
4 | address: "0x4200000000000000000000000000000000000042"
5 | disabled: false
6 | eventsToIndex:
7 | - name: Transfer
8 | arguments:
9 | - from
10 | - to
11 | - value
--------------------------------------------------------------------------------
/src/artifacts/indexes.yaml:
--------------------------------------------------------------------------------
1 | contracts:
2 | - name: unique_identifier_idx
3 | unique: true
4 | background: false
5 | spec:
6 | - identifier: 1
7 | - name: address_idx
8 | unique: false
9 | background: false
10 | spec:
11 | - address: 1
12 |
13 | events:
14 | - name: name_key_value_idx
15 | unique: false
16 | background: false
17 | spec:
18 | - name: 1
19 | - args.key: 1
20 | - args.value: 1
21 | - name: contract_name_idx
22 | unique: false
23 | background: false
24 | spec:
25 | - contractAddress: 1
26 | - name: 1
27 | - name: transaction_hash_log_index_idx
28 | unique: true
29 | background: false
30 | spec:
31 | - transactionHash: 1
32 | - logIndex: 1
--------------------------------------------------------------------------------
/src/dao/EventDAOImpl.ts:
--------------------------------------------------------------------------------
1 | import { EventDAO } from "./interface/EventDAO";
2 | import { Collection, Db } from "mongodb";
3 | import * as events from "events";
4 | import { OptimisticEventDBO } from "../models/OptimisticEventDBO";
5 | import { OptimisticContractService } from "../services/interfaces/OptimisticContractService";
6 |
7 | export class EventDAOImpl implements EventDAO {
8 | private events: Collection;
9 | private sweepData: Collection;
10 |
11 | constructor(db: Db, private contractService: OptimisticContractService) {
12 | this.events = db.collection("events");
13 | this.sweepData = db.collection("sweepData");
14 | }
15 |
16 | async getLastBlockProcessedForEvent(
17 | contractIdentifier: string,
18 | eventName: string
19 | ): Promise {
20 | const doc = await this.sweepData.findOne({
21 | contractIdentifier: contractIdentifier,
22 | eventName: eventName,
23 | });
24 | if (doc === null) {
25 | const contract = await this.contractService.getContract(
26 | contractIdentifier
27 | );
28 | return contract.startIdx;
29 | }
30 |
31 | return doc["blockNumber"];
32 | }
33 |
34 | async save(OptimisticEventDBO: OptimisticEventDBO): Promise {
35 | try {
36 | await this.events.insertOne(OptimisticEventDBO);
37 | return true;
38 | } catch (error) {
39 | console.error("Could not save event due to error: %s", error);
40 | return false;
41 | }
42 | }
43 |
44 | async updateLastProcessedBlockForEvent(
45 | identifier: string,
46 | name: string,
47 | currentBlockNumber: number
48 | ): Promise {
49 | await this.sweepData.updateOne(
50 | { contractIdentifier: identifier, eventName: name },
51 | { $set: { blockNumber: currentBlockNumber } },
52 | { upsert: true }
53 | );
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/dao/OptimisticContractDAOImpl.ts:
--------------------------------------------------------------------------------
1 | import {OptimisticContract} from "../models/OptimisticContract";
2 | import {OptimisticContractDAO} from "./interface/OptimisticContractDAO";
3 | import {Collection, Db, Document, Filter} from "mongodb";
4 | import {WithId} from "mongodb/mongodb.ts34";
5 |
6 | export class OptimisticContractDAOImpl implements OptimisticContractDAO {
7 | private collection: Collection;
8 | private static COLLECTION_NAME = "contracts";
9 |
10 | private static getContractFromDBObject(document: WithId): OptimisticContract {
11 | return {
12 | identifier: document['identifier'],
13 | abi: document['abi'],
14 | address: document['address'],
15 | eventsToIndex: document['eventsToIndex'],
16 | startIdx: document['startIdx'],
17 | disabled: document['disabled'] || false
18 | }
19 | }
20 |
21 | public constructor(database: Db) {
22 | this.collection = database.collection(OptimisticContractDAOImpl.COLLECTION_NAME);
23 | }
24 |
25 | async query(criteria: Filter): Promise> {
26 | const result = await this.collection.find({disabled: {"$ne": true}});
27 | let contracts = await result.toArray();
28 | return contracts.map((value) => {
29 | return OptimisticContractDAOImpl.getContractFromDBObject(value);
30 | });
31 | }
32 |
33 | async get(identifier: string): Promise {
34 | const result = await this.collection.findOne({identifier: identifier});
35 | if (result) {
36 | return {
37 | identifier: result['identifier'],
38 | abi: result['abi'],
39 | address: result['address'],
40 | eventsToIndex: result['eventsToIndex'],
41 | startIdx: result['startIdx']
42 | };
43 | }
44 | return Promise.reject('No such contract found with identifier: ' + identifier);
45 | }
46 |
47 | async save(contract: OptimisticContract): Promise {
48 | const result = await this.collection.replaceOne({identifier: contract.identifier}, contract, {upsert: true})
49 | return result.modifiedCount == 1
50 | }
51 |
52 | }
--------------------------------------------------------------------------------
/src/dao/interface/EventDAO.ts:
--------------------------------------------------------------------------------
1 | import { OptimisticEventDBO } from "../../models/OptimisticEventDBO";
2 |
3 | export interface EventDAO {
4 | getLastBlockProcessedForEvent(
5 | contractIdentifier: string,
6 | eventName: string
7 | ): Promise;
8 |
9 | save(OptimisticEventDBO: OptimisticEventDBO): Promise;
10 |
11 | updateLastProcessedBlockForEvent(
12 | contractIdentifier: string,
13 | eventName: string,
14 | currentBlockNumber: number
15 | ): Promise;
16 | }
17 |
--------------------------------------------------------------------------------
/src/dao/interface/OptimisticContractDAO.ts:
--------------------------------------------------------------------------------
1 | import {OptimisticContract} from "../../models/OptimisticContract";
2 | import {Filter} from "mongodb/mongodb.ts34";
3 |
4 | export interface OptimisticContractDAO {
5 | save(contract: OptimisticContract): Promise;
6 |
7 | get(identifier: string): Promise;
8 |
9 | query(criteria: Filter): Promise>;
10 | }
--------------------------------------------------------------------------------
/src/helpers/ContractRegistrationHelper.ts:
--------------------------------------------------------------------------------
1 | export interface ContractRegistrationHelper {
2 | registerContracts(): Promise>;
3 | }
--------------------------------------------------------------------------------
/src/helpers/ContractRegistrationServiceLocalImpl.ts:
--------------------------------------------------------------------------------
1 | import { ContractRegistrationHelper } from "./ContractRegistrationHelper";
2 | import { OptimisticContractService } from "../services/interfaces/OptimisticContractService";
3 | import { OptimisticContract } from "../models/OptimisticContract";
4 |
5 | const yaml = require("js-yaml");
6 | const fs = require("fs");
7 |
8 | export class ContractRegistrationServiceLocalImpl
9 | implements ContractRegistrationHelper
10 | {
11 | public constructor(
12 | private contractsPath: string,
13 | private contractService: OptimisticContractService
14 | ) {}
15 |
16 | async registerContracts(): Promise {
17 | const contracts: OptimisticContract[] = yaml.load(
18 | fs.readFileSync(this.contractsPath, "utf8")
19 | );
20 | let identifiers: Set = new Set();
21 |
22 | for (let contract of contracts) {
23 | let contractFromDB: OptimisticContract;
24 | try {
25 | contractFromDB = await this.contractService.getContract(
26 | contract.identifier
27 | );
28 | contractFromDB.abi = contract.abi;
29 | contractFromDB.address = contract.address;
30 | contractFromDB.eventsToIndex = contract.eventsToIndex;
31 | contractFromDB.disabled = contract.disabled;
32 | } catch (e) {
33 | contractFromDB = {
34 | identifier: contract.identifier,
35 | abi: contract.abi,
36 | startIdx: contract.startIdx,
37 | address: contract.address,
38 | eventsToIndex: contract.eventsToIndex,
39 | disabled: contract.disabled,
40 | };
41 | }
42 |
43 | await this.contractService.save(contractFromDB);
44 |
45 | identifiers.add(contract.identifier);
46 | }
47 | return identifiers;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/helpers/ContractRegistrationServiceRemoteImpl.ts:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Polynomial-Protocol/optimistic-indexer/34ca87c44e5494f8fa26ee4ba97858e29f029015/src/helpers/ContractRegistrationServiceRemoteImpl.ts
--------------------------------------------------------------------------------
/src/indexer.ts:
--------------------------------------------------------------------------------
1 | import { OptimisticContractDAOImpl } from "./dao/OptimisticContractDAOImpl";
2 | import { Db, MongoClient } from "mongodb";
3 | import { IndexManager } from "./services/interfaces/IndexManager";
4 | import { IndexManagerImpl } from "./services/IndexManagerImpl";
5 | import * as path from "path";
6 | import { ContractRegistrationServiceLocalImpl } from "./helpers/ContractRegistrationServiceLocalImpl";
7 | import { OptimisticContractServiceImpl } from "./services/OptimisticContractServiceImpl";
8 | import { Contract, ethers, providers } from "ethers";
9 | import { EventServiceImpl } from "./services/EventServiceImpl";
10 | import { EventDAOImpl } from "./dao/EventDAOImpl";
11 | import { ChainServiceImpl } from "./services/ChainServiceImpl";
12 | import { PointToPointIndexerServiceImpl } from "./services/PointToPointIndexerServiceImpl";
13 | import { SweepingIndexerServiceImpl } from "./services/SweepingIndexerServiceImpl";
14 | import { OptimisticContractService } from "./services/interfaces/OptimisticContractService";
15 | import { EventService } from "./services/interfaces/EventService";
16 | import { Kafka } from "kafkajs";
17 | import {
18 | KafkaQueueServiceImpl,
19 | MockQueueServiceImpl,
20 | } from "./queue/queue.service";
21 |
22 | let cron = require("node-cron");
23 | const yaml = require("js-yaml");
24 | const fs = require("fs");
25 | require("dotenv").config();
26 |
27 | const MONGO_URI = process.env.MONGO_URI!;
28 | const CONTRACTS_FILE_PATH = path.resolve(
29 | __dirname,
30 | process.env.CONTRACTS_RELATIVE_PATH!
31 | );
32 | const NETWORK = process.env.NETWORK!;
33 | const ALCHEMY_API_KEY_FOR_INDEXER = process.env.ALCHEMY_API_KEY_FOR_INDEXER!;
34 | const ALCHEMY_API_KEY_FOR_RECONCILIATION =
35 | process.env.ALCHEMY_API_KEY_FOR_RECONCILIATION!;
36 | const DB_NAME = process.env.DB_NAME!;
37 | const INDEXES_FILE_PATH = path.resolve(
38 | __dirname,
39 | process.env.INDEXES_RELATIVE_PATH!
40 | );
41 | const RECONCILIATION_CRON = process.env.RECONCILIATION_CRON || "*/5 * * * *";
42 | const EXPECTED_PONG_BACK = 15000;
43 | const KEEP_ALIVE_CHECK_INTERVAL = 7500;
44 | const KAFKA_CLIENT_ID = process.env.KAFKA_CLIENT_ID!;
45 | const KAFKA_BOOTSTRAP_SERVER = process.env.KAFKA_BOOTSTRAP_SERVER!;
46 | const KAFKA_API_KEY = process.env.KAFKA_API_KEY!;
47 | const KAFKA_API_SECRET = process.env.KAFKA_API_SECRET!;
48 | export const KAFKA_TOPIC = process.env.KAFKA_TOPIC!;
49 |
50 | async function setupKafka() {
51 | const kafka = await new Kafka({
52 | clientId: KAFKA_CLIENT_ID,
53 | brokers: [KAFKA_BOOTSTRAP_SERVER],
54 | ssl: true,
55 | sasl: {
56 | mechanism: "plain",
57 | username: KAFKA_API_KEY,
58 | password: KAFKA_API_SECRET,
59 | },
60 | });
61 |
62 | const kafkaProducer = kafka.producer();
63 | await kafkaProducer.connect();
64 | console.log("Kafka Producer connected.");
65 | return {
66 | kafkaProducer,
67 | };
68 | }
69 |
70 | export const getProvider = (
71 | network: string,
72 | apiKey: string
73 | ): providers.WebSocketProvider => {
74 | const provider = ethers.providers.AlchemyProvider.getWebSocketProvider(
75 | network,
76 | apiKey
77 | );
78 | let pingTimeout: any = null;
79 | let keepAliveInterval: any = null;
80 |
81 | provider._websocket.on("open", () => {
82 | keepAliveInterval = setInterval(() => {
83 | provider._websocket.ping();
84 |
85 | pingTimeout = setTimeout(() => {
86 | provider._websocket.terminate();
87 | }, EXPECTED_PONG_BACK);
88 | }, KEEP_ALIVE_CHECK_INTERVAL);
89 | });
90 |
91 | provider._websocket.on("close", () => {
92 | console.error(
93 | "The websocket connection was closed, killing and restarting service..."
94 | );
95 | clearInterval(keepAliveInterval);
96 | clearTimeout(pingTimeout);
97 | process.exit(1);
98 | });
99 |
100 | provider._websocket.on("pong", () => {
101 | clearInterval(pingTimeout);
102 | });
103 |
104 | return provider;
105 | };
106 |
107 | async function getDatabase(mongoUri: string, dbName: string): Promise {
108 | const client = new MongoClient(mongoUri);
109 | await client.connect();
110 | return client.db(dbName);
111 | }
112 |
113 | async function createIndexes(
114 | filePath: string,
115 | db: Db,
116 | indexManager: IndexManager
117 | ): Promise> {
118 | const collectionIndexes = yaml.load(fs.readFileSync(filePath, "utf8"));
119 | return await indexManager.ensureIndexes(collectionIndexes);
120 | }
121 |
122 | async function reconcilePastEvents(
123 | contractService: OptimisticContractService,
124 | eventService: EventService
125 | ) {
126 | let chainProvider = getProvider(NETWORK, ALCHEMY_API_KEY_FOR_RECONCILIATION);
127 | let chainService = new ChainServiceImpl(chainProvider);
128 | let contracts = await contractService.getActiveContracts();
129 | for (let OptimisticContract of contracts) {
130 | const chainContract = new Contract(
131 | OptimisticContract.address,
132 | OptimisticContract.abi,
133 | chainProvider
134 | );
135 | await new SweepingIndexerServiceImpl(
136 | OptimisticContract,
137 | chainContract,
138 | eventService,
139 | chainService
140 | ).reconcilePastEvents();
141 | }
142 | }
143 |
144 | async function runIndexer(
145 | db: Db,
146 | contractService: OptimisticContractService,
147 | eventService: EventService
148 | ) {
149 | const chainProvider = getProvider(NETWORK, ALCHEMY_API_KEY_FOR_INDEXER);
150 | const chainService = new ChainServiceImpl(chainProvider);
151 | const pointToPointIndexerService = new PointToPointIndexerServiceImpl(
152 | contractService,
153 | eventService,
154 | chainService,
155 | chainProvider
156 | );
157 | await pointToPointIndexerService.startListeningForEventsFromActiveContracts();
158 | }
159 |
160 | async function actrunCronForReconcilingPastEvents(
161 | contractService: OptimisticContractService,
162 | eventService: EventService
163 | ) {
164 | cron.schedule(RECONCILIATION_CRON, () => {
165 | reconcilePastEvents(contractService, eventService);
166 | });
167 | }
168 |
169 | async function main() {
170 | const db = await getDatabase(MONGO_URI, DB_NAME);
171 | console.log("Connected to database: %s", db.databaseName);
172 |
173 | const indexesCreated = await createIndexes(
174 | INDEXES_FILE_PATH,
175 | db,
176 | new IndexManagerImpl(db)
177 | );
178 | console.log("Created indexes: [%s]", indexesCreated.toString());
179 |
180 | const contractService = new OptimisticContractServiceImpl(
181 | new OptimisticContractDAOImpl(db)
182 | );
183 |
184 | let queueService;
185 | if (process.env.PUSH_TO_KAFKA === "true") {
186 | const { kafkaProducer } = await setupKafka();
187 | queueService = new KafkaQueueServiceImpl(kafkaProducer);
188 | } else {
189 | queueService = new MockQueueServiceImpl();
190 | }
191 |
192 | const eventService = new EventServiceImpl(
193 | new EventDAOImpl(db, contractService),
194 | queueService
195 | );
196 |
197 | const contractRegistrationService = new ContractRegistrationServiceLocalImpl(
198 | CONTRACTS_FILE_PATH,
199 | contractService
200 | );
201 | await contractRegistrationService.registerContracts();
202 |
203 | console.log("Reconciling past events during boot up...");
204 |
205 | await reconcilePastEvents(contractService, eventService);
206 |
207 | await runIndexer(db, contractService, eventService);
208 |
209 | await actrunCronForReconcilingPastEvents(contractService, eventService);
210 | }
211 |
212 | main().catch((error) => {
213 | console.log(error);
214 | process.exit(1);
215 | });
216 |
--------------------------------------------------------------------------------
/src/models/OptimisticContract.ts:
--------------------------------------------------------------------------------
1 | export interface Event {
2 | name: string;
3 | signature: string;
4 | }
5 |
6 | export interface OptimisticContract {
7 | identifier: string;
8 | abi: string[];
9 | address: string;
10 | eventsToIndex: OptimisticEvent[];
11 | startIdx: number;
12 | disabled?: boolean;
13 | }
14 |
15 | export interface OptimisticEvent {
16 | name: string
17 | arguments: string[]
18 | }
--------------------------------------------------------------------------------
/src/models/OptimisticEventDBO.ts:
--------------------------------------------------------------------------------
1 | import {ReconcilerType} from "./ReconcilerType";
2 |
3 | export interface OptimisticEventDBO {
4 | id?: string;
5 | contractAddress: string;
6 | transactionHash: string;
7 | name: string;
8 | timestamp?: number;
9 | args?: EventArg[];
10 | blockNumber: number;
11 | logIndex: number;
12 | signature: string | undefined;
13 | savedBy: ReconcilerType;
14 | }
15 |
16 | export interface EventArg {
17 | key: string
18 | value: any
19 | }
--------------------------------------------------------------------------------
/src/models/ReconcilerType.ts:
--------------------------------------------------------------------------------
1 | export enum ReconcilerType {
2 | SWEEP,
3 | POINT
4 | }
--------------------------------------------------------------------------------
/src/queue/queue.service.ts:
--------------------------------------------------------------------------------
1 | import { KAFKA_TOPIC } from "../indexer";
2 | import { Producer } from "kafkajs";
3 |
4 | export interface QueueServiceInterface {
5 | pushEvent(key: string, value: string): Promise;
6 | }
7 |
8 | export class KafkaQueueServiceImpl implements QueueServiceInterface {
9 | constructor(private kafkaProducer: Producer) {}
10 |
11 | async pushEvent(key: string, value: string): Promise {
12 | return await this.kafkaProducer.send({
13 | topic: KAFKA_TOPIC,
14 | messages: [
15 | {
16 | key: key,
17 | value: value,
18 | },
19 | ],
20 | });
21 | }
22 | }
23 |
24 | export class MockQueueServiceImpl implements QueueServiceInterface {
25 | async pushEvent(key: string, value: string): Promise {
26 | return "Not implemented";
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/services/ChainServiceImpl.ts:
--------------------------------------------------------------------------------
1 | import {ChainService} from "./interfaces/ChainService";
2 | import {ethers} from "ethers";
3 |
4 | export class ChainServiceImpl implements ChainService {
5 | delayFunc = (ms: number) => new Promise(res => setTimeout(res, ms));
6 |
7 | constructor(private provider: ethers.providers.Provider) {
8 | }
9 |
10 | async getCurrentBlockNumber(): Promise {
11 | return await this.provider.getBlockNumber();
12 | }
13 |
14 | async getTimestamp(blockNumber: number): Promise {
15 | let block: any = await this.provider.getBlock(blockNumber);
16 | if (!block) {
17 | await this.delayFunc(5000);
18 | block = await this.provider.getBlock(blockNumber);
19 | }
20 |
21 | if (block) {
22 | return block.timestamp;
23 | }
24 | return 0;
25 | }
26 |
27 | async getTimestampByHash(transactionHash: string): Promise {
28 | let block: any = await this.provider.getTransaction(transactionHash);
29 | if (!block) {
30 | await this.delayFunc(5000);
31 | block = await this.provider.getTransaction(transactionHash);
32 | }
33 |
34 | if (block) {
35 | return block.timestamp
36 | }
37 | return 0;
38 | }
39 |
40 | }
--------------------------------------------------------------------------------
/src/services/EventReconciliationServiceImpl.ts:
--------------------------------------------------------------------------------
1 | import { EventReconciliationService } from "./interfaces/EventReconciliationService";
2 | import { ReconcilerType } from "../models/ReconcilerType";
3 | import { EventService } from "./interfaces/EventService";
4 | import { ChainService } from "./interfaces/ChainService";
5 | import { Contract, ethers } from "ethers";
6 | import {
7 | OptimisticContract,
8 | OptimisticEvent,
9 | } from "../models/OptimisticContract";
10 | import { EventArg, OptimisticEventDBO } from "../models/OptimisticEventDBO";
11 |
12 | export class EventReconciliationServiceImpl
13 | implements EventReconciliationService
14 | {
15 | constructor(
16 | private eventService: EventService,
17 | private chainService: ChainService,
18 | private contract: Contract,
19 | private OptimisticContract: OptimisticContract,
20 | private OptimisticEvent: OptimisticEvent
21 | ) {}
22 |
23 | public static getArgs(
24 | argValues: ethers.utils.Result,
25 | args: string[]
26 | ): Array {
27 | let eventArgs = new Array();
28 | for (const argName of args) {
29 | let val = argValues[argName];
30 | if (val != undefined) {
31 | eventArgs.push({ key: argName, value: val });
32 | }
33 | }
34 | return eventArgs;
35 | }
36 |
37 | private async convertEvent(
38 | event: ethers.Event,
39 | contractAddress: string,
40 | reconcilerType: ReconcilerType
41 | ): Promise {
42 | let timestamp = await this.chainService.getTimestamp(event.blockNumber);
43 | return {
44 | name: event.event!,
45 | contractAddress: contractAddress,
46 | transactionHash: event.transactionHash,
47 | blockNumber: event.blockNumber,
48 | logIndex: event.logIndex,
49 | signature: event.eventSignature,
50 | timestamp: timestamp,
51 | args: EventReconciliationServiceImpl.getArgs(
52 | event.args!,
53 | this.OptimisticEvent.arguments
54 | ),
55 | savedBy: reconcilerType,
56 | };
57 | }
58 |
59 | async reconcileBatch(fromBlock: number, toBlock: number) {
60 | console.log(
61 | `Reconciling ${this.OptimisticEvent.name} from ${fromBlock} to ${toBlock}`
62 | );
63 | let events = await this.contract.queryFilter(
64 | this.contract.filters[this.OptimisticEvent.name](),
65 | fromBlock,
66 | toBlock
67 | );
68 |
69 | if (events.length > 0) {
70 | for (let event of events) {
71 | const OptimisticEventDBO = await this.convertEvent(
72 | event,
73 | this.OptimisticContract.address,
74 | ReconcilerType.SWEEP
75 | );
76 | try {
77 | await this.eventService.save(OptimisticEventDBO);
78 | } catch (error: any) {
79 | console.log("Could not save event: %s", error.toString());
80 | }
81 | }
82 | }
83 |
84 | console.log(
85 | "[%s] Reconciled %s events of type: %s for contract: %s from block: %s to block: %s",
86 | new Date(Date.now()).toLocaleString(),
87 | events.length,
88 | this.OptimisticEvent.name,
89 | this.OptimisticContract.identifier,
90 | fromBlock,
91 | toBlock
92 | );
93 | await this.eventService.updateLastBlockProcessedForEvent(
94 | this.OptimisticContract.identifier,
95 | this.OptimisticEvent.name,
96 | toBlock
97 | );
98 | }
99 |
100 | async reconcile(): Promise {
101 | let lastBlockNumber = await this.eventService.getLastBlockProcessedForEvent(
102 | this.OptimisticContract.identifier,
103 | this.OptimisticEvent.name
104 | );
105 | const currentBlockNumber = await this.chainService.getCurrentBlockNumber();
106 |
107 | const batchSize = 86400;
108 |
109 | while (lastBlockNumber < currentBlockNumber) {
110 | let toBlock = lastBlockNumber + batchSize;
111 | if (toBlock > currentBlockNumber) {
112 | toBlock = currentBlockNumber;
113 | }
114 | await this.reconcileBatch(lastBlockNumber, toBlock);
115 | lastBlockNumber = toBlock;
116 | }
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/src/services/EventServiceImpl.ts:
--------------------------------------------------------------------------------
1 | import { EventService } from "./interfaces/EventService";
2 | import { EventDAO } from "../dao/interface/EventDAO";
3 | import { OptimisticEventDBO } from "../models/OptimisticEventDBO";
4 | import { QueueServiceInterface } from "../queue/queue.service";
5 |
6 | export class EventServiceImpl implements EventService {
7 | constructor(
8 | private eventDAO: EventDAO,
9 | private queueService: QueueServiceInterface
10 | ) {}
11 |
12 | async getLastBlockProcessedForEvent(
13 | contractIdentifier: string,
14 | eventName: string
15 | ): Promise {
16 | return await this.eventDAO.getLastBlockProcessedForEvent(
17 | contractIdentifier,
18 | eventName
19 | );
20 | }
21 |
22 | async save(OptimisticEventDBO: OptimisticEventDBO): Promise {
23 | const success = await this.eventDAO.save(OptimisticEventDBO);
24 | const { contractAddress, name } = OptimisticEventDBO;
25 | if (success) {
26 | const response = await this.queueService.pushEvent(
27 | `${contractAddress}-${name}`,
28 | JSON.stringify(OptimisticEventDBO)
29 | );
30 | console.log(response);
31 | }
32 | return success;
33 | }
34 |
35 | async updateLastBlockProcessedForEvent(
36 | identifier: string,
37 | name: string,
38 | currentBlockNumber: number
39 | ): Promise {
40 | return await this.eventDAO.updateLastProcessedBlockForEvent(
41 | identifier,
42 | name,
43 | currentBlockNumber
44 | );
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/services/IndexManagerImpl.ts:
--------------------------------------------------------------------------------
1 | import {CollectionIndex, Index, IndexManager} from "./interfaces/IndexManager";
2 | import {Db} from "mongodb";
3 |
4 | export class IndexManagerImpl implements IndexManager {
5 | public constructor(private db: Db) {
6 | }
7 |
8 | async ensureIndexes(collectionIndex: CollectionIndex): Promise> {
9 | let indexNames = new Array();
10 | for (let collectionIndexKey in collectionIndex) {
11 | const indexes: Index[] = collectionIndex[collectionIndexKey]
12 | for (let index of indexes) {
13 | const indexName = await this.db.collection(collectionIndexKey).createIndex(
14 | index.spec, {background: index.background, unique: index.unique});
15 | indexNames.push(indexName);
16 | }
17 | }
18 |
19 | return Promise.resolve(indexNames);
20 | }
21 | }
--------------------------------------------------------------------------------
/src/services/OptimisticContractServiceImpl.ts:
--------------------------------------------------------------------------------
1 | import {OptimisticContractService} from "./interfaces/OptimisticContractService";
2 | import {OptimisticContract} from "../models/OptimisticContract";
3 | import {OptimisticContractDAO} from "../dao/interface/OptimisticContractDAO";
4 |
5 | export class OptimisticContractServiceImpl implements OptimisticContractService {
6 |
7 | public constructor(private dao: OptimisticContractDAO) {
8 | }
9 |
10 | async disableContract(identifier: string): Promise {
11 | let contract = await this.getContract(identifier);
12 | contract.disabled = true;
13 | await this.save(contract);
14 |
15 | return true;
16 | }
17 |
18 | async getContract(identifier: string): Promise {
19 | return await this.dao.get(identifier);
20 | }
21 |
22 | async save(contract: OptimisticContract): Promise {
23 | const id = await this.dao.save(contract);
24 | return Promise.resolve(id);
25 | }
26 |
27 | async getActiveContracts(): Promise> {
28 | return await this.dao.query({disabled: false});
29 | }
30 | }
--------------------------------------------------------------------------------
/src/services/PointToPointIndexerServiceImpl.ts:
--------------------------------------------------------------------------------
1 | import {PointToPointIndexerService} from "./interfaces/PointToPointIndexerService";
2 | import {Contract, ethers} from "ethers";
3 | import {OptimisticContractService} from "./interfaces/OptimisticContractService";
4 | import {EventService} from "./interfaces/EventService";
5 | import {ReconcilerType} from "../models/ReconcilerType";
6 | import {EventReconciliationServiceImpl} from "./EventReconciliationServiceImpl";
7 | import {ChainService} from "./interfaces/ChainService";
8 |
9 | export class PointToPointIndexerServiceImpl implements PointToPointIndexerService {
10 | private contracts: Map;
11 |
12 | public constructor(private contractService: OptimisticContractService,
13 | private eventService: EventService,
14 | private chainService: ChainService,
15 | private provider: ethers.providers.Provider) {
16 | this.contracts = new Map();
17 | }
18 |
19 | public async disableContract(identifier: string): Promise {
20 | const contract = this.contracts.get(identifier);
21 | if (contract === undefined) {
22 | return false;
23 | }
24 |
25 | const success = await this.contractService.disableContract(identifier);
26 | if (success) {
27 | await contract.removeAllListeners();
28 | return true;
29 | }
30 | return false;
31 | }
32 |
33 |
34 | public async startListeningForEventsFromActiveContracts() {
35 | const contracts = await this.contractService.getActiveContracts();
36 | for (let OptimisticContract of contracts) {
37 | const blockChainContract = new Contract(OptimisticContract.address, OptimisticContract.abi, this.provider);
38 | OptimisticContract.eventsToIndex.forEach(evt => {
39 | console.log("[%s] [Point to Point Indexer] => Running for Event: %s from Contract: %s, address: %s",
40 | new Date(Date.now()).toLocaleString(), evt.name, OptimisticContract.identifier, OptimisticContract.address)
41 | blockChainContract.on(evt.name, async (...args) => {
42 | console.log("[%s] [Point to Point Indexer]: Received event of type: %s from contract: %s",
43 | new Date(Date.now()).toLocaleString(), evt.name, OptimisticContract.identifier);
44 | let event: ethers.Event = args[args.length - 1];
45 | let timestamp = await this.chainService.getTimestamp(event.blockNumber);
46 | console.log("Transaction hash: %s Timestamp: %s", event.transactionHash, timestamp);
47 | await this.eventService.save({
48 | name: evt.name,
49 | transactionHash: event.transactionHash,
50 | contractAddress: OptimisticContract.address,
51 | savedBy: ReconcilerType.POINT,
52 | blockNumber: event.blockNumber,
53 | timestamp: timestamp,
54 | logIndex: event.logIndex,
55 | signature: event.eventSignature,
56 | args: EventReconciliationServiceImpl.getArgs(event.args!, evt.arguments)
57 | })
58 | });
59 | });
60 | this.contracts.set(OptimisticContract.identifier, blockChainContract);
61 | }
62 | }
63 | }
--------------------------------------------------------------------------------
/src/services/SweepingIndexerServiceImpl.ts:
--------------------------------------------------------------------------------
1 | import {OptimisticContract} from "../models/OptimisticContract";
2 | import {SweepingIndexerService} from "./interfaces/SweepingIndexerService";
3 | import {EventReconciliationServiceImpl} from "./EventReconciliationServiceImpl";
4 | import {ChainService} from "./interfaces/ChainService";
5 | import {EventService} from "./interfaces/EventService";
6 | import {Contract} from "ethers";
7 |
8 | export class SweepingIndexerServiceImpl implements SweepingIndexerService {
9 | constructor(private OptimisticContract: OptimisticContract, private contract: Contract, private eventService: EventService,
10 | private chainService: ChainService) {
11 | }
12 |
13 |
14 | async reconcilePastEvents(): Promise {
15 | for (let event of this.OptimisticContract.eventsToIndex) {
16 | const eventReconciliationService = new EventReconciliationServiceImpl(this.eventService, this.chainService,
17 | this.contract, this.OptimisticContract, event);
18 | await eventReconciliationService.reconcile();
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/src/services/interfaces/ChainService.ts:
--------------------------------------------------------------------------------
1 | export interface ChainService {
2 | getCurrentBlockNumber(): Promise;
3 |
4 | getTimestamp(blockNumber: number): Promise;
5 |
6 | getTimestampByHash(transactionHash: string): Promise;
7 | }
--------------------------------------------------------------------------------
/src/services/interfaces/EventReconciliationService.ts:
--------------------------------------------------------------------------------
1 | export interface EventReconciliationService {
2 | reconcile(): Promise;
3 | }
--------------------------------------------------------------------------------
/src/services/interfaces/EventService.ts:
--------------------------------------------------------------------------------
1 | import { OptimisticEventDBO } from "../../models/OptimisticEventDBO";
2 |
3 | export interface EventService {
4 | getLastBlockProcessedForEvent(
5 | contractIdentifier: string,
6 | eventName: string
7 | ): Promise;
8 |
9 | save(OptimisticEventDBO: OptimisticEventDBO): Promise;
10 |
11 | updateLastBlockProcessedForEvent(
12 | identifier: string,
13 | name: string,
14 | currentBlockNumber: number
15 | ): Promise;
16 | }
17 |
--------------------------------------------------------------------------------
/src/services/interfaces/IndexManager.ts:
--------------------------------------------------------------------------------
1 | export interface CollectionIndex {
2 | [key: string]: Index[]
3 | }
4 |
5 | export interface Index {
6 | name: string
7 | unique: boolean
8 | background: boolean
9 | spec: [IndexField]
10 | }
11 |
12 | export interface IndexField {
13 | [key: string]: -1 | 1 | 0
14 | }
15 |
16 | export interface IndexManager {
17 | ensureIndexes(collectionIndex: CollectionIndex): Promise>;
18 | }
--------------------------------------------------------------------------------
/src/services/interfaces/OptimisticContractService.ts:
--------------------------------------------------------------------------------
1 | import {OptimisticContract} from "../../models/OptimisticContract";
2 |
3 | export interface OptimisticContractService {
4 | save(contract: OptimisticContract): Promise;
5 |
6 | getContract(identifier: string): Promise;
7 |
8 | disableContract(identifier: string): Promise;
9 |
10 | getActiveContracts(): Promise>;
11 | }
--------------------------------------------------------------------------------
/src/services/interfaces/PointToPointIndexerService.ts:
--------------------------------------------------------------------------------
1 | export interface PointToPointIndexerService {
2 | disableContract(identifier: string): Promise;
3 |
4 | startListeningForEventsFromActiveContracts(): Promise;
5 | }
--------------------------------------------------------------------------------
/src/services/interfaces/SweepingIndexerService.ts:
--------------------------------------------------------------------------------
1 | export interface SweepingIndexerService {
2 | reconcilePastEvents(): Promise;
3 | }
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2016",
4 | "module": "commonjs",
5 | "outDir": "build",
6 | "moduleResolution": "Node",
7 | "strict": true,
8 | "esModuleInterop": true
9 | },
10 | "exclude": [
11 | "node_modules"
12 | ],
13 | "include": [
14 | "src/**/*"
15 | ]
16 | }
--------------------------------------------------------------------------------