diff --git a/packages/sushiswap-watcher/.eslintignore b/packages/sushiswap-watcher/.eslintignore new file mode 100644 index 0000000..55cb522 --- /dev/null +++ b/packages/sushiswap-watcher/.eslintignore @@ -0,0 +1,2 @@ +# Don't lint build output. +dist diff --git a/packages/sushiswap-watcher/.eslintrc.json b/packages/sushiswap-watcher/.eslintrc.json new file mode 100644 index 0000000..a2b842c --- /dev/null +++ b/packages/sushiswap-watcher/.eslintrc.json @@ -0,0 +1,28 @@ +{ + "env": { + "browser": true, + "es2021": true + }, + "extends": [ + "semistandard", + "plugin:@typescript-eslint/recommended" + ], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": 12, + "sourceType": "module" + }, + "plugins": [ + "@typescript-eslint" + ], + "rules": { + "indent": ["error", 2, { "SwitchCase": 1 }], + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/explicit-module-boundary-types": [ + "warn", + { + "allowArgumentsExplicitlyTypedAsAny": true + } + ] + } +} diff --git a/packages/sushiswap-watcher/.gitignore b/packages/sushiswap-watcher/.gitignore new file mode 100644 index 0000000..0b4cc3f --- /dev/null +++ b/packages/sushiswap-watcher/.gitignore @@ -0,0 +1,6 @@ +node_modules/ +dist/ +out/ + +.vscode +.idea diff --git a/packages/sushiswap-watcher/.husky/pre-commit b/packages/sushiswap-watcher/.husky/pre-commit new file mode 100755 index 0000000..9dcd433 --- /dev/null +++ b/packages/sushiswap-watcher/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +yarn lint diff --git a/packages/sushiswap-watcher/.npmrc b/packages/sushiswap-watcher/.npmrc new file mode 100644 index 0000000..6b64c5b --- /dev/null +++ b/packages/sushiswap-watcher/.npmrc @@ -0,0 +1 @@ +@cerc-io:registry=https://git.vdb.to/api/packages/cerc-io/npm/ diff --git a/packages/sushiswap-watcher/LICENSE b/packages/sushiswap-watcher/LICENSE new file mode 100644 index 0000000..331f7cf --- /dev/null +++ b/packages/sushiswap-watcher/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for + software and other kinds of works, specifically designed to ensure + cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed + to take away your freedom to share and change the works. By contrast, + our General Public Licenses are intended to guarantee your freedom to + share and change all versions of a program--to make sure it remains free + software for all its users. + + When we speak of free software, we are referring to freedom, not + price. Our General Public Licenses are designed to make sure that you + have the freedom to distribute copies of free software (and charge for + them if you wish), that you receive source code or can get it if you + want it, that you can change the software or use pieces of it in new + free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights + with two steps: (1) assert copyright on the software, and (2) offer + you this License which gives you legal permission to copy, distribute + and/or modify the software. + + A secondary benefit of defending all users' freedom is that + improvements made in alternate versions of the program, if they + receive widespread use, become available for other developers to + incorporate. Many developers of free software are heartened and + encouraged by the resulting cooperation. However, in the case of + software used on network servers, this result may fail to come about. + The GNU General Public License permits making a modified version and + letting the public access it on a server without ever releasing its + source code to the public. + + The GNU Affero General Public License is designed specifically to + ensure that, in such cases, the modified source code becomes available + to the community. It requires the operator of a network server to + provide the source code of the modified version running there to the + users of that server. Therefore, public use of a modified version, on + a publicly accessible server, gives the public access to the source + code of the modified version. + + An older license, called the Affero General Public License and + published by Affero, was designed to accomplish similar goals. This is + a different license, not a version of the Affero GPL, but Affero has + released a new version of the Affero GPL which permits relicensing under + this license. + + The precise terms and conditions for copying, distribution and + modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of + works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this + License. Each licensee is addressed as "you". "Licensees" and + "recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work + in a fashion requiring copyright permission, other than the making of an + exact copy. The resulting work is called a "modified version" of the + earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based + on the Program. + + To "propagate" a work means to do anything with it that, without + permission, would make you directly or secondarily liable for + infringement under applicable copyright law, except executing it on a + computer or modifying a private copy. Propagation includes copying, + distribution (with or without modification), making available to the + public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other + parties to make or receive copies. Mere interaction with a user through + a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" + to the extent that it includes a convenient and prominently visible + feature that (1) displays an appropriate copyright notice, and (2) + tells the user that there is no warranty for the work (except to the + extent that warranties are provided), that licensees may convey the + work under this License, and how to view a copy of this License. If + the interface presents a list of user commands or options, such as a + menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work + for making modifications to it. "Object code" means any non-source + form of a work. + + A "Standard Interface" means an interface that either is an official + standard defined by a recognized standards body, or, in the case of + interfaces specified for a particular programming language, one that + is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other + than the work as a whole, that (a) is included in the normal form of + packaging a Major Component, but which is not part of that Major + Component, and (b) serves only to enable use of the work with that + Major Component, or to implement a Standard Interface for which an + implementation is available to the public in source code form. A + "Major Component", in this context, means a major essential component + (kernel, window system, and so on) of the specific operating system + (if any) on which the executable work runs, or a compiler used to + produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all + the source code needed to generate, install, and (for an executable + work) run the object code and to modify the work, including scripts to + control those activities. However, it does not include the work's + System Libraries, or general-purpose tools or generally available free + programs which are used unmodified in performing those activities but + which are not part of the work. For example, Corresponding Source + includes interface definition files associated with source files for + the work, and the source code for shared libraries and dynamically + linked subprograms that the work is specifically designed to require, + such as by intimate data communication or control flow between those + subprograms and other parts of the work. + + The Corresponding Source need not include anything that users + can regenerate automatically from other parts of the Corresponding + Source. + + The Corresponding Source for a work in source code form is that + same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of + copyright on the Program, and are irrevocable provided the stated + conditions are met. This License explicitly affirms your unlimited + permission to run the unmodified Program. The output from running a + covered work is covered by this License only if the output, given its + content, constitutes a covered work. This License acknowledges your + rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not + convey, without conditions so long as your license otherwise remains + in force. You may convey covered works to others for the sole purpose + of having them make modifications exclusively for you, or provide you + with facilities for running those works, provided that you comply with + the terms of this License in conveying all material for which you do + not control copyright. Those thus making or running the covered works + for you must do so exclusively on your behalf, under your direction + and control, on terms that prohibit them from making any copies of + your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under + the conditions stated below. Sublicensing is not allowed; section 10 + makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological + measure under any applicable law fulfilling obligations under article + 11 of the WIPO copyright treaty adopted on 20 December 1996, or + similar laws prohibiting or restricting circumvention of such + measures. + + When you convey a covered work, you waive any legal power to forbid + circumvention of technological measures to the extent such circumvention + is effected by exercising rights under this License with respect to + the covered work, and you disclaim any intention to limit operation or + modification of the work as a means of enforcing, against the work's + users, your or third parties' legal rights to forbid circumvention of + technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you + receive it, in any medium, provided that you conspicuously and + appropriately publish on each copy an appropriate copyright notice; + keep intact all notices stating that this License and any + non-permissive terms added in accord with section 7 apply to the code; + keep intact all notices of the absence of any warranty; and give all + recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, + and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to + produce it from the Program, in the form of source code under the + terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent + works, which are not by their nature extensions of the covered work, + and which are not combined with it such as to form a larger program, + in or on a volume of a storage or distribution medium, is called an + "aggregate" if the compilation and its resulting copyright are not + used to limit the access or legal rights of the compilation's users + beyond what the individual works permit. Inclusion of a covered work + in an aggregate does not cause this License to apply to the other + parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms + of sections 4 and 5, provided that you also convey the + machine-readable Corresponding Source under the terms of this License, + in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded + from the Corresponding Source as a System Library, need not be + included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any + tangible personal property which is normally used for personal, family, + or household purposes, or (2) anything designed or sold for incorporation + into a dwelling. In determining whether a product is a consumer product, + doubtful cases shall be resolved in favor of coverage. For a particular + product received by a particular user, "normally used" refers to a + typical or common use of that class of product, regardless of the status + of the particular user or of the way in which the particular user + actually uses, or expects or is expected to use, the product. A product + is a consumer product regardless of whether the product has substantial + commercial, industrial or non-consumer uses, unless such uses represent + the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, + procedures, authorization keys, or other information required to install + and execute modified versions of a covered work in that User Product from + a modified version of its Corresponding Source. The information must + suffice to ensure that the continued functioning of the modified object + code is in no case prevented or interfered with solely because + modification has been made. + + If you convey an object code work under this section in, or with, or + specifically for use in, a User Product, and the conveying occurs as + part of a transaction in which the right of possession and use of the + User Product is transferred to the recipient in perpetuity or for a + fixed term (regardless of how the transaction is characterized), the + Corresponding Source conveyed under this section must be accompanied + by the Installation Information. But this requirement does not apply + if neither you nor any third party retains the ability to install + modified object code on the User Product (for example, the work has + been installed in ROM). + + The requirement to provide Installation Information does not include a + requirement to continue to provide support service, warranty, or updates + for a work that has been modified or installed by the recipient, or for + the User Product in which it has been modified or installed. Access to a + network may be denied when the modification itself materially and + adversely affects the operation of the network or violates the rules and + protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, + in accord with this section must be in a format that is publicly + documented (and with an implementation available to the public in + source code form), and must require no special password or key for + unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this + License by making exceptions from one or more of its conditions. + Additional permissions that are applicable to the entire Program shall + be treated as though they were included in this License, to the extent + that they are valid under applicable law. If additional permissions + apply only to part of the Program, that part may be used separately + under those permissions, but the entire Program remains governed by + this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option + remove any additional permissions from that copy, or from any part of + it. (Additional permissions may be written to require their own + removal in certain cases when you modify the work.) You may place + additional permissions on material, added by you to a covered work, + for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you + add to a covered work, you may (if authorized by the copyright holders of + that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further + restrictions" within the meaning of section 10. If the Program as you + received it, or any part of it, contains a notice stating that it is + governed by this License along with a term that is a further + restriction, you may remove that term. If a license document contains + a further restriction but permits relicensing or conveying under this + License, you may add to a covered work material governed by the terms + of that license document, provided that the further restriction does + not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you + must place, in the relevant source files, a statement of the + additional terms that apply to those files, or a notice indicating + where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the + form of a separately written license, or stated as exceptions; + the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly + provided under this License. Any attempt otherwise to propagate or + modify it is void, and will automatically terminate your rights under + this License (including any patent licenses granted under the third + paragraph of section 11). + + However, if you cease all violation of this License, then your + license from a particular copyright holder is reinstated (a) + provisionally, unless and until the copyright holder explicitly and + finally terminates your license, and (b) permanently, if the copyright + holder fails to notify you of the violation by some reasonable means + prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is + reinstated permanently if the copyright holder notifies you of the + violation by some reasonable means, this is the first time you have + received notice of violation of this License (for any work) from that + copyright holder, and you cure the violation prior to 30 days after + your receipt of the notice. + + Termination of your rights under this section does not terminate the + licenses of parties who have received copies or rights from you under + this License. If your rights have been terminated and not permanently + reinstated, you do not qualify to receive new licenses for the same + material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or + run a copy of the Program. Ancillary propagation of a covered work + occurring solely as a consequence of using peer-to-peer transmission + to receive a copy likewise does not require acceptance. However, + nothing other than this License grants you permission to propagate or + modify any covered work. These actions infringe copyright if you do + not accept this License. Therefore, by modifying or propagating a + covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically + receives a license from the original licensors, to run, modify and + propagate that work, subject to this License. You are not responsible + for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an + organization, or substantially all assets of one, or subdividing an + organization, or merging organizations. If propagation of a covered + work results from an entity transaction, each party to that + transaction who receives a copy of the work also receives whatever + licenses to the work the party's predecessor in interest had or could + give under the previous paragraph, plus a right to possession of the + Corresponding Source of the work from the predecessor in interest, if + the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the + rights granted or affirmed under this License. For example, you may + not impose a license fee, royalty, or other charge for exercise of + rights granted under this License, and you may not initiate litigation + (including a cross-claim or counterclaim in a lawsuit) alleging that + any patent claim is infringed by making, using, selling, offering for + sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this + License of the Program or a work on which the Program is based. The + work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims + owned or controlled by the contributor, whether already acquired or + hereafter acquired, that would be infringed by some manner, permitted + by this License, of making, using, or selling its contributor version, + but do not include claims that would be infringed only as a + consequence of further modification of the contributor version. For + purposes of this definition, "control" includes the right to grant + patent sublicenses in a manner consistent with the requirements of + this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free + patent license under the contributor's essential patent claims, to + make, use, sell, offer for sale, import and otherwise run, modify and + propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express + agreement or commitment, however denominated, not to enforce a patent + (such as an express permission to practice a patent or covenant not to + sue for patent infringement). To "grant" such a patent license to a + party means to make such an agreement or commitment not to enforce a + patent against the party. + + If you convey a covered work, knowingly relying on a patent license, + and the Corresponding Source of the work is not available for anyone + to copy, free of charge and under the terms of this License, through a + publicly available network server or other readily accessible means, + then you must either (1) cause the Corresponding Source to be so + available, or (2) arrange to deprive yourself of the benefit of the + patent license for this particular work, or (3) arrange, in a manner + consistent with the requirements of this License, to extend the patent + license to downstream recipients. "Knowingly relying" means you have + actual knowledge that, but for the patent license, your conveying the + covered work in a country, or your recipient's use of the covered work + in a country, would infringe one or more identifiable patents in that + country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or + arrangement, you convey, or propagate by procuring conveyance of, a + covered work, and grant a patent license to some of the parties + receiving the covered work authorizing them to use, propagate, modify + or convey a specific copy of the covered work, then the patent license + you grant is automatically extended to all recipients of the covered + work and works based on it. + + A patent license is "discriminatory" if it does not include within + the scope of its coverage, prohibits the exercise of, or is + conditioned on the non-exercise of one or more of the rights that are + specifically granted under this License. You may not convey a covered + work if you are a party to an arrangement with a third party that is + in the business of distributing software, under which you make payment + to the third party based on the extent of your activity of conveying + the work, and under which the third party grants, to any of the + parties who would receive the covered work from you, a discriminatory + patent license (a) in connection with copies of the covered work + conveyed by you (or copies made from those copies), or (b) primarily + for and in connection with specific products or compilations that + contain the covered work, unless you entered into that arrangement, + or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting + any implied license or other defenses to infringement that may + otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or + otherwise) that contradict the conditions of this License, they do not + excuse you from the conditions of this License. If you cannot convey a + covered work so as to satisfy simultaneously your obligations under this + License and any other pertinent obligations, then as a consequence you may + not convey it at all. For example, if you agree to terms that obligate you + to collect a royalty for further conveying from those to whom you convey + the Program, the only way you could satisfy both those terms and this + License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the + Program, your modified version must prominently offer all users + interacting with it remotely through a computer network (if your version + supports such interaction) an opportunity to receive the Corresponding + Source of your version by providing access to the Corresponding Source + from a network server at no charge, through some standard or customary + means of facilitating copying of software. This Corresponding Source + shall include the Corresponding Source for any work covered by version 3 + of the GNU General Public License that is incorporated pursuant to the + following paragraph. + + Notwithstanding any other provision of this License, you have + permission to link or combine any covered work with a work licensed + under version 3 of the GNU General Public License into a single + combined work, and to convey the resulting work. The terms of this + License will continue to apply to the part which is the covered work, + but the work with which it is combined will remain governed by version + 3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of + the GNU Affero General Public License from time to time. Such new versions + will be similar in spirit to the present version, but may differ in detail to + address new problems or concerns. + + Each version is given a distinguishing version number. If the + Program specifies that a certain numbered version of the GNU Affero General + Public License "or any later version" applies to it, you have the + option of following the terms and conditions either of that numbered + version or of any later version published by the Free Software + Foundation. If the Program does not specify a version number of the + GNU Affero General Public License, you may choose any version ever published + by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future + versions of the GNU Affero General Public License can be used, that proxy's + public statement of acceptance of a version permanently authorizes you + to choose that version for the Program. + + Later license versions may give you additional or different + permissions. However, no additional obligations are imposed on any + author or copyright holder as a result of your choosing to follow a + later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY + APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT + HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY + OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, + THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM + IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF + ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING + WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS + THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY + GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE + USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF + DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD + PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), + EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF + SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided + above cannot be given local legal effect according to their terms, + reviewing courts shall apply local law that most closely approximates + an absolute waiver of all civil liability in connection with the + Program, unless a warranty or assumption of liability accompanies a + copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest + possible use to the public, the best way to achieve this is to make it + free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest + to attach them to the start of each source file to most effectively + state the exclusion of warranty; and each file should have at least + the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer + network, you should also make sure that it provides a way for users to + get its source. For example, if your program is a web application, its + interface could display a "Source" link that leads users to an archive + of the code. There are many ways you could offer source, and different + solutions will be better for different programs; see section 13 for the + specific requirements. + + You should also get your employer (if you work as a programmer) or school, + if any, to sign a "copyright disclaimer" for the program, if necessary. + For more information on this, and how to apply and follow the GNU AGPL, see + . diff --git a/packages/sushiswap-watcher/README.md b/packages/sushiswap-watcher/README.md new file mode 100644 index 0000000..54edbbc --- /dev/null +++ b/packages/sushiswap-watcher/README.md @@ -0,0 +1,212 @@ +# sushiswap-watcher + +## Setup + +* Run the following command to install required packages: + + ```bash + yarn + ``` + +* Create a postgres12 database for the watcher: + + ```bash + sudo su - postgres + createdb sushiswap-watcher + ``` + +* If the watcher is an `active` watcher: + + Create database for the job queue and enable the `pgcrypto` extension on them (https://github.com/timgit/pg-boss/blob/master/docs/usage.md#intro): + + ``` + createdb sushiswap-watcher-job-queue + ``` + + ``` + postgres@tesla:~$ psql -U postgres -h localhost sushiswap-watcher-job-queue + Password for user postgres: + psql (12.7 (Ubuntu 12.7-1.pgdg18.04+1)) + SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off) + Type "help" for help. + + sushiswap-watcher-job-queue=# CREATE EXTENSION pgcrypto; + CREATE EXTENSION + sushiswap-watcher-job-queue=# exit + ``` + +* In the [config file](./environments/local.toml): + + * Update the database connection settings. + + * Update the `upstream` config and provide the `ipld-eth-server` GQL API endpoint. + + * Update the `server` config with state checkpoint settings. + +## Customize + +* Indexing on an event: + + * Edit the custom hook function `handleEvent` (triggered on an event) in [hooks.ts](./src/hooks.ts) to perform corresponding indexing using the `Indexer` object. + + * While using the indexer storage methods for indexing, pass `diff` as true if default state is desired to be generated using the state variables being indexed. + +* Generating state: + + * Edit the custom hook function `createInitialState` (triggered if the watcher passes the start block, checkpoint: `true`) in [hooks.ts](./src/hooks.ts) to save an initial `State` using the `Indexer` object. + + * Edit the custom hook function `createStateDiff` (triggered on a block) in [hooks.ts](./src/hooks.ts) to save the state in a `diff` `State` using the `Indexer` object. The default state (if exists) is updated. + + * Edit the custom hook function `createStateCheckpoint` (triggered just before default and CLI checkpoint) in [hooks.ts](./src/hooks.ts) to save the state in a `checkpoint` `State` using the `Indexer` object. + +### GQL Caching + +To enable GQL requests caching: + +* Update the `server.gql.cache` config with required settings. + +* In the GQL [schema file](./src/schema.gql), use the `cacheControl` directive to apply cache hints at schema level. + + * Eg. Set `inheritMaxAge` to true for non-scalar fields of a type. + +* In the GQL [resolvers file](./src/resolvers.ts), uncomment the `setGQLCacheHints()` calls in resolvers for required queries. + +## Run + +* If the watcher is a `lazy` watcher: + + * Run the server: + + ```bash + yarn server + ``` + + GQL console: http://localhost:3008/graphql + +* If the watcher is an `active` watcher: + + * Run the job-runner: + + ```bash + yarn job-runner + ``` + + * Run the server: + + ```bash + yarn server + ``` + + GQL console: http://localhost:3008/graphql + + * To watch a contract: + + ```bash + yarn watch:contract --address --kind --checkpoint --starting-block [block-number] + ``` + + * `address`: Address or identifier of the contract to be watched. + * `kind`: Kind of the contract. + * `checkpoint`: Turn checkpointing on (`true` | `false`). + * `starting-block`: Starting block for the contract (default: `1`). + + Examples: + + Watch a contract with its address and checkpointing on: + + ```bash + yarn watch:contract --address 0x1F78641644feB8b64642e833cE4AFE93DD6e7833 --kind ERC20 --checkpoint true + ``` + + Watch a contract with its identifier and checkpointing on: + + ```bash + yarn watch:contract --address MyProtocol --kind protocol --checkpoint true + ``` + + * To fill a block range: + + ```bash + yarn fill --start-block --end-block + ``` + + * `start-block`: Block number to start filling from. + * `end-block`: Block number till which to fill. + + * To create a checkpoint for a contract: + + ```bash + yarn checkpoint create --address --block-hash [block-hash] + ``` + + * `address`: Address or identifier of the contract for which to create a checkpoint. + * `block-hash`: Hash of a block (in the pruned region) at which to create the checkpoint (default: latest canonical block hash). + + * To verify a checkpoint: + + ```bash + yarn checkpoint verify --cid + ``` + + `cid`: CID of the checkpoint for which to verify. + + * To reset the watcher to a previous block number: + + * Reset watcher: + + ```bash + yarn reset watcher --block-number + ``` + + * Reset job-queue: + + ```bash + yarn reset job-queue + ``` + + * Reset state: + + ```bash + yarn reset state --block-number + ``` + + * `block-number`: Block number to which to reset the watcher. + + * To export and import the watcher state: + + * In source watcher, export watcher state: + + ```bash + yarn export-state --export-file [export-file-path] --block-number [snapshot-block-height] + ``` + + * `export-file`: Path of file to which to export the watcher data. + * `block-number`: Block height at which to take snapshot for export. + + * In target watcher, run job-runner: + + ```bash + yarn job-runner + ``` + + * Import watcher state: + + ```bash + yarn import-state --import-file + ``` + + * `import-file`: Path of file from which to import the watcher data. + + * Run server: + + ```bash + yarn server + ``` + + * To inspect a CID: + + ```bash + yarn inspect-cid --cid + ``` + + * `cid`: CID to be inspected. diff --git a/packages/sushiswap-watcher/environments/local.toml b/packages/sushiswap-watcher/environments/local.toml new file mode 100644 index 0000000..2ec6725 --- /dev/null +++ b/packages/sushiswap-watcher/environments/local.toml @@ -0,0 +1,109 @@ +[server] + host = "127.0.0.1" + port = 3008 + kind = "active" + + # Checkpointing state. + checkpointing = true + + # Checkpoint interval in number of blocks. + checkpointInterval = 2000 + + # Enable state creation + # CAUTION: Disable only if state creation is not desired or can be filled subsequently + enableState = true + + subgraphPath = "./subgraph-build" + + # Interval to restart wasm instance periodically + wasmRestartBlocksInterval = 20 + + # Interval in number of blocks at which to clear entities cache. + clearEntitiesCacheInterval = 1000 + + # Flag to specify whether RPC endpoint supports block hash as block tag parameter + rpcSupportsBlockHashParam = true + + # Server GQL config + [server.gql] + path = "/graphql" + + # Max block range for which to return events in eventsInRange GQL query. + # Use -1 for skipping check on block range. + maxEventsBlockRange = 1000 + + # Log directory for GQL requests + logDir = "./gql-logs" + + # GQL cache settings + [server.gql.cache] + enabled = true + + # Max in-memory cache size (in bytes) (default 8 MB) + # maxCacheSize + + # GQL cache-control max-age settings (in seconds) + maxAge = 15 + timeTravelMaxAge = 86400 # 1 day + +[metrics] + host = "127.0.0.1" + port = 9000 + [metrics.gql] + port = 9001 + +[database] + type = "postgres" + host = "localhost" + port = 5432 + database = "sushiswap-watcher" + username = "postgres" + password = "postgres" + synchronize = true + logging = false + +[upstream] + [upstream.ethServer] + gqlApiEndpoint = "http://127.0.0.1:8082/graphql" + rpcProviderEndpoints = [ + "http://127.0.0.1:8081" + ] + + # Boolean flag to specify if rpc-eth-client should be used for RPC endpoint instead of ipld-eth-client (ipld-eth-server GQL client) + rpcClient = false + + # Boolean flag to specify if rpcProviderEndpoint is an FEVM RPC endpoint + isFEVM = false + + # Boolean flag to filter event logs by contracts + filterLogsByAddresses = true + # Boolean flag to filter event logs by topics + filterLogsByTopics = true + + [upstream.cache] + name = "requests" + enabled = false + deleteOnStart = false + +[jobQueue] + dbConnectionString = "postgres://postgres:postgres@localhost/sushiswap-watcher-job-queue" + maxCompletionLagInSecs = 300 + jobDelayInMilliSecs = 100 + eventsInBatch = 50 + subgraphEventsOrder = true + blockDelayInMilliSecs = 2000 + + # Boolean to switch between modes of processing events when starting the server. + # Setting to true will fetch filtered events and required blocks in a range of blocks and then process them. + # Setting to false will fetch blocks consecutively with its events and then process them (Behaviour is followed in realtime processing near head). + useBlockRanges = true + + # Block range in which logs are fetched during historical blocks processing + historicalLogsBlockRange = 2000 + + # Max block range of historical processing after which it waits for completion of events processing + # If set to -1 historical processing does not wait for events processing and completes till latest canonical block + historicalMaxFetchAhead = 10000 + + # Max number of retries to fetch new block after which watcher will failover to other RPC endpoints + maxNewBlockRetries = 3 diff --git a/packages/sushiswap-watcher/gql-logs/watcher-gql-error.log b/packages/sushiswap-watcher/gql-logs/watcher-gql-error.log new file mode 100644 index 0000000..e69de29 diff --git a/packages/sushiswap-watcher/gql-logs/watcher-gql.log b/packages/sushiswap-watcher/gql-logs/watcher-gql.log new file mode 100644 index 0000000..e69de29 diff --git a/packages/sushiswap-watcher/package.json b/packages/sushiswap-watcher/package.json new file mode 100644 index 0000000..d7c5689 --- /dev/null +++ b/packages/sushiswap-watcher/package.json @@ -0,0 +1,76 @@ +{ + "name": "@cerc-io/sushiswap-watcher", + "version": "0.1.0", + "description": "sushiswap-watcher", + "private": true, + "main": "dist/index.js", + "scripts": { + "lint": "eslint --max-warnings=0 .", + "build": "yarn clean && tsc && yarn copy-assets", + "clean": "rm -rf ./dist", + "prepare": "husky install", + "copy-assets": "copyfiles -u 1 src/**/*.gql dist/", + "server": "DEBUG=vulcanize:* YARN_CHILD_PROCESS=true node --enable-source-maps dist/server.js", + "server:dev": "DEBUG=vulcanize:* YARN_CHILD_PROCESS=true ts-node src/server.ts", + "job-runner": "DEBUG=vulcanize:* YARN_CHILD_PROCESS=true node --enable-source-maps dist/job-runner.js", + "job-runner:dev": "DEBUG=vulcanize:* YARN_CHILD_PROCESS=true ts-node src/job-runner.ts", + "watch:contract": "DEBUG=vulcanize:* ts-node src/cli/watch-contract.ts", + "fill": "DEBUG=vulcanize:* ts-node src/fill.ts", + "fill:state": "DEBUG=vulcanize:* ts-node src/fill.ts --state", + "reset": "DEBUG=vulcanize:* ts-node src/cli/reset.ts", + "checkpoint": "DEBUG=vulcanize:* node --enable-source-maps dist/cli/checkpoint.js", + "checkpoint:dev": "DEBUG=vulcanize:* ts-node src/cli/checkpoint.ts", + "export-state": "DEBUG=vulcanize:* node --enable-source-maps dist/cli/export-state.js", + "export-state:dev": "DEBUG=vulcanize:* ts-node src/cli/export-state.ts", + "import-state": "DEBUG=vulcanize:* node --enable-source-maps dist/cli/import-state.js", + "import-state:dev": "DEBUG=vulcanize:* ts-node src/cli/import-state.ts", + "inspect-cid": "DEBUG=vulcanize:* ts-node src/cli/inspect-cid.ts", + "index-block": "DEBUG=vulcanize:* ts-node src/cli/index-block.ts" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/cerc-io/watcher-ts.git" + }, + "author": "", + "license": "AGPL-3.0", + "bugs": { + "url": "https://github.com/cerc-io/watcher-ts/issues" + }, + "homepage": "https://github.com/cerc-io/watcher-ts#readme", + "dependencies": { + "@apollo/client": "^3.3.19", + "@cerc-io/cli": "^0.2.93", + "@cerc-io/ipld-eth-client": "^0.2.93", + "@cerc-io/solidity-mapper": "^0.2.93", + "@cerc-io/util": "^0.2.93", + "@cerc-io/graph-node": "^0.2.93", + "@ethersproject/providers": "^5.4.4", + "debug": "^4.3.1", + "decimal.js": "^10.3.1", + "ethers": "^5.4.4", + "graphql": "^15.5.0", + "json-bigint": "^1.0.0", + "reflect-metadata": "^0.1.13", + "typeorm": "0.2.37", + "yargs": "^17.0.1" + }, + "devDependencies": { + "@ethersproject/abi": "^5.3.0", + "@types/debug": "^4.1.5", + "@types/json-bigint": "^1.0.0", + "@types/yargs": "^17.0.0", + "@typescript-eslint/eslint-plugin": "^5.47.1", + "@typescript-eslint/parser": "^5.47.1", + "copyfiles": "^2.4.1", + "eslint": "^8.35.0", + "eslint-config-semistandard": "^15.0.1", + "eslint-config-standard": "^16.0.3", + "eslint-plugin-import": "^2.27.5", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-promise": "^5.1.0", + "eslint-plugin-standard": "^5.0.0", + "husky": "^7.0.2", + "ts-node": "^10.2.1", + "typescript": "^5.0.2" + } +} diff --git a/packages/sushiswap-watcher/src/artifacts/Factory.json b/packages/sushiswap-watcher/src/artifacts/Factory.json new file mode 100644 index 0000000..244820a --- /dev/null +++ b/packages/sushiswap-watcher/src/artifacts/Factory.json @@ -0,0 +1,217 @@ +{ + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_feeToSetter", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "token0", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "token1", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "pair", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "PairCreated", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "allPairs", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "allPairsLength", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenA", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenB", + "type": "address" + } + ], + "name": "createPair", + "outputs": [ + { + "internalType": "address", + "name": "pair", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "feeTo", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "feeToSetter", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "getPair", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "migrator", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pairCodeHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_feeTo", + "type": "address" + } + ], + "name": "setFeeTo", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_feeToSetter", + "type": "address" + } + ], + "name": "setFeeToSetter", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_migrator", + "type": "address" + } + ], + "name": "setMigrator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ] +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/artifacts/Pair.json b/packages/sushiswap-watcher/src/artifacts/Pair.json new file mode 100644 index 0000000..26f7c8c --- /dev/null +++ b/packages/sushiswap-watcher/src/artifacts/Pair.json @@ -0,0 +1,660 @@ +{ + "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": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + } + ], + "name": "Burn", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount0In", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount1In", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount0Out", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount1Out", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + } + ], + "name": "Swap", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint112", + "name": "reserve0", + "type": "uint112" + }, + { + "indexed": false, + "internalType": "uint112", + "name": "reserve1", + "type": "uint112" + } + ], + "name": "Sync", + "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": [], + "name": "MINIMUM_LIQUIDITY", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "PERMIT_TYPEHASH", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + } + ], + "name": "burn", + "outputs": [ + { + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "factory", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getReserves", + "outputs": [ + { + "internalType": "uint112", + "name": "_reserve0", + "type": "uint112" + }, + { + "internalType": "uint112", + "name": "_reserve1", + "type": "uint112" + }, + { + "internalType": "uint32", + "name": "_blockTimestampLast", + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token0", + "type": "address" + }, + { + "internalType": "address", + "name": "_token1", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "kLast", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + } + ], + "name": "mint", + "outputs": [ + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "nonces", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "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": "price0CumulativeLast", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "price1CumulativeLast", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + } + ], + "name": "skim", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount0Out", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount1Out", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "swap", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "sync", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "token0", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "token1", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "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": "value", + "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": "value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ] +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/cli/checkpoint-cmds/create.ts b/packages/sushiswap-watcher/src/cli/checkpoint-cmds/create.ts new file mode 100644 index 0000000..e771c70 --- /dev/null +++ b/packages/sushiswap-watcher/src/cli/checkpoint-cmds/create.ts @@ -0,0 +1,44 @@ +// +// Copyright 2022 Vulcanize, Inc. +// + +import { CreateCheckpointCmd } from '@cerc-io/cli'; +import { getGraphDbAndWatcher } from '@cerc-io/graph-node'; + +import { Database, ENTITY_QUERY_TYPE_MAP, ENTITY_TO_LATEST_ENTITY_MAP } from '../../database'; +import { Indexer } from '../../indexer'; + +export const command = 'create'; + +export const desc = 'Create checkpoint'; + +export const builder = { + address: { + type: 'string', + require: true, + demandOption: true, + describe: 'Contract address to create the checkpoint for.' + }, + blockHash: { + type: 'string', + describe: 'Blockhash at which to create the checkpoint.' + } +}; + +export const handler = async (argv: any): Promise => { + const createCheckpointCmd = new CreateCheckpointCmd(); + await createCheckpointCmd.init(argv, Database); + + const { graphWatcher } = await getGraphDbAndWatcher( + createCheckpointCmd.config.server, + createCheckpointCmd.clients.ethClient, + createCheckpointCmd.ethProvider, + createCheckpointCmd.database.baseDatabase, + ENTITY_QUERY_TYPE_MAP, + ENTITY_TO_LATEST_ENTITY_MAP + ); + + await createCheckpointCmd.initIndexer(Indexer, graphWatcher); + + await createCheckpointCmd.exec(); +}; diff --git a/packages/sushiswap-watcher/src/cli/checkpoint-cmds/verify.ts b/packages/sushiswap-watcher/src/cli/checkpoint-cmds/verify.ts new file mode 100644 index 0000000..3709f54 --- /dev/null +++ b/packages/sushiswap-watcher/src/cli/checkpoint-cmds/verify.ts @@ -0,0 +1,40 @@ +// +// Copyright 2022 Vulcanize, Inc. +// + +import { VerifyCheckpointCmd } from '@cerc-io/cli'; +import { getGraphDbAndWatcher } from '@cerc-io/graph-node'; + +import { Database, ENTITY_QUERY_TYPE_MAP, ENTITY_TO_LATEST_ENTITY_MAP } from '../../database'; +import { Indexer } from '../../indexer'; + +export const command = 'verify'; + +export const desc = 'Verify checkpoint'; + +export const builder = { + cid: { + type: 'string', + alias: 'c', + demandOption: true, + describe: 'Checkpoint CID to be verified' + } +}; + +export const handler = async (argv: any): Promise => { + const verifyCheckpointCmd = new VerifyCheckpointCmd(); + await verifyCheckpointCmd.init(argv, Database); + + const { graphWatcher, graphDb } = await getGraphDbAndWatcher( + verifyCheckpointCmd.config.server, + verifyCheckpointCmd.clients.ethClient, + verifyCheckpointCmd.ethProvider, + verifyCheckpointCmd.database.baseDatabase, + ENTITY_QUERY_TYPE_MAP, + ENTITY_TO_LATEST_ENTITY_MAP + ); + + await verifyCheckpointCmd.initIndexer(Indexer, graphWatcher); + + await verifyCheckpointCmd.exec(graphDb); +}; diff --git a/packages/sushiswap-watcher/src/cli/checkpoint.ts b/packages/sushiswap-watcher/src/cli/checkpoint.ts new file mode 100644 index 0000000..d05ad8a --- /dev/null +++ b/packages/sushiswap-watcher/src/cli/checkpoint.ts @@ -0,0 +1,39 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import yargs from 'yargs'; +import 'reflect-metadata'; +import debug from 'debug'; + +import { DEFAULT_CONFIG_PATH } from '@cerc-io/util'; + +import { hideBin } from 'yargs/helpers'; + +const log = debug('vulcanize:checkpoint'); + +const main = async () => { + return yargs(hideBin(process.argv)) + .parserConfiguration({ + 'parse-numbers': false + }).options({ + configFile: { + alias: 'f', + type: 'string', + require: true, + demandOption: true, + describe: 'configuration file path (toml)', + default: DEFAULT_CONFIG_PATH + } + }) + .commandDir('checkpoint-cmds', { extensions: ['ts', 'js'], exclude: /([a-zA-Z0-9\s_\\.\-:])+(.d.ts)$/ }) + .demandCommand(1) + .help() + .argv; +}; + +main().then(() => { + process.exit(); +}).catch(err => { + log(err); +}); diff --git a/packages/sushiswap-watcher/src/cli/export-state.ts b/packages/sushiswap-watcher/src/cli/export-state.ts new file mode 100644 index 0000000..bcd1c8a --- /dev/null +++ b/packages/sushiswap-watcher/src/cli/export-state.ts @@ -0,0 +1,38 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import 'reflect-metadata'; +import debug from 'debug'; + +import { ExportStateCmd } from '@cerc-io/cli'; +import { getGraphDbAndWatcher } from '@cerc-io/graph-node'; + +import { Database, ENTITY_QUERY_TYPE_MAP, ENTITY_TO_LATEST_ENTITY_MAP } from '../database'; +import { Indexer } from '../indexer'; + +const log = debug('vulcanize:export-state'); + +const main = async (): Promise => { + const exportStateCmd = new ExportStateCmd(); + await exportStateCmd.init(Database); + + const { graphWatcher } = await getGraphDbAndWatcher( + exportStateCmd.config.server, + exportStateCmd.clients.ethClient, + exportStateCmd.ethProvider, + exportStateCmd.database.baseDatabase, + ENTITY_QUERY_TYPE_MAP, + ENTITY_TO_LATEST_ENTITY_MAP + ); + + await exportStateCmd.initIndexer(Indexer, graphWatcher); + + await exportStateCmd.exec(); +}; + +main().catch(err => { + log(err); +}).finally(() => { + process.exit(0); +}); diff --git a/packages/sushiswap-watcher/src/cli/import-state.ts b/packages/sushiswap-watcher/src/cli/import-state.ts new file mode 100644 index 0000000..04ce0e8 --- /dev/null +++ b/packages/sushiswap-watcher/src/cli/import-state.ts @@ -0,0 +1,39 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import 'reflect-metadata'; +import debug from 'debug'; + +import { ImportStateCmd } from '@cerc-io/cli'; +import { getGraphDbAndWatcher } from '@cerc-io/graph-node'; + +import { Database, ENTITY_QUERY_TYPE_MAP, ENTITY_TO_LATEST_ENTITY_MAP } from '../database'; +import { Indexer } from '../indexer'; +import { State } from '../entity/State'; + +const log = debug('vulcanize:import-state'); + +export const main = async (): Promise => { + const importStateCmd = new ImportStateCmd(); + await importStateCmd.init(Database); + + const { graphWatcher, graphDb } = await getGraphDbAndWatcher( + importStateCmd.config.server, + importStateCmd.clients.ethClient, + importStateCmd.ethProvider, + importStateCmd.database.baseDatabase, + ENTITY_QUERY_TYPE_MAP, + ENTITY_TO_LATEST_ENTITY_MAP + ); + + await importStateCmd.initIndexer(Indexer, graphWatcher); + + await importStateCmd.exec(State, graphDb); +}; + +main().catch(err => { + log(err); +}).finally(() => { + process.exit(0); +}); diff --git a/packages/sushiswap-watcher/src/cli/index-block.ts b/packages/sushiswap-watcher/src/cli/index-block.ts new file mode 100644 index 0000000..19a302a --- /dev/null +++ b/packages/sushiswap-watcher/src/cli/index-block.ts @@ -0,0 +1,38 @@ +// +// Copyright 2022 Vulcanize, Inc. +// + +import 'reflect-metadata'; +import debug from 'debug'; + +import { IndexBlockCmd } from '@cerc-io/cli'; +import { getGraphDbAndWatcher } from '@cerc-io/graph-node'; + +import { Database, ENTITY_QUERY_TYPE_MAP, ENTITY_TO_LATEST_ENTITY_MAP } from '../database'; +import { Indexer } from '../indexer'; + +const log = debug('vulcanize:index-block'); + +const main = async (): Promise => { + const indexBlockCmd = new IndexBlockCmd(); + await indexBlockCmd.init(Database); + + const { graphWatcher } = await getGraphDbAndWatcher( + indexBlockCmd.config.server, + indexBlockCmd.clients.ethClient, + indexBlockCmd.ethProvider, + indexBlockCmd.database.baseDatabase, + ENTITY_QUERY_TYPE_MAP, + ENTITY_TO_LATEST_ENTITY_MAP + ); + + await indexBlockCmd.initIndexer(Indexer, graphWatcher); + + await indexBlockCmd.exec(); +}; + +main().catch(err => { + log(err); +}).finally(() => { + process.exit(0); +}); diff --git a/packages/sushiswap-watcher/src/cli/inspect-cid.ts b/packages/sushiswap-watcher/src/cli/inspect-cid.ts new file mode 100644 index 0000000..4f5955e --- /dev/null +++ b/packages/sushiswap-watcher/src/cli/inspect-cid.ts @@ -0,0 +1,38 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import 'reflect-metadata'; +import debug from 'debug'; + +import { InspectCIDCmd } from '@cerc-io/cli'; +import { getGraphDbAndWatcher } from '@cerc-io/graph-node'; + +import { Database, ENTITY_QUERY_TYPE_MAP, ENTITY_TO_LATEST_ENTITY_MAP } from '../database'; +import { Indexer } from '../indexer'; + +const log = debug('vulcanize:inspect-cid'); + +const main = async (): Promise => { + const inspectCIDCmd = new InspectCIDCmd(); + await inspectCIDCmd.init(Database); + + const { graphWatcher } = await getGraphDbAndWatcher( + inspectCIDCmd.config.server, + inspectCIDCmd.clients.ethClient, + inspectCIDCmd.ethProvider, + inspectCIDCmd.database.baseDatabase, + ENTITY_QUERY_TYPE_MAP, + ENTITY_TO_LATEST_ENTITY_MAP + ); + + await inspectCIDCmd.initIndexer(Indexer, graphWatcher); + + await inspectCIDCmd.exec(); +}; + +main().catch(err => { + log(err); +}).finally(() => { + process.exit(0); +}); diff --git a/packages/sushiswap-watcher/src/cli/reset-cmds/job-queue.ts b/packages/sushiswap-watcher/src/cli/reset-cmds/job-queue.ts new file mode 100644 index 0000000..c33cbfd --- /dev/null +++ b/packages/sushiswap-watcher/src/cli/reset-cmds/job-queue.ts @@ -0,0 +1,22 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import debug from 'debug'; + +import { getConfig, resetJobs, Config } from '@cerc-io/util'; + +const log = debug('vulcanize:reset-job-queue'); + +export const command = 'job-queue'; + +export const desc = 'Reset job queue'; + +export const builder = {}; + +export const handler = async (argv: any): Promise => { + const config: Config = await getConfig(argv.configFile); + await resetJobs(config); + + log('Job queue reset successfully'); +}; diff --git a/packages/sushiswap-watcher/src/cli/reset-cmds/state.ts b/packages/sushiswap-watcher/src/cli/reset-cmds/state.ts new file mode 100644 index 0000000..33211d6 --- /dev/null +++ b/packages/sushiswap-watcher/src/cli/reset-cmds/state.ts @@ -0,0 +1,24 @@ +// +// Copyright 2022 Vulcanize, Inc. +// + +import { ResetStateCmd } from '@cerc-io/cli'; + +import { Database } from '../../database'; + +export const command = 'state'; + +export const desc = 'Reset State to a given block number'; + +export const builder = { + blockNumber: { + type: 'number' + } +}; + +export const handler = async (argv: any): Promise => { + const resetStateCmd = new ResetStateCmd(); + await resetStateCmd.init(argv, Database); + + await resetStateCmd.exec(); +}; diff --git a/packages/sushiswap-watcher/src/cli/reset-cmds/watcher.ts b/packages/sushiswap-watcher/src/cli/reset-cmds/watcher.ts new file mode 100644 index 0000000..827fd28 --- /dev/null +++ b/packages/sushiswap-watcher/src/cli/reset-cmds/watcher.ts @@ -0,0 +1,37 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import { ResetWatcherCmd } from '@cerc-io/cli'; +import { getGraphDbAndWatcher } from '@cerc-io/graph-node'; + +import { Database, ENTITY_QUERY_TYPE_MAP, ENTITY_TO_LATEST_ENTITY_MAP } from '../../database'; +import { Indexer } from '../../indexer'; + +export const command = 'watcher'; + +export const desc = 'Reset watcher to a block number'; + +export const builder = { + blockNumber: { + type: 'number' + } +}; + +export const handler = async (argv: any): Promise => { + const resetWatcherCmd = new ResetWatcherCmd(); + await resetWatcherCmd.init(argv, Database); + + const { graphWatcher } = await getGraphDbAndWatcher( + resetWatcherCmd.config.server, + resetWatcherCmd.clients.ethClient, + resetWatcherCmd.ethProvider, + resetWatcherCmd.database.baseDatabase, + ENTITY_QUERY_TYPE_MAP, + ENTITY_TO_LATEST_ENTITY_MAP + ); + + await resetWatcherCmd.initIndexer(Indexer, graphWatcher); + + await resetWatcherCmd.exec(); +}; diff --git a/packages/sushiswap-watcher/src/cli/reset.ts b/packages/sushiswap-watcher/src/cli/reset.ts new file mode 100644 index 0000000..95648c8 --- /dev/null +++ b/packages/sushiswap-watcher/src/cli/reset.ts @@ -0,0 +1,24 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import 'reflect-metadata'; +import debug from 'debug'; + +import { getResetYargs } from '@cerc-io/util'; + +const log = debug('vulcanize:reset'); + +const main = async () => { + return getResetYargs() + .commandDir('reset-cmds', { extensions: ['ts', 'js'], exclude: /([a-zA-Z0-9\s_\\.\-:])+(.d.ts)$/ }) + .demandCommand(1) + .help() + .argv; +}; + +main().then(() => { + process.exit(); +}).catch(err => { + log(err); +}); diff --git a/packages/sushiswap-watcher/src/cli/watch-contract.ts b/packages/sushiswap-watcher/src/cli/watch-contract.ts new file mode 100644 index 0000000..7d6ce1a --- /dev/null +++ b/packages/sushiswap-watcher/src/cli/watch-contract.ts @@ -0,0 +1,38 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import 'reflect-metadata'; +import debug from 'debug'; + +import { WatchContractCmd } from '@cerc-io/cli'; +import { getGraphDbAndWatcher } from '@cerc-io/graph-node'; + +import { Database, ENTITY_QUERY_TYPE_MAP, ENTITY_TO_LATEST_ENTITY_MAP } from '../database'; +import { Indexer } from '../indexer'; + +const log = debug('vulcanize:watch-contract'); + +const main = async (): Promise => { + const watchContractCmd = new WatchContractCmd(); + await watchContractCmd.init(Database); + + const { graphWatcher } = await getGraphDbAndWatcher( + watchContractCmd.config.server, + watchContractCmd.clients.ethClient, + watchContractCmd.ethProvider, + watchContractCmd.database.baseDatabase, + ENTITY_QUERY_TYPE_MAP, + ENTITY_TO_LATEST_ENTITY_MAP + ); + + await watchContractCmd.initIndexer(Indexer, graphWatcher); + + await watchContractCmd.exec(); +}; + +main().catch(err => { + log(err); +}).finally(() => { + process.exit(0); +}); diff --git a/packages/sushiswap-watcher/src/client.ts b/packages/sushiswap-watcher/src/client.ts new file mode 100644 index 0000000..8bb2bb0 --- /dev/null +++ b/packages/sushiswap-watcher/src/client.ts @@ -0,0 +1,55 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import { gql } from '@apollo/client/core'; +import { GraphQLClient, GraphQLConfig } from '@cerc-io/ipld-eth-client'; + +import { queries, mutations, subscriptions } from './gql'; + +export class Client { + _config: GraphQLConfig; + _client: GraphQLClient; + + constructor (config: GraphQLConfig) { + this._config = config; + + this._client = new GraphQLClient(config); + } + + async getEvents (blockHash: string, contractAddress: string, name: string): Promise { + const { events } = await this._client.query( + gql(queries.events), + { blockHash, contractAddress, name } + ); + + return events; + } + + async getEventsInRange (fromBlockNumber: number, toBlockNumber: number): Promise { + const { eventsInRange } = await this._client.query( + gql(queries.eventsInRange), + { fromBlockNumber, toBlockNumber } + ); + + return eventsInRange; + } + + async watchContract (contractAddress: string, startingBlock?: number): Promise { + const { watchContract } = await this._client.mutate( + gql(mutations.watchContract), + { contractAddress, startingBlock } + ); + + return watchContract; + } + + async watchEvents (onNext: (value: any) => void): Promise { + return this._client.subscribe( + gql(subscriptions.onEvent), + ({ data }) => { + onNext(data.onEvent); + } + ); + } +} diff --git a/packages/sushiswap-watcher/src/database.ts b/packages/sushiswap-watcher/src/database.ts new file mode 100644 index 0000000..05ef00e --- /dev/null +++ b/packages/sushiswap-watcher/src/database.ts @@ -0,0 +1,304 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import assert from 'assert'; +import { Connection, ConnectionOptions, DeepPartial, FindConditions, QueryRunner, FindManyOptions, EntityTarget } from 'typeorm'; +import path from 'path'; + +import { + ENTITY_QUERY_TYPE, + Database as BaseDatabase, + DatabaseInterface, + QueryOptions, + StateKind, + Where +} from '@cerc-io/util'; + +import { Contract } from './entity/Contract'; +import { Event } from './entity/Event'; +import { SyncStatus } from './entity/SyncStatus'; +import { StateSyncStatus } from './entity/StateSyncStatus'; +import { BlockProgress } from './entity/BlockProgress'; +import { State } from './entity/State'; +import { Factory } from './entity/Factory'; +import { Bundle } from './entity/Bundle'; +import { Token } from './entity/Token'; +import { TokenPrice } from './entity/TokenPrice'; +import { _TokenPair } from './entity/_TokenPair'; +import { _WhitelistedTokenPair } from './entity/_WhitelistedTokenPair'; +import { Pair } from './entity/Pair'; +import { User } from './entity/User'; +import { LiquidityPosition } from './entity/LiquidityPosition'; +import { Mint } from './entity/Mint'; +import { Burn } from './entity/Burn'; +import { Swap } from './entity/Swap'; +import { Transaction } from './entity/Transaction'; +import { LiquidityPositionSnapshot } from './entity/LiquidityPositionSnapshot'; +import { PairHourSnapshot } from './entity/PairHourSnapshot'; +import { PairDaySnapshot } from './entity/PairDaySnapshot'; +import { TokenHourSnapshot } from './entity/TokenHourSnapshot'; +import { TokenDaySnapshot } from './entity/TokenDaySnapshot'; +import { FactoryHourSnapshot } from './entity/FactoryHourSnapshot'; +import { FactoryDaySnapshot } from './entity/FactoryDaySnapshot'; + +export const SUBGRAPH_ENTITIES = new Set([Factory, Bundle, Token, TokenPrice, _TokenPair, _WhitelistedTokenPair, Pair, User, LiquidityPosition, Mint, Burn, Swap, Transaction, LiquidityPositionSnapshot, PairHourSnapshot, PairDaySnapshot, TokenHourSnapshot, TokenDaySnapshot, FactoryHourSnapshot, FactoryDaySnapshot]); +export const ENTITIES = [...SUBGRAPH_ENTITIES]; +// Map: Entity to suitable query type. +export const ENTITY_QUERY_TYPE_MAP = new Map any, ENTITY_QUERY_TYPE>([]); + +export const ENTITY_TO_LATEST_ENTITY_MAP: Map = new Map(); + +export class Database implements DatabaseInterface { + _config: ConnectionOptions; + _conn!: Connection; + _baseDatabase: BaseDatabase; + _propColMaps: { [key: string]: Map; }; + + constructor (config: ConnectionOptions) { + assert(config); + + this._config = { + ...config, + subscribers: [path.join(__dirname, 'entity/Subscriber.*')], + entities: [path.join(__dirname, 'entity/*')] + }; + + this._baseDatabase = new BaseDatabase(this._config); + this._propColMaps = {}; + } + + get baseDatabase (): BaseDatabase { + return this._baseDatabase; + } + + async init (): Promise { + this._conn = await this._baseDatabase.init(); + } + + async close (): Promise { + return this._baseDatabase.close(); + } + + getNewState (): State { + return new State(); + } + + async getStates (where: FindConditions): Promise { + const repo = this._conn.getRepository(State); + + return this._baseDatabase.getStates(repo, where); + } + + async getLatestState (contractAddress: string, kind: StateKind | null, blockNumber?: number): Promise { + const repo = this._conn.getRepository(State); + + return this._baseDatabase.getLatestState(repo, contractAddress, kind, blockNumber); + } + + async getPrevState (blockHash: string, contractAddress: string, kind?: string): Promise { + const repo = this._conn.getRepository(State); + + return this._baseDatabase.getPrevState(repo, blockHash, contractAddress, kind); + } + + // Fetch all diff States after the specified block number. + async getDiffStatesInRange (contractAddress: string, startblock: number, endBlock: number): Promise { + const repo = this._conn.getRepository(State); + + return this._baseDatabase.getDiffStatesInRange(repo, contractAddress, startblock, endBlock); + } + + async saveOrUpdateState (dbTx: QueryRunner, state: State): Promise { + const repo = dbTx.manager.getRepository(State); + + return this._baseDatabase.saveOrUpdateState(repo, state); + } + + async removeStates (dbTx: QueryRunner, blockNumber: number, kind: string): Promise { + const repo = dbTx.manager.getRepository(State); + + await this._baseDatabase.removeStates(repo, blockNumber, kind); + } + + async removeStatesAfterBlock (dbTx: QueryRunner, blockNumber: number): Promise { + const repo = dbTx.manager.getRepository(State); + + await this._baseDatabase.removeStatesAfterBlock(repo, blockNumber); + } + + async getStateSyncStatus (): Promise { + const repo = this._conn.getRepository(StateSyncStatus); + + return this._baseDatabase.getStateSyncStatus(repo); + } + + async updateStateSyncStatusIndexedBlock (queryRunner: QueryRunner, blockNumber: number, force?: boolean): Promise { + const repo = queryRunner.manager.getRepository(StateSyncStatus); + + return this._baseDatabase.updateStateSyncStatusIndexedBlock(repo, blockNumber, force); + } + + async updateStateSyncStatusCheckpointBlock (queryRunner: QueryRunner, blockNumber: number, force?: boolean): Promise { + const repo = queryRunner.manager.getRepository(StateSyncStatus); + + return this._baseDatabase.updateStateSyncStatusCheckpointBlock(repo, blockNumber, force); + } + + async getContracts (): Promise { + const repo = this._conn.getRepository(Contract); + + return this._baseDatabase.getContracts(repo); + } + + async createTransactionRunner (): Promise { + return this._baseDatabase.createTransactionRunner(); + } + + async getProcessedBlockCountForRange (fromBlockNumber: number, toBlockNumber: number): Promise<{ expected: number, actual: number }> { + const repo = this._conn.getRepository(BlockProgress); + + return this._baseDatabase.getProcessedBlockCountForRange(repo, fromBlockNumber, toBlockNumber); + } + + async getEventsInRange (fromBlockNumber: number, toBlockNumber: number): Promise> { + const repo = this._conn.getRepository(Event); + + return this._baseDatabase.getEventsInRange(repo, fromBlockNumber, toBlockNumber); + } + + async saveEventEntity (queryRunner: QueryRunner, entity: Event): Promise { + const repo = queryRunner.manager.getRepository(Event); + return this._baseDatabase.saveEventEntity(repo, entity); + } + + async getBlockEvents (blockHash: string, where: Where, queryOptions: QueryOptions): Promise { + const repo = this._conn.getRepository(Event); + + return this._baseDatabase.getBlockEvents(repo, blockHash, where, queryOptions); + } + + async saveBlockWithEvents (queryRunner: QueryRunner, block: DeepPartial, events: DeepPartial[]): Promise { + const blockRepo = queryRunner.manager.getRepository(BlockProgress); + const eventRepo = queryRunner.manager.getRepository(Event); + + return this._baseDatabase.saveBlockWithEvents(blockRepo, eventRepo, block, events); + } + + async saveEvents (queryRunner: QueryRunner, events: Event[]): Promise { + const eventRepo = queryRunner.manager.getRepository(Event); + + return this._baseDatabase.saveEvents(eventRepo, events); + } + + async saveBlockProgress (queryRunner: QueryRunner, block: DeepPartial): Promise { + const repo = queryRunner.manager.getRepository(BlockProgress); + + return this._baseDatabase.saveBlockProgress(repo, block); + } + + async saveContract (queryRunner: QueryRunner, address: string, kind: string, checkpoint: boolean, startingBlock: number, context?: any): Promise { + const repo = queryRunner.manager.getRepository(Contract); + + return this._baseDatabase.saveContract(repo, address, kind, checkpoint, startingBlock, context); + } + + async updateSyncStatusIndexedBlock (queryRunner: QueryRunner, blockHash: string, blockNumber: number, force = false): Promise { + const repo = queryRunner.manager.getRepository(SyncStatus); + + return this._baseDatabase.updateSyncStatusIndexedBlock(repo, blockHash, blockNumber, force); + } + + async updateSyncStatusCanonicalBlock (queryRunner: QueryRunner, blockHash: string, blockNumber: number, force = false): Promise { + const repo = queryRunner.manager.getRepository(SyncStatus); + + return this._baseDatabase.updateSyncStatusCanonicalBlock(repo, blockHash, blockNumber, force); + } + + async updateSyncStatusChainHead (queryRunner: QueryRunner, blockHash: string, blockNumber: number, force = false): Promise { + const repo = queryRunner.manager.getRepository(SyncStatus); + + return this._baseDatabase.updateSyncStatusChainHead(repo, blockHash, blockNumber, force); + } + + async updateSyncStatusProcessedBlock (queryRunner: QueryRunner, blockHash: string, blockNumber: number, force = false): Promise { + const repo = queryRunner.manager.getRepository(SyncStatus); + + return this._baseDatabase.updateSyncStatusProcessedBlock(repo, blockHash, blockNumber, force); + } + + async updateSyncStatusIndexingError (queryRunner: QueryRunner, hasIndexingError: boolean): Promise { + const repo = queryRunner.manager.getRepository(SyncStatus); + + return this._baseDatabase.updateSyncStatusIndexingError(repo, hasIndexingError); + } + + async updateSyncStatus (queryRunner: QueryRunner, syncStatus: DeepPartial): Promise { + const repo = queryRunner.manager.getRepository(SyncStatus); + + return this._baseDatabase.updateSyncStatus(repo, syncStatus); + } + + async getSyncStatus (queryRunner: QueryRunner): Promise { + const repo = queryRunner.manager.getRepository(SyncStatus); + + return this._baseDatabase.getSyncStatus(repo); + } + + async getEvent (id: string): Promise { + const repo = this._conn.getRepository(Event); + + return this._baseDatabase.getEvent(repo, id); + } + + async getBlocksAtHeight (height: number, isPruned: boolean): Promise { + const repo = this._conn.getRepository(BlockProgress); + + return this._baseDatabase.getBlocksAtHeight(repo, height, isPruned); + } + + async markBlocksAsPruned (queryRunner: QueryRunner, blocks: BlockProgress[]): Promise { + const repo = queryRunner.manager.getRepository(BlockProgress); + + return this._baseDatabase.markBlocksAsPruned(repo, blocks); + } + + async getBlockProgress (blockHash: string): Promise { + const repo = this._conn.getRepository(BlockProgress); + return this._baseDatabase.getBlockProgress(repo, blockHash); + } + + async getBlockProgressEntities (where: FindConditions, options: FindManyOptions): Promise { + const repo = this._conn.getRepository(BlockProgress); + + return this._baseDatabase.getBlockProgressEntities(repo, where, options); + } + + async getEntitiesForBlock (blockHash: string, tableName: string): Promise { + return this._baseDatabase.getEntitiesForBlock(blockHash, tableName); + } + + async updateBlockProgress (queryRunner: QueryRunner, block: BlockProgress, lastProcessedEventIndex: number): Promise { + const repo = queryRunner.manager.getRepository(BlockProgress); + + return this._baseDatabase.updateBlockProgress(repo, block, lastProcessedEventIndex); + } + + async removeEntities (queryRunner: QueryRunner, entity: new () => Entity, findConditions?: FindManyOptions | FindConditions): Promise { + return this._baseDatabase.removeEntities(queryRunner, entity, findConditions); + } + + async deleteEntitiesByConditions (queryRunner: QueryRunner, entity: EntityTarget, findConditions: FindConditions): Promise { + await this._baseDatabase.deleteEntitiesByConditions(queryRunner, entity, findConditions); + } + + async getAncestorAtHeight (blockHash: string, height: number): Promise { + return this._baseDatabase.getAncestorAtHeight(blockHash, height); + } + + _getPropertyColumnMapForEntity (entityName: string): Map { + return this._conn.getMetadata(entityName).ownColumns.reduce((acc, curr) => { + return acc.set(curr.propertyName, curr.databaseName); + }, new Map()); + } +} diff --git a/packages/sushiswap-watcher/src/entity/BlockProgress.ts b/packages/sushiswap-watcher/src/entity/BlockProgress.ts new file mode 100644 index 0000000..ded4a86 --- /dev/null +++ b/packages/sushiswap-watcher/src/entity/BlockProgress.ts @@ -0,0 +1,48 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import { Entity, PrimaryGeneratedColumn, Column, Index, CreateDateColumn } from 'typeorm'; +import { BlockProgressInterface } from '@cerc-io/util'; + +@Entity() +@Index(['blockHash'], { unique: true }) +@Index(['blockNumber']) +@Index(['parentHash']) +export class BlockProgress implements BlockProgressInterface { + @PrimaryGeneratedColumn() + id!: number; + + @Column('varchar', { nullable: true }) + cid!: string | null; + + @Column('varchar', { length: 66 }) + blockHash!: string; + + @Column('varchar', { length: 66 }) + parentHash!: string; + + @Column('integer') + blockNumber!: number; + + @Column('integer') + blockTimestamp!: number; + + @Column('integer') + numEvents!: number; + + @Column('integer') + numProcessedEvents!: number; + + @Column('integer') + lastProcessedEventIndex!: number; + + @Column('boolean') + isComplete!: boolean; + + @Column('boolean', { default: false }) + isPruned!: boolean; + + @CreateDateColumn() + createdAt!: Date; +} diff --git a/packages/sushiswap-watcher/src/entity/Bundle.ts b/packages/sushiswap-watcher/src/entity/Bundle.ts new file mode 100644 index 0000000..140aa41 --- /dev/null +++ b/packages/sushiswap-watcher/src/entity/Bundle.ts @@ -0,0 +1,29 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import { Entity, PrimaryColumn, Column, Index } from 'typeorm'; +import { decimalTransformer } from '@cerc-io/util'; +import { Decimal } from 'decimal.js'; + +@Entity() +@Index(['blockNumber']) +export class Bundle { + @PrimaryColumn('varchar') + id!: string; + + @PrimaryColumn('varchar', { length: 66 }) + blockHash!: string; + + @Column('integer') + blockNumber!: number; + + @Column('numeric', { transformer: decimalTransformer }) + nativePrice!: Decimal; + + @Column('boolean', { default: false }) + isPruned!: boolean; + + @Column('boolean', { default: false }) + isRemoved!: boolean; +} diff --git a/packages/sushiswap-watcher/src/entity/Burn.ts b/packages/sushiswap-watcher/src/entity/Burn.ts new file mode 100644 index 0000000..7d39724 --- /dev/null +++ b/packages/sushiswap-watcher/src/entity/Burn.ts @@ -0,0 +1,65 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import { Entity, PrimaryColumn, Column, Index } from 'typeorm'; +import { decimalTransformer, bigintTransformer } from '@cerc-io/util'; +import { Decimal } from 'decimal.js'; + +@Entity() +@Index(['blockNumber']) +export class Burn { + @PrimaryColumn('varchar') + id!: string; + + @PrimaryColumn('varchar', { length: 66 }) + blockHash!: string; + + @Column('integer') + blockNumber!: number; + + @Column('varchar') + transaction!: string; + + @Column('numeric', { transformer: bigintTransformer }) + timestamp!: bigint; + + @Column('varchar') + pair!: string; + + @Column('numeric', { transformer: decimalTransformer }) + liquidity!: Decimal; + + @Column('varchar', { nullable: true }) + sender!: string | null; + + @Column('numeric', { nullable: true, transformer: decimalTransformer }) + amount0!: Decimal | null; + + @Column('numeric', { nullable: true, transformer: decimalTransformer }) + amount1!: Decimal | null; + + @Column('varchar', { nullable: true }) + to!: string | null; + + @Column('numeric', { nullable: true, transformer: bigintTransformer }) + logIndex!: bigint | null; + + @Column('numeric', { nullable: true, transformer: decimalTransformer }) + amountUSD!: Decimal | null; + + @Column('boolean') + complete!: boolean; + + @Column('varchar', { nullable: true }) + feeTo!: string | null; + + @Column('numeric', { nullable: true, transformer: decimalTransformer }) + feeLiquidity!: Decimal | null; + + @Column('boolean', { default: false }) + isPruned!: boolean; + + @Column('boolean', { default: false }) + isRemoved!: boolean; +} diff --git a/packages/sushiswap-watcher/src/entity/Contract.ts b/packages/sushiswap-watcher/src/entity/Contract.ts new file mode 100644 index 0000000..e4defa8 --- /dev/null +++ b/packages/sushiswap-watcher/src/entity/Contract.ts @@ -0,0 +1,27 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import { Entity, PrimaryGeneratedColumn, Column, Index } from 'typeorm'; + +@Entity() +@Index(['address'], { unique: true }) +export class Contract { + @PrimaryGeneratedColumn() + id!: number; + + @Column('varchar', { length: 42 }) + address!: string; + + @Column('varchar') + kind!: string; + + @Column('boolean') + checkpoint!: boolean; + + @Column('integer') + startingBlock!: number; + + @Column('jsonb', { nullable: true }) + context!: Record; +} diff --git a/packages/sushiswap-watcher/src/entity/Event.ts b/packages/sushiswap-watcher/src/entity/Event.ts new file mode 100644 index 0000000..91f1e6d --- /dev/null +++ b/packages/sushiswap-watcher/src/entity/Event.ts @@ -0,0 +1,38 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import { Entity, PrimaryGeneratedColumn, Column, Index, ManyToOne } from 'typeorm'; +import { BlockProgress } from './BlockProgress'; + +@Entity() +@Index(['block', 'contract']) +@Index(['block', 'contract', 'eventName']) +export class Event { + @PrimaryGeneratedColumn() + id!: number; + + @ManyToOne(() => BlockProgress, { onDelete: 'CASCADE' }) + block!: BlockProgress; + + @Column('varchar', { length: 66 }) + txHash!: string; + + @Column('integer') + index!: number; + + @Column('varchar', { length: 42 }) + contract!: string; + + @Column('varchar', { length: 256 }) + eventName!: string; + + @Column('text') + eventInfo!: string; + + @Column('text') + extraInfo!: string; + + @Column('text') + proof!: string; +} diff --git a/packages/sushiswap-watcher/src/entity/Factory.ts b/packages/sushiswap-watcher/src/entity/Factory.ts new file mode 100644 index 0000000..5107e05 --- /dev/null +++ b/packages/sushiswap-watcher/src/entity/Factory.ts @@ -0,0 +1,60 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import { Entity, PrimaryColumn, Column, Index } from 'typeorm'; +import { PairType } from '../types'; +import { decimalTransformer, bigintTransformer } from '@cerc-io/util'; +import { Decimal } from 'decimal.js'; + +@Entity() +@Index(['blockNumber']) +export class Factory { + @PrimaryColumn('varchar') + id!: string; + + @PrimaryColumn('varchar', { length: 66 }) + blockHash!: string; + + @Column('integer') + blockNumber!: number; + + @Column({ type: 'enum', enum: PairType }) + type!: PairType; + + @Column('numeric', { transformer: decimalTransformer }) + volumeUSD!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + volumeNative!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + liquidityUSD!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + liquidityNative!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + feesUSD!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + feesNative!: Decimal; + + @Column('numeric', { transformer: bigintTransformer }) + pairCount!: bigint; + + @Column('numeric', { transformer: bigintTransformer }) + transactionCount!: bigint; + + @Column('numeric', { transformer: bigintTransformer }) + tokenCount!: bigint; + + @Column('numeric', { transformer: bigintTransformer }) + userCount!: bigint; + + @Column('boolean', { default: false }) + isPruned!: boolean; + + @Column('boolean', { default: false }) + isRemoved!: boolean; +} diff --git a/packages/sushiswap-watcher/src/entity/FactoryDaySnapshot.ts b/packages/sushiswap-watcher/src/entity/FactoryDaySnapshot.ts new file mode 100644 index 0000000..c230214 --- /dev/null +++ b/packages/sushiswap-watcher/src/entity/FactoryDaySnapshot.ts @@ -0,0 +1,53 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import { Entity, PrimaryColumn, Column, Index } from 'typeorm'; +import { decimalTransformer, bigintTransformer } from '@cerc-io/util'; +import { Decimal } from 'decimal.js'; + +@Entity() +@Index(['blockNumber']) +export class FactoryDaySnapshot { + @PrimaryColumn('varchar') + id!: string; + + @PrimaryColumn('varchar', { length: 66 }) + blockHash!: string; + + @Column('integer') + blockNumber!: number; + + @Column('varchar') + factory!: string; + + @Column('integer') + date!: number; + + @Column('numeric', { transformer: decimalTransformer }) + volumeUSD!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + volumeNative!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + liquidityNative!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + liquidityUSD!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + feesNative!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + feesUSD!: Decimal; + + @Column('numeric', { transformer: bigintTransformer }) + transactionCount!: bigint; + + @Column('boolean', { default: false }) + isPruned!: boolean; + + @Column('boolean', { default: false }) + isRemoved!: boolean; +} diff --git a/packages/sushiswap-watcher/src/entity/FactoryHourSnapshot.ts b/packages/sushiswap-watcher/src/entity/FactoryHourSnapshot.ts new file mode 100644 index 0000000..86a7adc --- /dev/null +++ b/packages/sushiswap-watcher/src/entity/FactoryHourSnapshot.ts @@ -0,0 +1,53 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import { Entity, PrimaryColumn, Column, Index } from 'typeorm'; +import { decimalTransformer, bigintTransformer } from '@cerc-io/util'; +import { Decimal } from 'decimal.js'; + +@Entity() +@Index(['blockNumber']) +export class FactoryHourSnapshot { + @PrimaryColumn('varchar') + id!: string; + + @PrimaryColumn('varchar', { length: 66 }) + blockHash!: string; + + @Column('integer') + blockNumber!: number; + + @Column('varchar') + factory!: string; + + @Column('integer') + date!: number; + + @Column('numeric', { transformer: decimalTransformer }) + volumeUSD!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + volumeNative!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + liquidityNative!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + liquidityUSD!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + feesNative!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + feesUSD!: Decimal; + + @Column('numeric', { transformer: bigintTransformer }) + transactionCount!: bigint; + + @Column('boolean', { default: false }) + isPruned!: boolean; + + @Column('boolean', { default: false }) + isRemoved!: boolean; +} diff --git a/packages/sushiswap-watcher/src/entity/FrothyEntity.ts b/packages/sushiswap-watcher/src/entity/FrothyEntity.ts new file mode 100644 index 0000000..9898ce8 --- /dev/null +++ b/packages/sushiswap-watcher/src/entity/FrothyEntity.ts @@ -0,0 +1,21 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import { Entity, PrimaryColumn, Column, Index } from 'typeorm'; + +@Entity() +@Index(['blockNumber']) +export class FrothyEntity { + @PrimaryColumn('varchar') + id!: string; + + @PrimaryColumn('varchar') + name!: string; + + @PrimaryColumn('varchar', { length: 66 }) + blockHash!: string; + + @Column('integer') + blockNumber!: number; +} diff --git a/packages/sushiswap-watcher/src/entity/LiquidityPosition.ts b/packages/sushiswap-watcher/src/entity/LiquidityPosition.ts new file mode 100644 index 0000000..2130c9d --- /dev/null +++ b/packages/sushiswap-watcher/src/entity/LiquidityPosition.ts @@ -0,0 +1,40 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import { Entity, PrimaryColumn, Column, Index } from 'typeorm'; +import { bigintTransformer } from '@cerc-io/util'; + +@Entity() +@Index(['blockNumber']) +export class LiquidityPosition { + @PrimaryColumn('varchar') + id!: string; + + @PrimaryColumn('varchar', { length: 66 }) + blockHash!: string; + + @Column('integer') + blockNumber!: number; + + @Column('varchar') + pair!: string; + + @Column('varchar') + user!: string; + + @Column('numeric', { transformer: bigintTransformer }) + balance!: bigint; + + @Column('numeric', { transformer: bigintTransformer }) + createdAtBlock!: bigint; + + @Column('numeric', { transformer: bigintTransformer }) + createdAtTimestamp!: bigint; + + @Column('boolean', { default: false }) + isPruned!: boolean; + + @Column('boolean', { default: false }) + isRemoved!: boolean; +} diff --git a/packages/sushiswap-watcher/src/entity/LiquidityPositionSnapshot.ts b/packages/sushiswap-watcher/src/entity/LiquidityPositionSnapshot.ts new file mode 100644 index 0000000..138eb77 --- /dev/null +++ b/packages/sushiswap-watcher/src/entity/LiquidityPositionSnapshot.ts @@ -0,0 +1,62 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import { Entity, PrimaryColumn, Column, Index } from 'typeorm'; +import { decimalTransformer, bigintTransformer } from '@cerc-io/util'; +import { Decimal } from 'decimal.js'; + +@Entity() +@Index(['blockNumber']) +export class LiquidityPositionSnapshot { + @PrimaryColumn('varchar') + id!: string; + + @PrimaryColumn('varchar', { length: 66 }) + blockHash!: string; + + @Column('integer') + blockNumber!: number; + + @Column('varchar') + liquidityPosition!: string; + + @Column('integer') + timestamp!: number; + + @Column('integer') + block!: number; + + @Column('varchar') + user!: string; + + @Column('varchar') + pair!: string; + + @Column('numeric', { transformer: decimalTransformer }) + token0PriceUSD!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + token1PriceUSD!: Decimal; + + @Column('numeric', { transformer: bigintTransformer }) + reserve0!: bigint; + + @Column('numeric', { transformer: bigintTransformer }) + reserve1!: bigint; + + @Column('numeric', { transformer: decimalTransformer }) + reserveUSD!: Decimal; + + @Column('numeric', { transformer: bigintTransformer }) + liquidityTokenTotalSupply!: bigint; + + @Column('numeric', { transformer: bigintTransformer }) + liquidityTokenBalance!: bigint; + + @Column('boolean', { default: false }) + isPruned!: boolean; + + @Column('boolean', { default: false }) + isRemoved!: boolean; +} diff --git a/packages/sushiswap-watcher/src/entity/Mint.ts b/packages/sushiswap-watcher/src/entity/Mint.ts new file mode 100644 index 0000000..ec1512a --- /dev/null +++ b/packages/sushiswap-watcher/src/entity/Mint.ts @@ -0,0 +1,62 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import { Entity, PrimaryColumn, Column, Index } from 'typeorm'; +import { decimalTransformer, bigintTransformer } from '@cerc-io/util'; +import { Decimal } from 'decimal.js'; + +@Entity() +@Index(['blockNumber']) +export class Mint { + @PrimaryColumn('varchar') + id!: string; + + @PrimaryColumn('varchar', { length: 66 }) + blockHash!: string; + + @Column('integer') + blockNumber!: number; + + @Column('varchar') + transaction!: string; + + @Column('numeric', { transformer: bigintTransformer }) + timestamp!: bigint; + + @Column('varchar') + pair!: string; + + @Column('varchar') + to!: string; + + @Column('numeric', { transformer: decimalTransformer }) + liquidity!: Decimal; + + @Column('varchar', { nullable: true }) + sender!: string | null; + + @Column('numeric', { nullable: true, transformer: decimalTransformer }) + amount0!: Decimal | null; + + @Column('numeric', { nullable: true, transformer: decimalTransformer }) + amount1!: Decimal | null; + + @Column('numeric', { nullable: true, transformer: bigintTransformer }) + logIndex!: bigint | null; + + @Column('numeric', { nullable: true, transformer: decimalTransformer }) + amountUSD!: Decimal | null; + + @Column('varchar', { nullable: true }) + feeTo!: string | null; + + @Column('numeric', { nullable: true, transformer: decimalTransformer }) + feeLiquidity!: Decimal | null; + + @Column('boolean', { default: false }) + isPruned!: boolean; + + @Column('boolean', { default: false }) + isRemoved!: boolean; +} diff --git a/packages/sushiswap-watcher/src/entity/Pair.ts b/packages/sushiswap-watcher/src/entity/Pair.ts new file mode 100644 index 0000000..d81de25 --- /dev/null +++ b/packages/sushiswap-watcher/src/entity/Pair.ts @@ -0,0 +1,105 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import { Entity, PrimaryColumn, Column, Index } from 'typeorm'; +import { PairType } from '../types'; +import { decimalTransformer, bigintTransformer } from '@cerc-io/util'; +import { Decimal } from 'decimal.js'; + +@Entity() +@Index(['blockNumber']) +export class Pair { + @PrimaryColumn('varchar') + id!: string; + + @PrimaryColumn('varchar', { length: 66 }) + blockHash!: string; + + @Column('integer') + blockNumber!: number; + + @Column({ type: 'enum', enum: PairType }) + type!: PairType; + + @Column('numeric', { transformer: bigintTransformer }) + swapFee!: bigint; + + @Column('boolean') + twapEnabled!: boolean; + + @Column('varchar') + name!: string; + + @Column('varchar') + token0!: string; + + @Column('varchar') + token1!: string; + + @Column('varchar') + source!: string; + + @Column('numeric', { transformer: bigintTransformer }) + createdAtBlock!: bigint; + + @Column('numeric', { transformer: bigintTransformer }) + createdAtTimestamp!: bigint; + + @Column('numeric', { transformer: bigintTransformer }) + reserve0!: bigint; + + @Column('numeric', { transformer: bigintTransformer }) + reserve1!: bigint; + + @Column('numeric', { transformer: bigintTransformer }) + liquidity!: bigint; + + @Column('numeric', { transformer: decimalTransformer }) + liquidityUSD!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + liquidityNative!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + trackedLiquidityNative!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + token0Price!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + token1Price!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + volumeNative!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + volumeUSD!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + volumeToken0!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + volumeToken1!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + feesNative!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + feesUSD!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + apr!: Decimal; + + @Column('numeric', { transformer: bigintTransformer }) + aprUpdatedAtTimestamp!: bigint; + + @Column('numeric', { transformer: bigintTransformer }) + txCount!: bigint; + + @Column('boolean', { default: false }) + isPruned!: boolean; + + @Column('boolean', { default: false }) + isRemoved!: boolean; +} diff --git a/packages/sushiswap-watcher/src/entity/PairDaySnapshot.ts b/packages/sushiswap-watcher/src/entity/PairDaySnapshot.ts new file mode 100644 index 0000000..1a49ce5 --- /dev/null +++ b/packages/sushiswap-watcher/src/entity/PairDaySnapshot.ts @@ -0,0 +1,68 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import { Entity, PrimaryColumn, Column, Index } from 'typeorm'; +import { decimalTransformer, bigintTransformer } from '@cerc-io/util'; +import { Decimal } from 'decimal.js'; + +@Entity() +@Index(['blockNumber']) +export class PairDaySnapshot { + @PrimaryColumn('varchar') + id!: string; + + @PrimaryColumn('varchar', { length: 66 }) + blockHash!: string; + + @Column('integer') + blockNumber!: number; + + @Column('varchar') + pair!: string; + + @Column('integer') + date!: number; + + @Column('numeric', { transformer: decimalTransformer }) + cumulativeVolumeUSD!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + volumeUSD!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + volumeNative!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + volumeToken0!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + volumeToken1!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + liquidity!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + liquidityNative!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + liquidityUSD!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + feesNative!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + feesUSD!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + apr!: Decimal; + + @Column('numeric', { transformer: bigintTransformer }) + transactionCount!: bigint; + + @Column('boolean', { default: false }) + isPruned!: boolean; + + @Column('boolean', { default: false }) + isRemoved!: boolean; +} diff --git a/packages/sushiswap-watcher/src/entity/PairHourSnapshot.ts b/packages/sushiswap-watcher/src/entity/PairHourSnapshot.ts new file mode 100644 index 0000000..426d5a8 --- /dev/null +++ b/packages/sushiswap-watcher/src/entity/PairHourSnapshot.ts @@ -0,0 +1,68 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import { Entity, PrimaryColumn, Column, Index } from 'typeorm'; +import { decimalTransformer, bigintTransformer } from '@cerc-io/util'; +import { Decimal } from 'decimal.js'; + +@Entity() +@Index(['blockNumber']) +export class PairHourSnapshot { + @PrimaryColumn('varchar') + id!: string; + + @PrimaryColumn('varchar', { length: 66 }) + blockHash!: string; + + @Column('integer') + blockNumber!: number; + + @Column('varchar') + pair!: string; + + @Column('integer') + date!: number; + + @Column('numeric', { transformer: decimalTransformer }) + cumulativeVolumeUSD!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + volumeUSD!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + volumeNative!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + volumeToken0!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + volumeToken1!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + liquidity!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + liquidityNative!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + liquidityUSD!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + feesNative!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + feesUSD!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + apr!: Decimal; + + @Column('numeric', { transformer: bigintTransformer }) + transactionCount!: bigint; + + @Column('boolean', { default: false }) + isPruned!: boolean; + + @Column('boolean', { default: false }) + isRemoved!: boolean; +} diff --git a/packages/sushiswap-watcher/src/entity/State.ts b/packages/sushiswap-watcher/src/entity/State.ts new file mode 100644 index 0000000..bc05bca --- /dev/null +++ b/packages/sushiswap-watcher/src/entity/State.ts @@ -0,0 +1,31 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import { Entity, PrimaryGeneratedColumn, Column, Index, ManyToOne } from 'typeorm'; +import { StateKind } from '@cerc-io/util'; +import { BlockProgress } from './BlockProgress'; + +@Entity() +@Index(['cid'], { unique: true }) +@Index(['block', 'contractAddress']) +@Index(['block', 'contractAddress', 'kind'], { unique: true }) +export class State { + @PrimaryGeneratedColumn() + id!: number; + + @ManyToOne(() => BlockProgress, { onDelete: 'CASCADE' }) + block!: BlockProgress; + + @Column('varchar', { length: 42 }) + contractAddress!: string; + + @Column('varchar') + cid!: string; + + @Column({ type: 'enum', enum: StateKind }) + kind!: StateKind; + + @Column('bytea') + data!: Buffer; +} diff --git a/packages/sushiswap-watcher/src/entity/StateSyncStatus.ts b/packages/sushiswap-watcher/src/entity/StateSyncStatus.ts new file mode 100644 index 0000000..1535eb4 --- /dev/null +++ b/packages/sushiswap-watcher/src/entity/StateSyncStatus.ts @@ -0,0 +1,17 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm'; + +@Entity() +export class StateSyncStatus { + @PrimaryGeneratedColumn() + id!: number; + + @Column('integer') + latestIndexedBlockNumber!: number; + + @Column('integer') + latestCheckpointBlockNumber!: number; +} diff --git a/packages/sushiswap-watcher/src/entity/Subscriber.ts b/packages/sushiswap-watcher/src/entity/Subscriber.ts new file mode 100644 index 0000000..2cccb84 --- /dev/null +++ b/packages/sushiswap-watcher/src/entity/Subscriber.ts @@ -0,0 +1,21 @@ +// +// Copyright 2022 Vulcanize, Inc. +// + +import { EventSubscriber, EntitySubscriberInterface, InsertEvent, UpdateEvent } from 'typeorm'; + +import { afterEntityInsertOrUpdate } from '@cerc-io/util'; + +import { FrothyEntity } from './FrothyEntity'; +import { ENTITY_TO_LATEST_ENTITY_MAP, SUBGRAPH_ENTITIES } from '../database'; + +@EventSubscriber() +export class EntitySubscriber implements EntitySubscriberInterface { + async afterInsert (event: InsertEvent): Promise { + await afterEntityInsertOrUpdate(FrothyEntity, SUBGRAPH_ENTITIES, event, ENTITY_TO_LATEST_ENTITY_MAP); + } + + async afterUpdate (event: UpdateEvent): Promise { + await afterEntityInsertOrUpdate(FrothyEntity, SUBGRAPH_ENTITIES, event, ENTITY_TO_LATEST_ENTITY_MAP); + } +} diff --git a/packages/sushiswap-watcher/src/entity/Swap.ts b/packages/sushiswap-watcher/src/entity/Swap.ts new file mode 100644 index 0000000..f319132 --- /dev/null +++ b/packages/sushiswap-watcher/src/entity/Swap.ts @@ -0,0 +1,59 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import { Entity, PrimaryColumn, Column, Index } from 'typeorm'; +import { decimalTransformer, bigintTransformer } from '@cerc-io/util'; +import { Decimal } from 'decimal.js'; + +@Entity() +@Index(['blockNumber']) +export class Swap { + @PrimaryColumn('varchar') + id!: string; + + @PrimaryColumn('varchar', { length: 66 }) + blockHash!: string; + + @Column('integer') + blockNumber!: number; + + @Column('varchar') + transaction!: string; + + @Column('numeric', { transformer: bigintTransformer }) + timestamp!: bigint; + + @Column('varchar') + pair!: string; + + @Column('varchar') + sender!: string; + + @Column('varchar') + tokenIn!: string; + + @Column('varchar') + tokenOut!: string; + + @Column('numeric', { transformer: decimalTransformer }) + amountIn!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + amountOut!: Decimal; + + @Column('varchar') + to!: string; + + @Column('numeric', { nullable: true, transformer: bigintTransformer }) + logIndex!: bigint | null; + + @Column('numeric', { transformer: decimalTransformer }) + amountUSD!: Decimal; + + @Column('boolean', { default: false }) + isPruned!: boolean; + + @Column('boolean', { default: false }) + isRemoved!: boolean; +} diff --git a/packages/sushiswap-watcher/src/entity/SyncStatus.ts b/packages/sushiswap-watcher/src/entity/SyncStatus.ts new file mode 100644 index 0000000..cc13c70 --- /dev/null +++ b/packages/sushiswap-watcher/src/entity/SyncStatus.ts @@ -0,0 +1,45 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm'; +import { SyncStatusInterface } from '@cerc-io/util'; + +@Entity() +export class SyncStatus implements SyncStatusInterface { + @PrimaryGeneratedColumn() + id!: number; + + @Column('varchar', { length: 66 }) + chainHeadBlockHash!: string; + + @Column('integer') + chainHeadBlockNumber!: number; + + @Column('varchar', { length: 66 }) + latestIndexedBlockHash!: string; + + @Column('integer') + latestIndexedBlockNumber!: number; + + @Column('varchar', { length: 66 }) + latestProcessedBlockHash!: string; + + @Column('integer') + latestProcessedBlockNumber!: number; + + @Column('varchar', { length: 66 }) + latestCanonicalBlockHash!: string; + + @Column('integer') + latestCanonicalBlockNumber!: number; + + @Column('varchar', { length: 66 }) + initialIndexedBlockHash!: string; + + @Column('integer') + initialIndexedBlockNumber!: number; + + @Column('boolean', { default: false }) + hasIndexingError!: boolean; +} diff --git a/packages/sushiswap-watcher/src/entity/Token.ts b/packages/sushiswap-watcher/src/entity/Token.ts new file mode 100644 index 0000000..482a899 --- /dev/null +++ b/packages/sushiswap-watcher/src/entity/Token.ts @@ -0,0 +1,80 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import { Entity, PrimaryColumn, Column, Index } from 'typeorm'; +import { decimalTransformer, bigintTransformer } from '@cerc-io/util'; +import { Decimal } from 'decimal.js'; + +@Entity() +@Index(['blockNumber']) +export class Token { + @PrimaryColumn('varchar') + id!: string; + + @PrimaryColumn('varchar', { length: 66 }) + blockHash!: string; + + @Column('integer') + blockNumber!: number; + + @Column('varchar') + price!: string; + + @Column('varchar') + symbol!: string; + + @Column('boolean') + symbolSuccess!: boolean; + + @Column('varchar') + name!: string; + + @Column('boolean') + nameSuccess!: boolean; + + @Column('numeric', { transformer: bigintTransformer }) + decimals!: bigint; + + @Column('boolean') + decimalsSuccess!: boolean; + + @Column('numeric', { transformer: bigintTransformer }) + liquidity!: bigint; + + @Column('numeric', { transformer: decimalTransformer }) + liquidityNative!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + liquidityUSD!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + volume!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + volumeNative!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + volumeUSD!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + feesNative!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + feesUSD!: Decimal; + + @Column('numeric', { transformer: bigintTransformer }) + txCount!: bigint; + + @Column('numeric', { transformer: bigintTransformer }) + pairCount!: bigint; + + @Column('numeric', { transformer: bigintTransformer }) + whitelistedPairCount!: bigint; + + @Column('boolean', { default: false }) + isPruned!: boolean; + + @Column('boolean', { default: false }) + isRemoved!: boolean; +} diff --git a/packages/sushiswap-watcher/src/entity/TokenDaySnapshot.ts b/packages/sushiswap-watcher/src/entity/TokenDaySnapshot.ts new file mode 100644 index 0000000..6472399 --- /dev/null +++ b/packages/sushiswap-watcher/src/entity/TokenDaySnapshot.ts @@ -0,0 +1,65 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import { Entity, PrimaryColumn, Column, Index } from 'typeorm'; +import { decimalTransformer, bigintTransformer } from '@cerc-io/util'; +import { Decimal } from 'decimal.js'; + +@Entity() +@Index(['blockNumber']) +export class TokenDaySnapshot { + @PrimaryColumn('varchar') + id!: string; + + @PrimaryColumn('varchar', { length: 66 }) + blockHash!: string; + + @Column('integer') + blockNumber!: number; + + @Column('integer') + date!: number; + + @Column('varchar') + token!: string; + + @Column('numeric', { transformer: decimalTransformer }) + liquidity!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + liquidityNative!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + liquidityUSD!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + volume!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + volumeNative!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + volumeUSD!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + priceNative!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + priceUSD!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + feesNative!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + feesUSD!: Decimal; + + @Column('numeric', { transformer: bigintTransformer }) + transactionCount!: bigint; + + @Column('boolean', { default: false }) + isPruned!: boolean; + + @Column('boolean', { default: false }) + isRemoved!: boolean; +} diff --git a/packages/sushiswap-watcher/src/entity/TokenHourSnapshot.ts b/packages/sushiswap-watcher/src/entity/TokenHourSnapshot.ts new file mode 100644 index 0000000..c78ebc7 --- /dev/null +++ b/packages/sushiswap-watcher/src/entity/TokenHourSnapshot.ts @@ -0,0 +1,65 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import { Entity, PrimaryColumn, Column, Index } from 'typeorm'; +import { decimalTransformer, bigintTransformer } from '@cerc-io/util'; +import { Decimal } from 'decimal.js'; + +@Entity() +@Index(['blockNumber']) +export class TokenHourSnapshot { + @PrimaryColumn('varchar') + id!: string; + + @PrimaryColumn('varchar', { length: 66 }) + blockHash!: string; + + @Column('integer') + blockNumber!: number; + + @Column('integer') + date!: number; + + @Column('varchar') + token!: string; + + @Column('numeric', { transformer: decimalTransformer }) + liquidity!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + liquidityNative!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + liquidityUSD!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + volume!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + volumeNative!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + volumeUSD!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + priceNative!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + priceUSD!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + feesNative!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + feesUSD!: Decimal; + + @Column('numeric', { transformer: bigintTransformer }) + transactionCount!: bigint; + + @Column('boolean', { default: false }) + isPruned!: boolean; + + @Column('boolean', { default: false }) + isRemoved!: boolean; +} diff --git a/packages/sushiswap-watcher/src/entity/TokenPrice.ts b/packages/sushiswap-watcher/src/entity/TokenPrice.ts new file mode 100644 index 0000000..1730dff --- /dev/null +++ b/packages/sushiswap-watcher/src/entity/TokenPrice.ts @@ -0,0 +1,41 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import { Entity, PrimaryColumn, Column, Index } from 'typeorm'; +import { decimalTransformer } from '@cerc-io/util'; +import { Decimal } from 'decimal.js'; + +@Entity() +@Index(['blockNumber']) +export class TokenPrice { + @PrimaryColumn('varchar') + id!: string; + + @PrimaryColumn('varchar', { length: 66 }) + blockHash!: string; + + @Column('integer') + blockNumber!: number; + + @Column('varchar') + token!: string; + + @Column('numeric', { transformer: decimalTransformer }) + derivedNative!: Decimal; + + @Column('numeric', { transformer: decimalTransformer }) + lastUsdPrice!: Decimal; + + @Column('varchar', { nullable: true }) + pricedOffToken!: string | null; + + @Column('varchar', { nullable: true }) + pricedOffPair!: string | null; + + @Column('boolean', { default: false }) + isPruned!: boolean; + + @Column('boolean', { default: false }) + isRemoved!: boolean; +} diff --git a/packages/sushiswap-watcher/src/entity/Transaction.ts b/packages/sushiswap-watcher/src/entity/Transaction.ts new file mode 100644 index 0000000..85f1576 --- /dev/null +++ b/packages/sushiswap-watcher/src/entity/Transaction.ts @@ -0,0 +1,46 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import { Entity, PrimaryColumn, Column, Index } from 'typeorm'; +import { bigintTransformer } from '@cerc-io/util'; + +@Entity() +@Index(['blockNumber']) +export class Transaction { + @PrimaryColumn('varchar') + id!: string; + + @PrimaryColumn('varchar', { length: 66 }) + blockHash!: string; + + @Column('integer') + blockNumber!: number; + + @Column('numeric', { transformer: bigintTransformer }) + gasLimit!: bigint; + + @Column('numeric', { transformer: bigintTransformer }) + gasPrice!: bigint; + + @Column('varchar', { array: true }) + mints!: string[]; + + @Column('varchar', { array: true }) + burns!: string[]; + + @Column('varchar', { array: true }) + swaps!: string[]; + + @Column('numeric', { transformer: bigintTransformer }) + createdAtBlock!: bigint; + + @Column('numeric', { transformer: bigintTransformer }) + createdAtTimestamp!: bigint; + + @Column('boolean', { default: false }) + isPruned!: boolean; + + @Column('boolean', { default: false }) + isRemoved!: boolean; +} diff --git a/packages/sushiswap-watcher/src/entity/User.ts b/packages/sushiswap-watcher/src/entity/User.ts new file mode 100644 index 0000000..9d6c39c --- /dev/null +++ b/packages/sushiswap-watcher/src/entity/User.ts @@ -0,0 +1,28 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import { Entity, PrimaryColumn, Column, Index } from 'typeorm'; +import { bigintTransformer } from '@cerc-io/util'; + +@Entity() +@Index(['blockNumber']) +export class User { + @PrimaryColumn('varchar') + id!: string; + + @PrimaryColumn('varchar', { length: 66 }) + blockHash!: string; + + @Column('integer') + blockNumber!: number; + + @Column('numeric', { transformer: bigintTransformer }) + lpSnapshotsCount!: bigint; + + @Column('boolean', { default: false }) + isPruned!: boolean; + + @Column('boolean', { default: false }) + isRemoved!: boolean; +} diff --git a/packages/sushiswap-watcher/src/entity/_TokenPair.ts b/packages/sushiswap-watcher/src/entity/_TokenPair.ts new file mode 100644 index 0000000..3fead9b --- /dev/null +++ b/packages/sushiswap-watcher/src/entity/_TokenPair.ts @@ -0,0 +1,30 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import { Entity, PrimaryColumn, Column, Index } from 'typeorm'; + +@Entity() +@Index(['blockNumber']) +export class _TokenPair { + @PrimaryColumn('varchar') + id!: string; + + @PrimaryColumn('varchar', { length: 66 }) + blockHash!: string; + + @Column('integer') + blockNumber!: number; + + @Column('varchar') + pair!: string; + + @Column('varchar') + token!: string; + + @Column('boolean', { default: false }) + isPruned!: boolean; + + @Column('boolean', { default: false }) + isRemoved!: boolean; +} diff --git a/packages/sushiswap-watcher/src/entity/_WhitelistedTokenPair.ts b/packages/sushiswap-watcher/src/entity/_WhitelistedTokenPair.ts new file mode 100644 index 0000000..796c96d --- /dev/null +++ b/packages/sushiswap-watcher/src/entity/_WhitelistedTokenPair.ts @@ -0,0 +1,30 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import { Entity, PrimaryColumn, Column, Index } from 'typeorm'; + +@Entity() +@Index(['blockNumber']) +export class _WhitelistedTokenPair { + @PrimaryColumn('varchar') + id!: string; + + @PrimaryColumn('varchar', { length: 66 }) + blockHash!: string; + + @Column('integer') + blockNumber!: number; + + @Column('varchar') + pair!: string; + + @Column('varchar') + token!: string; + + @Column('boolean', { default: false }) + isPruned!: boolean; + + @Column('boolean', { default: false }) + isRemoved!: boolean; +} diff --git a/packages/sushiswap-watcher/src/fill.ts b/packages/sushiswap-watcher/src/fill.ts new file mode 100644 index 0000000..210341e --- /dev/null +++ b/packages/sushiswap-watcher/src/fill.ts @@ -0,0 +1,48 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import 'reflect-metadata'; +import debug from 'debug'; + +import { FillCmd } from '@cerc-io/cli'; +import { getContractEntitiesMap } from '@cerc-io/util'; +import { getGraphDbAndWatcher } from '@cerc-io/graph-node'; + +import { Database, ENTITY_QUERY_TYPE_MAP, ENTITY_TO_LATEST_ENTITY_MAP } from './database'; +import { Indexer } from './indexer'; + +const log = debug('vulcanize:fill'); + +export const main = async (): Promise => { + const fillCmd = new FillCmd(); + await fillCmd.init(Database); + + const { graphWatcher } = await getGraphDbAndWatcher( + fillCmd.config.server, + fillCmd.clients.ethClient, + fillCmd.ethProvider, + fillCmd.database.baseDatabase, + ENTITY_QUERY_TYPE_MAP, + ENTITY_TO_LATEST_ENTITY_MAP + ); + + await fillCmd.initIndexer(Indexer, graphWatcher); + + // Get contractEntitiesMap required for fill-state + // NOTE: Assuming each entity type is only mapped to a single contract + const contractEntitiesMap = getContractEntitiesMap(graphWatcher.dataSources); + + await fillCmd.exec(contractEntitiesMap); +}; + +main().catch(err => { + log(err); +}).finally(() => { + process.exit(); +}); + +process.on('SIGINT', () => { + log(`Exiting process ${process.pid} with code 0`); + process.exit(0); +}); diff --git a/packages/sushiswap-watcher/src/gql/index.ts b/packages/sushiswap-watcher/src/gql/index.ts new file mode 100644 index 0000000..4732f68 --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/index.ts @@ -0,0 +1,3 @@ +export * as mutations from './mutations'; +export * as queries from './queries'; +export * as subscriptions from './subscriptions'; diff --git a/packages/sushiswap-watcher/src/gql/mutations/index.ts b/packages/sushiswap-watcher/src/gql/mutations/index.ts new file mode 100644 index 0000000..0c3bd85 --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/mutations/index.ts @@ -0,0 +1,4 @@ +import fs from 'fs'; +import path from 'path'; + +export const watchContract = fs.readFileSync(path.join(__dirname, 'watchContract.gql'), 'utf8'); diff --git a/packages/sushiswap-watcher/src/gql/mutations/watchContract.gql b/packages/sushiswap-watcher/src/gql/mutations/watchContract.gql new file mode 100644 index 0000000..2ecc74f --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/mutations/watchContract.gql @@ -0,0 +1,3 @@ +mutation watchContract($address: String!, $kind: String!, $checkpoint: Boolean!, $startingBlock: Int){ + watchContract(address: $address, kind: $kind, checkpoint: $checkpoint, startingBlock: $startingBlock) +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/_TokenPair.gql b/packages/sushiswap-watcher/src/gql/queries/_TokenPair.gql new file mode 100644 index 0000000..fda98bc --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/_TokenPair.gql @@ -0,0 +1,52 @@ +query _TokenPair($id: ID!, $block: Block_height){ + _TokenPair(id: $id, block: $block){ + id + pair{ + id + type + swapFee + twapEnabled + name + source + createdAtBlock + createdAtTimestamp + reserve0 + reserve1 + liquidity + liquidityUSD + liquidityNative + trackedLiquidityNative + token0Price + token1Price + volumeNative + volumeUSD + volumeToken0 + volumeToken1 + feesNative + feesUSD + apr + aprUpdatedAtTimestamp + txCount + } + token{ + id + symbol + symbolSuccess + name + nameSuccess + decimals + decimalsSuccess + liquidity + liquidityNative + liquidityUSD + volume + volumeNative + volumeUSD + feesNative + feesUSD + txCount + pairCount + whitelistedPairCount + } + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/_TokenPairs.gql b/packages/sushiswap-watcher/src/gql/queries/_TokenPairs.gql new file mode 100644 index 0000000..20992b4 --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/_TokenPairs.gql @@ -0,0 +1,52 @@ +query _TokenPairs($block: Block_height, $where: _TokenPair_filter, $orderBy: _TokenPair_orderBy, $orderDirection: OrderDirection, $first: Int, $skip: Int){ + _TokenPairs(block: $block, where: $where, orderBy: $orderBy, orderDirection: $orderDirection, first: $first, skip: $skip){ + id + pair{ + id + type + swapFee + twapEnabled + name + source + createdAtBlock + createdAtTimestamp + reserve0 + reserve1 + liquidity + liquidityUSD + liquidityNative + trackedLiquidityNative + token0Price + token1Price + volumeNative + volumeUSD + volumeToken0 + volumeToken1 + feesNative + feesUSD + apr + aprUpdatedAtTimestamp + txCount + } + token{ + id + symbol + symbolSuccess + name + nameSuccess + decimals + decimalsSuccess + liquidity + liquidityNative + liquidityUSD + volume + volumeNative + volumeUSD + feesNative + feesUSD + txCount + pairCount + whitelistedPairCount + } + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/_WhitelistedTokenPair.gql b/packages/sushiswap-watcher/src/gql/queries/_WhitelistedTokenPair.gql new file mode 100644 index 0000000..0f78550 --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/_WhitelistedTokenPair.gql @@ -0,0 +1,52 @@ +query _WhitelistedTokenPair($id: ID!, $block: Block_height){ + _WhitelistedTokenPair(id: $id, block: $block){ + id + pair{ + id + type + swapFee + twapEnabled + name + source + createdAtBlock + createdAtTimestamp + reserve0 + reserve1 + liquidity + liquidityUSD + liquidityNative + trackedLiquidityNative + token0Price + token1Price + volumeNative + volumeUSD + volumeToken0 + volumeToken1 + feesNative + feesUSD + apr + aprUpdatedAtTimestamp + txCount + } + token{ + id + symbol + symbolSuccess + name + nameSuccess + decimals + decimalsSuccess + liquidity + liquidityNative + liquidityUSD + volume + volumeNative + volumeUSD + feesNative + feesUSD + txCount + pairCount + whitelistedPairCount + } + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/_WhitelistedTokenPairs.gql b/packages/sushiswap-watcher/src/gql/queries/_WhitelistedTokenPairs.gql new file mode 100644 index 0000000..3be1662 --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/_WhitelistedTokenPairs.gql @@ -0,0 +1,52 @@ +query _WhitelistedTokenPairs($block: Block_height, $where: _WhitelistedTokenPair_filter, $orderBy: _WhitelistedTokenPair_orderBy, $orderDirection: OrderDirection, $first: Int, $skip: Int){ + _WhitelistedTokenPairs(block: $block, where: $where, orderBy: $orderBy, orderDirection: $orderDirection, first: $first, skip: $skip){ + id + pair{ + id + type + swapFee + twapEnabled + name + source + createdAtBlock + createdAtTimestamp + reserve0 + reserve1 + liquidity + liquidityUSD + liquidityNative + trackedLiquidityNative + token0Price + token1Price + volumeNative + volumeUSD + volumeToken0 + volumeToken1 + feesNative + feesUSD + apr + aprUpdatedAtTimestamp + txCount + } + token{ + id + symbol + symbolSuccess + name + nameSuccess + decimals + decimalsSuccess + liquidity + liquidityNative + liquidityUSD + volume + volumeNative + volumeUSD + feesNative + feesUSD + txCount + pairCount + whitelistedPairCount + } + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/_meta.gql b/packages/sushiswap-watcher/src/gql/queries/_meta.gql new file mode 100644 index 0000000..d686e04 --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/_meta.gql @@ -0,0 +1,11 @@ +query _meta($block: Block_height){ + _meta(block: $block){ + block{ + hash + number + timestamp + } + deployment + hasIndexingErrors + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/bundle.gql b/packages/sushiswap-watcher/src/gql/queries/bundle.gql new file mode 100644 index 0000000..fe156e7 --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/bundle.gql @@ -0,0 +1,6 @@ +query bundle($id: ID!, $block: Block_height){ + bundle(id: $id, block: $block){ + id + nativePrice + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/bundles.gql b/packages/sushiswap-watcher/src/gql/queries/bundles.gql new file mode 100644 index 0000000..2d47827 --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/bundles.gql @@ -0,0 +1,6 @@ +query bundles($block: Block_height, $where: Bundle_filter, $orderBy: Bundle_orderBy, $orderDirection: OrderDirection, $first: Int, $skip: Int){ + bundles(block: $block, where: $where, orderBy: $orderBy, orderDirection: $orderDirection, first: $first, skip: $skip){ + id + nativePrice + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/burn.gql b/packages/sushiswap-watcher/src/gql/queries/burn.gql new file mode 100644 index 0000000..64c8154 --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/burn.gql @@ -0,0 +1,50 @@ +query burn($id: ID!, $block: Block_height){ + burn(id: $id, block: $block){ + id + transaction{ + id + gasLimit + gasPrice + createdAtBlock + createdAtTimestamp + } + timestamp + pair{ + id + type + swapFee + twapEnabled + name + source + createdAtBlock + createdAtTimestamp + reserve0 + reserve1 + liquidity + liquidityUSD + liquidityNative + trackedLiquidityNative + token0Price + token1Price + volumeNative + volumeUSD + volumeToken0 + volumeToken1 + feesNative + feesUSD + apr + aprUpdatedAtTimestamp + txCount + } + liquidity + sender + amount0 + amount1 + to + logIndex + amountUSD + complete + feeTo + feeLiquidity + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/burns.gql b/packages/sushiswap-watcher/src/gql/queries/burns.gql new file mode 100644 index 0000000..184995a --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/burns.gql @@ -0,0 +1,50 @@ +query burns($block: Block_height, $where: Burn_filter, $orderBy: Burn_orderBy, $orderDirection: OrderDirection, $first: Int, $skip: Int){ + burns(block: $block, where: $where, orderBy: $orderBy, orderDirection: $orderDirection, first: $first, skip: $skip){ + id + transaction{ + id + gasLimit + gasPrice + createdAtBlock + createdAtTimestamp + } + timestamp + pair{ + id + type + swapFee + twapEnabled + name + source + createdAtBlock + createdAtTimestamp + reserve0 + reserve1 + liquidity + liquidityUSD + liquidityNative + trackedLiquidityNative + token0Price + token1Price + volumeNative + volumeUSD + volumeToken0 + volumeToken1 + feesNative + feesUSD + apr + aprUpdatedAtTimestamp + txCount + } + liquidity + sender + amount0 + amount1 + to + logIndex + amountUSD + complete + feeTo + feeLiquidity + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/events.gql b/packages/sushiswap-watcher/src/gql/queries/events.gql new file mode 100644 index 0000000..03b8121 --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/events.gql @@ -0,0 +1,63 @@ +query events($blockHash: String!, $contractAddress: String!, $name: String){ + events(blockHash: $blockHash, contractAddress: $contractAddress, name: $name){ + block{ + cid + hash + number + timestamp + parentHash + } + tx{ + hash + index + from + to + } + contract + eventIndex + event{ + ... on PairCreatedEvent { + token0 + token1 + pair + null + } + ... on ApprovalEvent { + owner + spender + value + } + ... on BurnEvent { + sender + amount0 + amount1 + to + } + ... on MintEvent { + sender + amount0 + amount1 + } + ... on SwapEvent { + sender + amount0In + amount1In + amount0Out + amount1Out + to + } + ... on SyncEvent { + reserve0 + reserve1 + } + ... on TransferEvent { + from + to + value + } + } + proof{ + data + } + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/eventsInRange.gql b/packages/sushiswap-watcher/src/gql/queries/eventsInRange.gql new file mode 100644 index 0000000..edf319a --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/eventsInRange.gql @@ -0,0 +1,63 @@ +query eventsInRange($fromBlockNumber: Int!, $toBlockNumber: Int!){ + eventsInRange(fromBlockNumber: $fromBlockNumber, toBlockNumber: $toBlockNumber){ + block{ + cid + hash + number + timestamp + parentHash + } + tx{ + hash + index + from + to + } + contract + eventIndex + event{ + ... on PairCreatedEvent { + token0 + token1 + pair + null + } + ... on ApprovalEvent { + owner + spender + value + } + ... on BurnEvent { + sender + amount0 + amount1 + to + } + ... on MintEvent { + sender + amount0 + amount1 + } + ... on SwapEvent { + sender + amount0In + amount1In + amount0Out + amount1Out + to + } + ... on SyncEvent { + reserve0 + reserve1 + } + ... on TransferEvent { + from + to + value + } + } + proof{ + data + } + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/factories.gql b/packages/sushiswap-watcher/src/gql/queries/factories.gql new file mode 100644 index 0000000..cadaba4 --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/factories.gql @@ -0,0 +1,16 @@ +query factories($block: Block_height, $where: Factory_filter, $orderBy: Factory_orderBy, $orderDirection: OrderDirection, $first: Int, $skip: Int){ + factories(block: $block, where: $where, orderBy: $orderBy, orderDirection: $orderDirection, first: $first, skip: $skip){ + id + type + volumeUSD + volumeNative + liquidityUSD + liquidityNative + feesUSD + feesNative + pairCount + transactionCount + tokenCount + userCount + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/factory.gql b/packages/sushiswap-watcher/src/gql/queries/factory.gql new file mode 100644 index 0000000..36422d9 --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/factory.gql @@ -0,0 +1,16 @@ +query factory($id: ID!, $block: Block_height){ + factory(id: $id, block: $block){ + id + type + volumeUSD + volumeNative + liquidityUSD + liquidityNative + feesUSD + feesNative + pairCount + transactionCount + tokenCount + userCount + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/factoryDaySnapshot.gql b/packages/sushiswap-watcher/src/gql/queries/factoryDaySnapshot.gql new file mode 100644 index 0000000..2410d9c --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/factoryDaySnapshot.gql @@ -0,0 +1,27 @@ +query factoryDaySnapshot($id: ID!, $block: Block_height){ + factoryDaySnapshot(id: $id, block: $block){ + id + factory{ + id + type + volumeUSD + volumeNative + liquidityUSD + liquidityNative + feesUSD + feesNative + pairCount + transactionCount + tokenCount + userCount + } + date + volumeUSD + volumeNative + liquidityNative + liquidityUSD + feesNative + feesUSD + transactionCount + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/factoryDaySnapshots.gql b/packages/sushiswap-watcher/src/gql/queries/factoryDaySnapshots.gql new file mode 100644 index 0000000..efa965e --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/factoryDaySnapshots.gql @@ -0,0 +1,27 @@ +query factoryDaySnapshots($block: Block_height, $where: FactoryDaySnapshot_filter, $orderBy: FactoryDaySnapshot_orderBy, $orderDirection: OrderDirection, $first: Int, $skip: Int){ + factoryDaySnapshots(block: $block, where: $where, orderBy: $orderBy, orderDirection: $orderDirection, first: $first, skip: $skip){ + id + factory{ + id + type + volumeUSD + volumeNative + liquidityUSD + liquidityNative + feesUSD + feesNative + pairCount + transactionCount + tokenCount + userCount + } + date + volumeUSD + volumeNative + liquidityNative + liquidityUSD + feesNative + feesUSD + transactionCount + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/factoryHourSnapshot.gql b/packages/sushiswap-watcher/src/gql/queries/factoryHourSnapshot.gql new file mode 100644 index 0000000..a854f7a --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/factoryHourSnapshot.gql @@ -0,0 +1,27 @@ +query factoryHourSnapshot($id: ID!, $block: Block_height){ + factoryHourSnapshot(id: $id, block: $block){ + id + factory{ + id + type + volumeUSD + volumeNative + liquidityUSD + liquidityNative + feesUSD + feesNative + pairCount + transactionCount + tokenCount + userCount + } + date + volumeUSD + volumeNative + liquidityNative + liquidityUSD + feesNative + feesUSD + transactionCount + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/factoryHourSnapshots.gql b/packages/sushiswap-watcher/src/gql/queries/factoryHourSnapshots.gql new file mode 100644 index 0000000..2015d21 --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/factoryHourSnapshots.gql @@ -0,0 +1,27 @@ +query factoryHourSnapshots($block: Block_height, $where: FactoryHourSnapshot_filter, $orderBy: FactoryHourSnapshot_orderBy, $orderDirection: OrderDirection, $first: Int, $skip: Int){ + factoryHourSnapshots(block: $block, where: $where, orderBy: $orderBy, orderDirection: $orderDirection, first: $first, skip: $skip){ + id + factory{ + id + type + volumeUSD + volumeNative + liquidityUSD + liquidityNative + feesUSD + feesNative + pairCount + transactionCount + tokenCount + userCount + } + date + volumeUSD + volumeNative + liquidityNative + liquidityUSD + feesNative + feesUSD + transactionCount + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/getState.gql b/packages/sushiswap-watcher/src/gql/queries/getState.gql new file mode 100644 index 0000000..3b8f605 --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/getState.gql @@ -0,0 +1,15 @@ +query getState($blockHash: String!, $contractAddress: String!, $kind: String){ + getState(blockHash: $blockHash, contractAddress: $contractAddress, kind: $kind){ + block{ + cid + hash + number + timestamp + parentHash + } + contractAddress + cid + kind + data + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/getStateByCID.gql b/packages/sushiswap-watcher/src/gql/queries/getStateByCID.gql new file mode 100644 index 0000000..6c3c4fd --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/getStateByCID.gql @@ -0,0 +1,15 @@ +query getStateByCID($cid: String!){ + getStateByCID(cid: $cid){ + block{ + cid + hash + number + timestamp + parentHash + } + contractAddress + cid + kind + data + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/getSyncStatus.gql b/packages/sushiswap-watcher/src/gql/queries/getSyncStatus.gql new file mode 100644 index 0000000..48175b4 --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/getSyncStatus.gql @@ -0,0 +1,12 @@ +query getSyncStatus{ + getSyncStatus{ + latestIndexedBlockHash + latestIndexedBlockNumber + latestCanonicalBlockHash + latestCanonicalBlockNumber + initialIndexedBlockHash + initialIndexedBlockNumber + latestProcessedBlockHash + latestProcessedBlockNumber + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/index.ts b/packages/sushiswap-watcher/src/gql/queries/index.ts new file mode 100644 index 0000000..63a6a35 --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/index.ts @@ -0,0 +1,49 @@ +import fs from 'fs'; +import path from 'path'; + +export const events = fs.readFileSync(path.join(__dirname, 'events.gql'), 'utf8'); +export const eventsInRange = fs.readFileSync(path.join(__dirname, 'eventsInRange.gql'), 'utf8'); +export const factory = fs.readFileSync(path.join(__dirname, 'factory.gql'), 'utf8'); +export const factories = fs.readFileSync(path.join(__dirname, 'factories.gql'), 'utf8'); +export const bundle = fs.readFileSync(path.join(__dirname, 'bundle.gql'), 'utf8'); +export const bundles = fs.readFileSync(path.join(__dirname, 'bundles.gql'), 'utf8'); +export const token = fs.readFileSync(path.join(__dirname, 'token.gql'), 'utf8'); +export const tokens = fs.readFileSync(path.join(__dirname, 'tokens.gql'), 'utf8'); +export const tokenPrice = fs.readFileSync(path.join(__dirname, 'tokenPrice.gql'), 'utf8'); +export const tokenPrices = fs.readFileSync(path.join(__dirname, 'tokenPrices.gql'), 'utf8'); +export const _TokenPair = fs.readFileSync(path.join(__dirname, '_TokenPair.gql'), 'utf8'); +export const _TokenPairs = fs.readFileSync(path.join(__dirname, '_TokenPairs.gql'), 'utf8'); +export const _WhitelistedTokenPair = fs.readFileSync(path.join(__dirname, '_WhitelistedTokenPair.gql'), 'utf8'); +export const _WhitelistedTokenPairs = fs.readFileSync(path.join(__dirname, '_WhitelistedTokenPairs.gql'), 'utf8'); +export const pair = fs.readFileSync(path.join(__dirname, 'pair.gql'), 'utf8'); +export const pairs = fs.readFileSync(path.join(__dirname, 'pairs.gql'), 'utf8'); +export const user = fs.readFileSync(path.join(__dirname, 'user.gql'), 'utf8'); +export const users = fs.readFileSync(path.join(__dirname, 'users.gql'), 'utf8'); +export const liquidityPosition = fs.readFileSync(path.join(__dirname, 'liquidityPosition.gql'), 'utf8'); +export const liquidityPositions = fs.readFileSync(path.join(__dirname, 'liquidityPositions.gql'), 'utf8'); +export const mint = fs.readFileSync(path.join(__dirname, 'mint.gql'), 'utf8'); +export const mints = fs.readFileSync(path.join(__dirname, 'mints.gql'), 'utf8'); +export const burn = fs.readFileSync(path.join(__dirname, 'burn.gql'), 'utf8'); +export const burns = fs.readFileSync(path.join(__dirname, 'burns.gql'), 'utf8'); +export const swap = fs.readFileSync(path.join(__dirname, 'swap.gql'), 'utf8'); +export const swaps = fs.readFileSync(path.join(__dirname, 'swaps.gql'), 'utf8'); +export const transaction = fs.readFileSync(path.join(__dirname, 'transaction.gql'), 'utf8'); +export const transactions = fs.readFileSync(path.join(__dirname, 'transactions.gql'), 'utf8'); +export const liquidityPositionSnapshot = fs.readFileSync(path.join(__dirname, 'liquidityPositionSnapshot.gql'), 'utf8'); +export const liquidityPositionSnapshots = fs.readFileSync(path.join(__dirname, 'liquidityPositionSnapshots.gql'), 'utf8'); +export const pairHourSnapshot = fs.readFileSync(path.join(__dirname, 'pairHourSnapshot.gql'), 'utf8'); +export const pairHourSnapshots = fs.readFileSync(path.join(__dirname, 'pairHourSnapshots.gql'), 'utf8'); +export const pairDaySnapshot = fs.readFileSync(path.join(__dirname, 'pairDaySnapshot.gql'), 'utf8'); +export const pairDaySnapshots = fs.readFileSync(path.join(__dirname, 'pairDaySnapshots.gql'), 'utf8'); +export const tokenHourSnapshot = fs.readFileSync(path.join(__dirname, 'tokenHourSnapshot.gql'), 'utf8'); +export const tokenHourSnapshots = fs.readFileSync(path.join(__dirname, 'tokenHourSnapshots.gql'), 'utf8'); +export const tokenDaySnapshot = fs.readFileSync(path.join(__dirname, 'tokenDaySnapshot.gql'), 'utf8'); +export const tokenDaySnapshots = fs.readFileSync(path.join(__dirname, 'tokenDaySnapshots.gql'), 'utf8'); +export const factoryHourSnapshot = fs.readFileSync(path.join(__dirname, 'factoryHourSnapshot.gql'), 'utf8'); +export const factoryHourSnapshots = fs.readFileSync(path.join(__dirname, 'factoryHourSnapshots.gql'), 'utf8'); +export const factoryDaySnapshot = fs.readFileSync(path.join(__dirname, 'factoryDaySnapshot.gql'), 'utf8'); +export const factoryDaySnapshots = fs.readFileSync(path.join(__dirname, 'factoryDaySnapshots.gql'), 'utf8'); +export const _meta = fs.readFileSync(path.join(__dirname, '_meta.gql'), 'utf8'); +export const getStateByCID = fs.readFileSync(path.join(__dirname, 'getStateByCID.gql'), 'utf8'); +export const getState = fs.readFileSync(path.join(__dirname, 'getState.gql'), 'utf8'); +export const getSyncStatus = fs.readFileSync(path.join(__dirname, 'getSyncStatus.gql'), 'utf8'); diff --git a/packages/sushiswap-watcher/src/gql/queries/liquidityPosition.gql b/packages/sushiswap-watcher/src/gql/queries/liquidityPosition.gql new file mode 100644 index 0000000..fa948c2 --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/liquidityPosition.gql @@ -0,0 +1,39 @@ +query liquidityPosition($id: ID!, $block: Block_height){ + liquidityPosition(id: $id, block: $block){ + id + pair{ + id + type + swapFee + twapEnabled + name + source + createdAtBlock + createdAtTimestamp + reserve0 + reserve1 + liquidity + liquidityUSD + liquidityNative + trackedLiquidityNative + token0Price + token1Price + volumeNative + volumeUSD + volumeToken0 + volumeToken1 + feesNative + feesUSD + apr + aprUpdatedAtTimestamp + txCount + } + user{ + id + lpSnapshotsCount + } + balance + createdAtBlock + createdAtTimestamp + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/liquidityPositionSnapshot.gql b/packages/sushiswap-watcher/src/gql/queries/liquidityPositionSnapshot.gql new file mode 100644 index 0000000..41ebce6 --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/liquidityPositionSnapshot.gql @@ -0,0 +1,51 @@ +query liquidityPositionSnapshot($id: ID!, $block: Block_height){ + liquidityPositionSnapshot(id: $id, block: $block){ + id + liquidityPosition{ + id + balance + createdAtBlock + createdAtTimestamp + } + timestamp + block + user{ + id + lpSnapshotsCount + } + pair{ + id + type + swapFee + twapEnabled + name + source + createdAtBlock + createdAtTimestamp + reserve0 + reserve1 + liquidity + liquidityUSD + liquidityNative + trackedLiquidityNative + token0Price + token1Price + volumeNative + volumeUSD + volumeToken0 + volumeToken1 + feesNative + feesUSD + apr + aprUpdatedAtTimestamp + txCount + } + token0PriceUSD + token1PriceUSD + reserve0 + reserve1 + reserveUSD + liquidityTokenTotalSupply + liquidityTokenBalance + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/liquidityPositionSnapshots.gql b/packages/sushiswap-watcher/src/gql/queries/liquidityPositionSnapshots.gql new file mode 100644 index 0000000..f56f868 --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/liquidityPositionSnapshots.gql @@ -0,0 +1,51 @@ +query liquidityPositionSnapshots($block: Block_height, $where: LiquidityPositionSnapshot_filter, $orderBy: LiquidityPositionSnapshot_orderBy, $orderDirection: OrderDirection, $first: Int, $skip: Int){ + liquidityPositionSnapshots(block: $block, where: $where, orderBy: $orderBy, orderDirection: $orderDirection, first: $first, skip: $skip){ + id + liquidityPosition{ + id + balance + createdAtBlock + createdAtTimestamp + } + timestamp + block + user{ + id + lpSnapshotsCount + } + pair{ + id + type + swapFee + twapEnabled + name + source + createdAtBlock + createdAtTimestamp + reserve0 + reserve1 + liquidity + liquidityUSD + liquidityNative + trackedLiquidityNative + token0Price + token1Price + volumeNative + volumeUSD + volumeToken0 + volumeToken1 + feesNative + feesUSD + apr + aprUpdatedAtTimestamp + txCount + } + token0PriceUSD + token1PriceUSD + reserve0 + reserve1 + reserveUSD + liquidityTokenTotalSupply + liquidityTokenBalance + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/liquidityPositions.gql b/packages/sushiswap-watcher/src/gql/queries/liquidityPositions.gql new file mode 100644 index 0000000..f9f7d2f --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/liquidityPositions.gql @@ -0,0 +1,39 @@ +query liquidityPositions($block: Block_height, $where: LiquidityPosition_filter, $orderBy: LiquidityPosition_orderBy, $orderDirection: OrderDirection, $first: Int, $skip: Int){ + liquidityPositions(block: $block, where: $where, orderBy: $orderBy, orderDirection: $orderDirection, first: $first, skip: $skip){ + id + pair{ + id + type + swapFee + twapEnabled + name + source + createdAtBlock + createdAtTimestamp + reserve0 + reserve1 + liquidity + liquidityUSD + liquidityNative + trackedLiquidityNative + token0Price + token1Price + volumeNative + volumeUSD + volumeToken0 + volumeToken1 + feesNative + feesUSD + apr + aprUpdatedAtTimestamp + txCount + } + user{ + id + lpSnapshotsCount + } + balance + createdAtBlock + createdAtTimestamp + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/mint.gql b/packages/sushiswap-watcher/src/gql/queries/mint.gql new file mode 100644 index 0000000..5a0115f --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/mint.gql @@ -0,0 +1,49 @@ +query mint($id: ID!, $block: Block_height){ + mint(id: $id, block: $block){ + id + transaction{ + id + gasLimit + gasPrice + createdAtBlock + createdAtTimestamp + } + timestamp + pair{ + id + type + swapFee + twapEnabled + name + source + createdAtBlock + createdAtTimestamp + reserve0 + reserve1 + liquidity + liquidityUSD + liquidityNative + trackedLiquidityNative + token0Price + token1Price + volumeNative + volumeUSD + volumeToken0 + volumeToken1 + feesNative + feesUSD + apr + aprUpdatedAtTimestamp + txCount + } + to + liquidity + sender + amount0 + amount1 + logIndex + amountUSD + feeTo + feeLiquidity + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/mints.gql b/packages/sushiswap-watcher/src/gql/queries/mints.gql new file mode 100644 index 0000000..dece868 --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/mints.gql @@ -0,0 +1,49 @@ +query mints($block: Block_height, $where: Mint_filter, $orderBy: Mint_orderBy, $orderDirection: OrderDirection, $first: Int, $skip: Int){ + mints(block: $block, where: $where, orderBy: $orderBy, orderDirection: $orderDirection, first: $first, skip: $skip){ + id + transaction{ + id + gasLimit + gasPrice + createdAtBlock + createdAtTimestamp + } + timestamp + pair{ + id + type + swapFee + twapEnabled + name + source + createdAtBlock + createdAtTimestamp + reserve0 + reserve1 + liquidity + liquidityUSD + liquidityNative + trackedLiquidityNative + token0Price + token1Price + volumeNative + volumeUSD + volumeToken0 + volumeToken1 + feesNative + feesUSD + apr + aprUpdatedAtTimestamp + txCount + } + to + liquidity + sender + amount0 + amount1 + logIndex + amountUSD + feeTo + feeLiquidity + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/pair.gql b/packages/sushiswap-watcher/src/gql/queries/pair.gql new file mode 100644 index 0000000..1cad206 --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/pair.gql @@ -0,0 +1,119 @@ +query pair($id: ID!, $block: Block_height){ + pair(id: $id, block: $block){ + id + type + swapFee + twapEnabled + name + token0{ + id + symbol + symbolSuccess + name + nameSuccess + decimals + decimalsSuccess + liquidity + liquidityNative + liquidityUSD + volume + volumeNative + volumeUSD + feesNative + feesUSD + txCount + pairCount + whitelistedPairCount + } + token1{ + id + symbol + symbolSuccess + name + nameSuccess + decimals + decimalsSuccess + liquidity + liquidityNative + liquidityUSD + volume + volumeNative + volumeUSD + feesNative + feesUSD + txCount + pairCount + whitelistedPairCount + } + source + createdAtBlock + createdAtTimestamp + reserve0 + reserve1 + liquidity + liquidityUSD + liquidityNative + trackedLiquidityNative + token0Price + token1Price + volumeNative + volumeUSD + volumeToken0 + volumeToken1 + feesNative + feesUSD + apr + aprUpdatedAtTimestamp + txCount + liquidityPositions{ + id + balance + createdAtBlock + createdAtTimestamp + } + liquidityPositionSnapshots{ + id + timestamp + block + token0PriceUSD + token1PriceUSD + reserve0 + reserve1 + reserveUSD + liquidityTokenTotalSupply + liquidityTokenBalance + } + hourSnapshots{ + id + date + cumulativeVolumeUSD + volumeUSD + volumeNative + volumeToken0 + volumeToken1 + liquidity + liquidityNative + liquidityUSD + feesNative + feesUSD + apr + transactionCount + } + daySnapshots{ + id + date + cumulativeVolumeUSD + volumeUSD + volumeNative + volumeToken0 + volumeToken1 + liquidity + liquidityNative + liquidityUSD + feesNative + feesUSD + apr + transactionCount + } + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/pairDaySnapshot.gql b/packages/sushiswap-watcher/src/gql/queries/pairDaySnapshot.gql new file mode 100644 index 0000000..24ed11e --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/pairDaySnapshot.gql @@ -0,0 +1,45 @@ +query pairDaySnapshot($id: ID!, $block: Block_height){ + pairDaySnapshot(id: $id, block: $block){ + id + pair{ + id + type + swapFee + twapEnabled + name + source + createdAtBlock + createdAtTimestamp + reserve0 + reserve1 + liquidity + liquidityUSD + liquidityNative + trackedLiquidityNative + token0Price + token1Price + volumeNative + volumeUSD + volumeToken0 + volumeToken1 + feesNative + feesUSD + apr + aprUpdatedAtTimestamp + txCount + } + date + cumulativeVolumeUSD + volumeUSD + volumeNative + volumeToken0 + volumeToken1 + liquidity + liquidityNative + liquidityUSD + feesNative + feesUSD + apr + transactionCount + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/pairDaySnapshots.gql b/packages/sushiswap-watcher/src/gql/queries/pairDaySnapshots.gql new file mode 100644 index 0000000..b8fa060 --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/pairDaySnapshots.gql @@ -0,0 +1,45 @@ +query pairDaySnapshots($block: Block_height, $where: PairDaySnapshot_filter, $orderBy: PairDaySnapshot_orderBy, $orderDirection: OrderDirection, $first: Int, $skip: Int){ + pairDaySnapshots(block: $block, where: $where, orderBy: $orderBy, orderDirection: $orderDirection, first: $first, skip: $skip){ + id + pair{ + id + type + swapFee + twapEnabled + name + source + createdAtBlock + createdAtTimestamp + reserve0 + reserve1 + liquidity + liquidityUSD + liquidityNative + trackedLiquidityNative + token0Price + token1Price + volumeNative + volumeUSD + volumeToken0 + volumeToken1 + feesNative + feesUSD + apr + aprUpdatedAtTimestamp + txCount + } + date + cumulativeVolumeUSD + volumeUSD + volumeNative + volumeToken0 + volumeToken1 + liquidity + liquidityNative + liquidityUSD + feesNative + feesUSD + apr + transactionCount + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/pairHourSnapshot.gql b/packages/sushiswap-watcher/src/gql/queries/pairHourSnapshot.gql new file mode 100644 index 0000000..7392c93 --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/pairHourSnapshot.gql @@ -0,0 +1,45 @@ +query pairHourSnapshot($id: ID!, $block: Block_height){ + pairHourSnapshot(id: $id, block: $block){ + id + pair{ + id + type + swapFee + twapEnabled + name + source + createdAtBlock + createdAtTimestamp + reserve0 + reserve1 + liquidity + liquidityUSD + liquidityNative + trackedLiquidityNative + token0Price + token1Price + volumeNative + volumeUSD + volumeToken0 + volumeToken1 + feesNative + feesUSD + apr + aprUpdatedAtTimestamp + txCount + } + date + cumulativeVolumeUSD + volumeUSD + volumeNative + volumeToken0 + volumeToken1 + liquidity + liquidityNative + liquidityUSD + feesNative + feesUSD + apr + transactionCount + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/pairHourSnapshots.gql b/packages/sushiswap-watcher/src/gql/queries/pairHourSnapshots.gql new file mode 100644 index 0000000..f144927 --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/pairHourSnapshots.gql @@ -0,0 +1,45 @@ +query pairHourSnapshots($block: Block_height, $where: PairHourSnapshot_filter, $orderBy: PairHourSnapshot_orderBy, $orderDirection: OrderDirection, $first: Int, $skip: Int){ + pairHourSnapshots(block: $block, where: $where, orderBy: $orderBy, orderDirection: $orderDirection, first: $first, skip: $skip){ + id + pair{ + id + type + swapFee + twapEnabled + name + source + createdAtBlock + createdAtTimestamp + reserve0 + reserve1 + liquidity + liquidityUSD + liquidityNative + trackedLiquidityNative + token0Price + token1Price + volumeNative + volumeUSD + volumeToken0 + volumeToken1 + feesNative + feesUSD + apr + aprUpdatedAtTimestamp + txCount + } + date + cumulativeVolumeUSD + volumeUSD + volumeNative + volumeToken0 + volumeToken1 + liquidity + liquidityNative + liquidityUSD + feesNative + feesUSD + apr + transactionCount + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/pairs.gql b/packages/sushiswap-watcher/src/gql/queries/pairs.gql new file mode 100644 index 0000000..0331a34 --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/pairs.gql @@ -0,0 +1,119 @@ +query pairs($block: Block_height, $where: Pair_filter, $orderBy: Pair_orderBy, $orderDirection: OrderDirection, $first: Int, $skip: Int){ + pairs(block: $block, where: $where, orderBy: $orderBy, orderDirection: $orderDirection, first: $first, skip: $skip){ + id + type + swapFee + twapEnabled + name + token0{ + id + symbol + symbolSuccess + name + nameSuccess + decimals + decimalsSuccess + liquidity + liquidityNative + liquidityUSD + volume + volumeNative + volumeUSD + feesNative + feesUSD + txCount + pairCount + whitelistedPairCount + } + token1{ + id + symbol + symbolSuccess + name + nameSuccess + decimals + decimalsSuccess + liquidity + liquidityNative + liquidityUSD + volume + volumeNative + volumeUSD + feesNative + feesUSD + txCount + pairCount + whitelistedPairCount + } + source + createdAtBlock + createdAtTimestamp + reserve0 + reserve1 + liquidity + liquidityUSD + liquidityNative + trackedLiquidityNative + token0Price + token1Price + volumeNative + volumeUSD + volumeToken0 + volumeToken1 + feesNative + feesUSD + apr + aprUpdatedAtTimestamp + txCount + liquidityPositions{ + id + balance + createdAtBlock + createdAtTimestamp + } + liquidityPositionSnapshots{ + id + timestamp + block + token0PriceUSD + token1PriceUSD + reserve0 + reserve1 + reserveUSD + liquidityTokenTotalSupply + liquidityTokenBalance + } + hourSnapshots{ + id + date + cumulativeVolumeUSD + volumeUSD + volumeNative + volumeToken0 + volumeToken1 + liquidity + liquidityNative + liquidityUSD + feesNative + feesUSD + apr + transactionCount + } + daySnapshots{ + id + date + cumulativeVolumeUSD + volumeUSD + volumeNative + volumeToken0 + volumeToken1 + liquidity + liquidityNative + liquidityUSD + feesNative + feesUSD + apr + transactionCount + } + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/swap.gql b/packages/sushiswap-watcher/src/gql/queries/swap.gql new file mode 100644 index 0000000..a7d1872 --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/swap.gql @@ -0,0 +1,86 @@ +query swap($id: ID!, $block: Block_height){ + swap(id: $id, block: $block){ + id + transaction{ + id + gasLimit + gasPrice + createdAtBlock + createdAtTimestamp + } + timestamp + pair{ + id + type + swapFee + twapEnabled + name + source + createdAtBlock + createdAtTimestamp + reserve0 + reserve1 + liquidity + liquidityUSD + liquidityNative + trackedLiquidityNative + token0Price + token1Price + volumeNative + volumeUSD + volumeToken0 + volumeToken1 + feesNative + feesUSD + apr + aprUpdatedAtTimestamp + txCount + } + sender + tokenIn{ + id + symbol + symbolSuccess + name + nameSuccess + decimals + decimalsSuccess + liquidity + liquidityNative + liquidityUSD + volume + volumeNative + volumeUSD + feesNative + feesUSD + txCount + pairCount + whitelistedPairCount + } + tokenOut{ + id + symbol + symbolSuccess + name + nameSuccess + decimals + decimalsSuccess + liquidity + liquidityNative + liquidityUSD + volume + volumeNative + volumeUSD + feesNative + feesUSD + txCount + pairCount + whitelistedPairCount + } + amountIn + amountOut + to + logIndex + amountUSD + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/swaps.gql b/packages/sushiswap-watcher/src/gql/queries/swaps.gql new file mode 100644 index 0000000..dded99c --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/swaps.gql @@ -0,0 +1,86 @@ +query swaps($block: Block_height, $where: Swap_filter, $orderBy: Swap_orderBy, $orderDirection: OrderDirection, $first: Int, $skip: Int){ + swaps(block: $block, where: $where, orderBy: $orderBy, orderDirection: $orderDirection, first: $first, skip: $skip){ + id + transaction{ + id + gasLimit + gasPrice + createdAtBlock + createdAtTimestamp + } + timestamp + pair{ + id + type + swapFee + twapEnabled + name + source + createdAtBlock + createdAtTimestamp + reserve0 + reserve1 + liquidity + liquidityUSD + liquidityNative + trackedLiquidityNative + token0Price + token1Price + volumeNative + volumeUSD + volumeToken0 + volumeToken1 + feesNative + feesUSD + apr + aprUpdatedAtTimestamp + txCount + } + sender + tokenIn{ + id + symbol + symbolSuccess + name + nameSuccess + decimals + decimalsSuccess + liquidity + liquidityNative + liquidityUSD + volume + volumeNative + volumeUSD + feesNative + feesUSD + txCount + pairCount + whitelistedPairCount + } + tokenOut{ + id + symbol + symbolSuccess + name + nameSuccess + decimals + decimalsSuccess + liquidity + liquidityNative + liquidityUSD + volume + volumeNative + volumeUSD + feesNative + feesUSD + txCount + pairCount + whitelistedPairCount + } + amountIn + amountOut + to + logIndex + amountUSD + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/token.gql b/packages/sushiswap-watcher/src/gql/queries/token.gql new file mode 100644 index 0000000..8bd95fc --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/token.gql @@ -0,0 +1,33 @@ +query token($id: ID!, $block: Block_height){ + token(id: $id, block: $block){ + id + price{ + id + derivedNative + lastUsdPrice + } + symbol + symbolSuccess + name + nameSuccess + decimals + decimalsSuccess + liquidity + liquidityNative + liquidityUSD + volume + volumeNative + volumeUSD + feesNative + feesUSD + txCount + pairCount + whitelistedPairCount + pairs{ + id + } + whitelistedPairs{ + id + } + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/tokenDaySnapshot.gql b/packages/sushiswap-watcher/src/gql/queries/tokenDaySnapshot.gql new file mode 100644 index 0000000..bfa3dc6 --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/tokenDaySnapshot.gql @@ -0,0 +1,37 @@ +query tokenDaySnapshot($id: ID!, $block: Block_height){ + tokenDaySnapshot(id: $id, block: $block){ + id + date + token{ + id + symbol + symbolSuccess + name + nameSuccess + decimals + decimalsSuccess + liquidity + liquidityNative + liquidityUSD + volume + volumeNative + volumeUSD + feesNative + feesUSD + txCount + pairCount + whitelistedPairCount + } + liquidity + liquidityNative + liquidityUSD + volume + volumeNative + volumeUSD + priceNative + priceUSD + feesNative + feesUSD + transactionCount + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/tokenDaySnapshots.gql b/packages/sushiswap-watcher/src/gql/queries/tokenDaySnapshots.gql new file mode 100644 index 0000000..1233ec0 --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/tokenDaySnapshots.gql @@ -0,0 +1,37 @@ +query tokenDaySnapshots($block: Block_height, $where: TokenDaySnapshot_filter, $orderBy: TokenDaySnapshot_orderBy, $orderDirection: OrderDirection, $first: Int, $skip: Int){ + tokenDaySnapshots(block: $block, where: $where, orderBy: $orderBy, orderDirection: $orderDirection, first: $first, skip: $skip){ + id + date + token{ + id + symbol + symbolSuccess + name + nameSuccess + decimals + decimalsSuccess + liquidity + liquidityNative + liquidityUSD + volume + volumeNative + volumeUSD + feesNative + feesUSD + txCount + pairCount + whitelistedPairCount + } + liquidity + liquidityNative + liquidityUSD + volume + volumeNative + volumeUSD + priceNative + priceUSD + feesNative + feesUSD + transactionCount + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/tokenHourSnapshot.gql b/packages/sushiswap-watcher/src/gql/queries/tokenHourSnapshot.gql new file mode 100644 index 0000000..3ce1de4 --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/tokenHourSnapshot.gql @@ -0,0 +1,37 @@ +query tokenHourSnapshot($id: ID!, $block: Block_height){ + tokenHourSnapshot(id: $id, block: $block){ + id + date + token{ + id + symbol + symbolSuccess + name + nameSuccess + decimals + decimalsSuccess + liquidity + liquidityNative + liquidityUSD + volume + volumeNative + volumeUSD + feesNative + feesUSD + txCount + pairCount + whitelistedPairCount + } + liquidity + liquidityNative + liquidityUSD + volume + volumeNative + volumeUSD + priceNative + priceUSD + feesNative + feesUSD + transactionCount + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/tokenHourSnapshots.gql b/packages/sushiswap-watcher/src/gql/queries/tokenHourSnapshots.gql new file mode 100644 index 0000000..90750a7 --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/tokenHourSnapshots.gql @@ -0,0 +1,37 @@ +query tokenHourSnapshots($block: Block_height, $where: TokenHourSnapshot_filter, $orderBy: TokenHourSnapshot_orderBy, $orderDirection: OrderDirection, $first: Int, $skip: Int){ + tokenHourSnapshots(block: $block, where: $where, orderBy: $orderBy, orderDirection: $orderDirection, first: $first, skip: $skip){ + id + date + token{ + id + symbol + symbolSuccess + name + nameSuccess + decimals + decimalsSuccess + liquidity + liquidityNative + liquidityUSD + volume + volumeNative + volumeUSD + feesNative + feesUSD + txCount + pairCount + whitelistedPairCount + } + liquidity + liquidityNative + liquidityUSD + volume + volumeNative + volumeUSD + priceNative + priceUSD + feesNative + feesUSD + transactionCount + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/tokenPrice.gql b/packages/sushiswap-watcher/src/gql/queries/tokenPrice.gql new file mode 100644 index 0000000..c2149c8 --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/tokenPrice.gql @@ -0,0 +1,74 @@ +query tokenPrice($id: ID!, $block: Block_height){ + tokenPrice(id: $id, block: $block){ + id + token{ + id + symbol + symbolSuccess + name + nameSuccess + decimals + decimalsSuccess + liquidity + liquidityNative + liquidityUSD + volume + volumeNative + volumeUSD + feesNative + feesUSD + txCount + pairCount + whitelistedPairCount + } + derivedNative + lastUsdPrice + pricedOffToken{ + id + symbol + symbolSuccess + name + nameSuccess + decimals + decimalsSuccess + liquidity + liquidityNative + liquidityUSD + volume + volumeNative + volumeUSD + feesNative + feesUSD + txCount + pairCount + whitelistedPairCount + } + pricedOffPair{ + id + type + swapFee + twapEnabled + name + source + createdAtBlock + createdAtTimestamp + reserve0 + reserve1 + liquidity + liquidityUSD + liquidityNative + trackedLiquidityNative + token0Price + token1Price + volumeNative + volumeUSD + volumeToken0 + volumeToken1 + feesNative + feesUSD + apr + aprUpdatedAtTimestamp + txCount + } + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/tokenPrices.gql b/packages/sushiswap-watcher/src/gql/queries/tokenPrices.gql new file mode 100644 index 0000000..3069e3e --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/tokenPrices.gql @@ -0,0 +1,74 @@ +query tokenPrices($block: Block_height, $where: TokenPrice_filter, $orderBy: TokenPrice_orderBy, $orderDirection: OrderDirection, $first: Int, $skip: Int){ + tokenPrices(block: $block, where: $where, orderBy: $orderBy, orderDirection: $orderDirection, first: $first, skip: $skip){ + id + token{ + id + symbol + symbolSuccess + name + nameSuccess + decimals + decimalsSuccess + liquidity + liquidityNative + liquidityUSD + volume + volumeNative + volumeUSD + feesNative + feesUSD + txCount + pairCount + whitelistedPairCount + } + derivedNative + lastUsdPrice + pricedOffToken{ + id + symbol + symbolSuccess + name + nameSuccess + decimals + decimalsSuccess + liquidity + liquidityNative + liquidityUSD + volume + volumeNative + volumeUSD + feesNative + feesUSD + txCount + pairCount + whitelistedPairCount + } + pricedOffPair{ + id + type + swapFee + twapEnabled + name + source + createdAtBlock + createdAtTimestamp + reserve0 + reserve1 + liquidity + liquidityUSD + liquidityNative + trackedLiquidityNative + token0Price + token1Price + volumeNative + volumeUSD + volumeToken0 + volumeToken1 + feesNative + feesUSD + apr + aprUpdatedAtTimestamp + txCount + } + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/tokens.gql b/packages/sushiswap-watcher/src/gql/queries/tokens.gql new file mode 100644 index 0000000..47b128b --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/tokens.gql @@ -0,0 +1,33 @@ +query tokens($block: Block_height, $where: Token_filter, $orderBy: Token_orderBy, $orderDirection: OrderDirection, $first: Int, $skip: Int){ + tokens(block: $block, where: $where, orderBy: $orderBy, orderDirection: $orderDirection, first: $first, skip: $skip){ + id + price{ + id + derivedNative + lastUsdPrice + } + symbol + symbolSuccess + name + nameSuccess + decimals + decimalsSuccess + liquidity + liquidityNative + liquidityUSD + volume + volumeNative + volumeUSD + feesNative + feesUSD + txCount + pairCount + whitelistedPairCount + pairs{ + id + } + whitelistedPairs{ + id + } + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/transaction.gql b/packages/sushiswap-watcher/src/gql/queries/transaction.gql new file mode 100644 index 0000000..2239f8f --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/transaction.gql @@ -0,0 +1,46 @@ +query transaction($id: ID!, $block: Block_height){ + transaction(id: $id, block: $block){ + id + gasLimit + gasPrice + mints{ + id + timestamp + to + liquidity + sender + amount0 + amount1 + logIndex + amountUSD + feeTo + feeLiquidity + } + burns{ + id + timestamp + liquidity + sender + amount0 + amount1 + to + logIndex + amountUSD + complete + feeTo + feeLiquidity + } + swaps{ + id + timestamp + sender + amountIn + amountOut + to + logIndex + amountUSD + } + createdAtBlock + createdAtTimestamp + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/transactions.gql b/packages/sushiswap-watcher/src/gql/queries/transactions.gql new file mode 100644 index 0000000..a1b4e12 --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/transactions.gql @@ -0,0 +1,46 @@ +query transactions($block: Block_height, $where: Transaction_filter, $orderBy: Transaction_orderBy, $orderDirection: OrderDirection, $first: Int, $skip: Int){ + transactions(block: $block, where: $where, orderBy: $orderBy, orderDirection: $orderDirection, first: $first, skip: $skip){ + id + gasLimit + gasPrice + mints{ + id + timestamp + to + liquidity + sender + amount0 + amount1 + logIndex + amountUSD + feeTo + feeLiquidity + } + burns{ + id + timestamp + liquidity + sender + amount0 + amount1 + to + logIndex + amountUSD + complete + feeTo + feeLiquidity + } + swaps{ + id + timestamp + sender + amountIn + amountOut + to + logIndex + amountUSD + } + createdAtBlock + createdAtTimestamp + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/user.gql b/packages/sushiswap-watcher/src/gql/queries/user.gql new file mode 100644 index 0000000..d7183af --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/user.gql @@ -0,0 +1,12 @@ +query user($id: ID!, $block: Block_height){ + user(id: $id, block: $block){ + id + lpSnapshotsCount + liquidityPositions{ + id + balance + createdAtBlock + createdAtTimestamp + } + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/queries/users.gql b/packages/sushiswap-watcher/src/gql/queries/users.gql new file mode 100644 index 0000000..8344916 --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/queries/users.gql @@ -0,0 +1,12 @@ +query users($block: Block_height, $where: User_filter, $orderBy: User_orderBy, $orderDirection: OrderDirection, $first: Int, $skip: Int){ + users(block: $block, where: $where, orderBy: $orderBy, orderDirection: $orderDirection, first: $first, skip: $skip){ + id + lpSnapshotsCount + liquidityPositions{ + id + balance + createdAtBlock + createdAtTimestamp + } + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/gql/subscriptions/index.ts b/packages/sushiswap-watcher/src/gql/subscriptions/index.ts new file mode 100644 index 0000000..f12910c --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/subscriptions/index.ts @@ -0,0 +1,4 @@ +import fs from 'fs'; +import path from 'path'; + +export const onEvent = fs.readFileSync(path.join(__dirname, 'onEvent.gql'), 'utf8'); diff --git a/packages/sushiswap-watcher/src/gql/subscriptions/onEvent.gql b/packages/sushiswap-watcher/src/gql/subscriptions/onEvent.gql new file mode 100644 index 0000000..305777a --- /dev/null +++ b/packages/sushiswap-watcher/src/gql/subscriptions/onEvent.gql @@ -0,0 +1,63 @@ +subscription onEvent{ + onEvent{ + block{ + cid + hash + number + timestamp + parentHash + } + tx{ + hash + index + from + to + } + contract + eventIndex + event{ + ... on PairCreatedEvent { + token0 + token1 + pair + null + } + ... on ApprovalEvent { + owner + spender + value + } + ... on BurnEvent { + sender + amount0 + amount1 + to + } + ... on MintEvent { + sender + amount0 + amount1 + } + ... on SwapEvent { + sender + amount0In + amount1In + amount0Out + amount1Out + to + } + ... on SyncEvent { + reserve0 + reserve1 + } + ... on TransferEvent { + from + to + value + } + } + proof{ + data + } + } +} \ No newline at end of file diff --git a/packages/sushiswap-watcher/src/hooks.ts b/packages/sushiswap-watcher/src/hooks.ts new file mode 100644 index 0000000..d45498b --- /dev/null +++ b/packages/sushiswap-watcher/src/hooks.ts @@ -0,0 +1,86 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import assert from 'assert'; + +import { + ResultEvent, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + updateStateForMappingType, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + updateStateForElementaryType +} from '@cerc-io/util'; + +import { Indexer } from './indexer'; + +/** + * Hook function to store an initial state. + * @param indexer Indexer instance. + * @param blockHash Hash of the concerned block. + * @param contractAddress Address of the concerned contract. + * @returns Data block to be stored. + */ +export async function createInitialState (indexer: Indexer, contractAddress: string, blockHash: string): Promise { + assert(indexer); + assert(blockHash); + assert(contractAddress); + + // Store an empty State. + const stateData: any = { + state: {} + }; + + // Use updateStateForElementaryType to update initial state with an elementary property. + // Eg. const stateData = updateStateForElementaryType(stateData, '_totalBalance', result.value.toString()); + + // Use updateStateForMappingType to update initial state with a nested property. + // Eg. const stateData = updateStateForMappingType(stateData, '_allowances', [owner, spender], allowance.value.toString()); + + // Return initial state data to be saved. + return stateData; +} + +/** + * Hook function to create state diff. + * @param indexer Indexer instance that contains methods to fetch the contract variable values. + * @param blockHash Block hash of the concerned block. + */ +export async function createStateDiff (indexer: Indexer, blockHash: string): Promise { + assert(indexer); + assert(blockHash); + + // Use indexer.createDiff() method to save custom state diff(s). +} + +/** + * Hook function to create state checkpoint + * @param indexer Indexer instance. + * @param contractAddress Address of the concerned contract. + * @param blockHash Block hash of the concerned block. + * @returns Whether to disable default checkpoint. If false, the state from this hook is updated with that from default checkpoint. + */ +export async function createStateCheckpoint (indexer: Indexer, contractAddress: string, blockHash: string): Promise { + assert(indexer); + assert(blockHash); + assert(contractAddress); + + // Use indexer.createStateCheckpoint() method to create a custom checkpoint. + + // Return false to update the state created by this hook by auto-generated checkpoint state. + // Return true to disable update of the state created by this hook by auto-generated checkpoint state. + return false; +} + +/** + * Event hook function. + * @param indexer Indexer instance that contains methods to fetch and update the contract values in the database. + * @param eventData ResultEvent object containing event information. + */ +export async function handleEvent (indexer: Indexer, eventData: ResultEvent): Promise { + assert(indexer); + assert(eventData); + + // Use indexer methods to index data. + // Pass `diff` parameter to indexer methods as true to save an auto-generated state from the indexed data. +} diff --git a/packages/sushiswap-watcher/src/indexer.ts b/packages/sushiswap-watcher/src/indexer.ts new file mode 100644 index 0000000..b7174d1 --- /dev/null +++ b/packages/sushiswap-watcher/src/indexer.ts @@ -0,0 +1,1197 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import assert from 'assert'; +import { DeepPartial, FindConditions, FindManyOptions, ObjectLiteral } from 'typeorm'; +import debug from 'debug'; +import { ethers, constants } from 'ethers'; +import { GraphQLResolveInfo } from 'graphql'; + +import { JsonFragment } from '@ethersproject/abi'; +import { BaseProvider } from '@ethersproject/providers'; +import { MappingKey, StorageLayout } from '@cerc-io/solidity-mapper'; +import { + Indexer as BaseIndexer, + IndexerInterface, + ValueResult, + ServerConfig, + JobQueue, + Where, + QueryOptions, + BlockHeight, + ResultMeta, + updateSubgraphState, + dumpSubgraphState, + GraphWatcherInterface, + StateKind, + StateStatus, + ResultEvent, + getResultEvent, + DatabaseInterface, + Clients, + EthClient, + UpstreamConfig, + EthFullBlock, + EthFullTransaction, + ExtraEventData +} from '@cerc-io/util'; +import { GraphWatcher } from '@cerc-io/graph-node'; + +import FactoryArtifacts from './artifacts/Factory.json'; +import PairArtifacts from './artifacts/Pair.json'; +import { Database, ENTITIES, SUBGRAPH_ENTITIES } from './database'; +import { createInitialState, handleEvent, createStateDiff, createStateCheckpoint } from './hooks'; +import { Contract } from './entity/Contract'; +import { Event } from './entity/Event'; +import { SyncStatus } from './entity/SyncStatus'; +import { StateSyncStatus } from './entity/StateSyncStatus'; +import { BlockProgress } from './entity/BlockProgress'; +import { State } from './entity/State'; +/* eslint-disable @typescript-eslint/no-unused-vars */ +import { Factory } from './entity/Factory'; +import { Bundle } from './entity/Bundle'; +import { Token } from './entity/Token'; +import { TokenPrice } from './entity/TokenPrice'; +import { _TokenPair } from './entity/_TokenPair'; +import { _WhitelistedTokenPair } from './entity/_WhitelistedTokenPair'; +import { Pair } from './entity/Pair'; +import { User } from './entity/User'; +import { LiquidityPosition } from './entity/LiquidityPosition'; +import { Mint } from './entity/Mint'; +import { Burn } from './entity/Burn'; +import { Swap } from './entity/Swap'; +import { Transaction } from './entity/Transaction'; +import { LiquidityPositionSnapshot } from './entity/LiquidityPositionSnapshot'; +import { PairHourSnapshot } from './entity/PairHourSnapshot'; +import { PairDaySnapshot } from './entity/PairDaySnapshot'; +import { TokenHourSnapshot } from './entity/TokenHourSnapshot'; +import { TokenDaySnapshot } from './entity/TokenDaySnapshot'; +import { FactoryHourSnapshot } from './entity/FactoryHourSnapshot'; +import { FactoryDaySnapshot } from './entity/FactoryDaySnapshot'; +/* eslint-enable @typescript-eslint/no-unused-vars */ + +import { FrothyEntity } from './entity/FrothyEntity'; + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +const log = debug('vulcanize:indexer'); + +const KIND_FACTORY = 'Factory'; + +const KIND_PAIR = 'Pair'; + +export class Indexer implements IndexerInterface { + _db: Database; + _ethClient: EthClient; + _ethProvider: BaseProvider; + _baseIndexer: BaseIndexer; + _serverConfig: ServerConfig; + _upstreamConfig: UpstreamConfig; + _graphWatcher: GraphWatcher; + + _abiMap: Map; + _storageLayoutMap: Map; + _contractMap: Map; + eventSignaturesMap: Map; + + _entityTypesMap: Map; + _relationsMap: Map; + + _subgraphStateMap: Map; + + constructor ( + config: { + server: ServerConfig; + upstream: UpstreamConfig; + }, + db: DatabaseInterface, + clients: Clients, + ethProvider: BaseProvider, + jobQueue: JobQueue, + graphWatcher?: GraphWatcherInterface + ) { + assert(db); + assert(clients.ethClient); + + this._db = db as Database; + this._ethClient = clients.ethClient; + this._ethProvider = ethProvider; + this._serverConfig = config.server; + this._upstreamConfig = config.upstream; + this._baseIndexer = new BaseIndexer(config, this._db, this._ethClient, this._ethProvider, jobQueue); + assert(graphWatcher); + this._graphWatcher = graphWatcher as GraphWatcher; + + this._abiMap = new Map(); + this._storageLayoutMap = new Map(); + this._contractMap = new Map(); + this.eventSignaturesMap = new Map(); + + const { abi: FactoryABI } = FactoryArtifacts; + + const { abi: PairABI } = PairArtifacts; + + assert(FactoryABI); + this._abiMap.set(KIND_FACTORY, FactoryABI); + + const FactoryContractInterface = new ethers.utils.Interface(FactoryABI); + this._contractMap.set(KIND_FACTORY, FactoryContractInterface); + + const FactoryEventSignatures = Object.values(FactoryContractInterface.events).map(value => { + return FactoryContractInterface.getEventTopic(value); + }); + this.eventSignaturesMap.set(KIND_FACTORY, FactoryEventSignatures); + + assert(PairABI); + this._abiMap.set(KIND_PAIR, PairABI); + + const PairContractInterface = new ethers.utils.Interface(PairABI); + this._contractMap.set(KIND_PAIR, PairContractInterface); + + const PairEventSignatures = Object.values(PairContractInterface.events).map(value => { + return PairContractInterface.getEventTopic(value); + }); + this.eventSignaturesMap.set(KIND_PAIR, PairEventSignatures); + + this._entityTypesMap = new Map(); + this._populateEntityTypesMap(); + + this._relationsMap = new Map(); + this._populateRelationsMap(); + + this._subgraphStateMap = new Map(); + } + + get serverConfig (): ServerConfig { + return this._serverConfig; + } + + get upstreamConfig (): UpstreamConfig { + return this._upstreamConfig; + } + + get storageLayoutMap (): Map { + return this._storageLayoutMap; + } + + get graphWatcher (): GraphWatcher { + return this._graphWatcher; + } + + async init (): Promise { + await this._baseIndexer.fetchContracts(); + await this._baseIndexer.fetchStateStatus(); + } + + switchClients ({ ethClient, ethProvider }: { ethClient: EthClient, ethProvider: BaseProvider }): void { + this._ethClient = ethClient; + this._ethProvider = ethProvider; + this._baseIndexer.switchClients({ ethClient, ethProvider }); + this._graphWatcher.switchClients({ ethClient, ethProvider }); + } + + async getMetaData (block: BlockHeight): Promise { + return this._baseIndexer.getMetaData(block); + } + + getResultEvent (event: Event): ResultEvent { + return getResultEvent(event); + } + + async getStorageValue (storageLayout: StorageLayout, blockHash: string, contractAddress: string, variable: string, ...mappingKeys: MappingKey[]): Promise { + return this._baseIndexer.getStorageValue( + storageLayout, + blockHash, + contractAddress, + variable, + ...mappingKeys + ); + } + + async getEntitiesForBlock (blockHash: string, tableName: string): Promise { + return this._db.getEntitiesForBlock(blockHash, tableName); + } + + async processInitialState (contractAddress: string, blockHash: string): Promise { + // Call initial state hook. + return createInitialState(this, contractAddress, blockHash); + } + + async processStateCheckpoint (contractAddress: string, blockHash: string): Promise { + // Call checkpoint hook. + return createStateCheckpoint(this, contractAddress, blockHash); + } + + async processCanonicalBlock (blockHash: string, blockNumber: number): Promise { + console.time('time:indexer#processCanonicalBlock-finalize_auto_diffs'); + // Finalize staged diff blocks if any. + await this._baseIndexer.finalizeDiffStaged(blockHash); + console.timeEnd('time:indexer#processCanonicalBlock-finalize_auto_diffs'); + + // Call custom stateDiff hook. + await createStateDiff(this, blockHash); + + this._graphWatcher.pruneEntityCacheFrothyBlocks(blockHash, blockNumber); + } + + async processCheckpoint (blockHash: string): Promise { + // Return if checkpointInterval is <= 0. + const checkpointInterval = this._serverConfig.checkpointInterval; + if (checkpointInterval <= 0) return; + + console.time('time:indexer#processCheckpoint-checkpoint'); + await this._baseIndexer.processCheckpoint(this, blockHash, checkpointInterval); + console.timeEnd('time:indexer#processCheckpoint-checkpoint'); + } + + async processCLICheckpoint (contractAddress: string, blockHash?: string): Promise { + return this._baseIndexer.processCLICheckpoint(this, contractAddress, blockHash); + } + + async getPrevState (blockHash: string, contractAddress: string, kind?: string): Promise { + return this._db.getPrevState(blockHash, contractAddress, kind); + } + + async getLatestState (contractAddress: string, kind: StateKind | null, blockNumber?: number): Promise { + return this._db.getLatestState(contractAddress, kind, blockNumber); + } + + async getStatesByHash (blockHash: string): Promise { + return this._baseIndexer.getStatesByHash(blockHash); + } + + async getStateByCID (cid: string): Promise { + return this._baseIndexer.getStateByCID(cid); + } + + async getStates (where: FindConditions): Promise { + return this._db.getStates(where); + } + + getStateData (state: State): any { + return this._baseIndexer.getStateData(state); + } + + // Method used to create auto diffs (diff_staged). + async createDiffStaged (contractAddress: string, blockHash: string, data: any): Promise { + console.time('time:indexer#createDiffStaged-auto_diff'); + await this._baseIndexer.createDiffStaged(contractAddress, blockHash, data); + console.timeEnd('time:indexer#createDiffStaged-auto_diff'); + } + + // Method to be used by createStateDiff hook. + async createDiff (contractAddress: string, blockHash: string, data: any): Promise { + const block = await this.getBlockProgress(blockHash); + assert(block); + + await this._baseIndexer.createDiff(contractAddress, block, data); + } + + // Method to be used by createStateCheckpoint hook. + async createStateCheckpoint (contractAddress: string, blockHash: string, data: any): Promise { + const block = await this.getBlockProgress(blockHash); + assert(block); + + return this._baseIndexer.createStateCheckpoint(contractAddress, block, data); + } + + // Method to be used by export-state CLI. + async createCheckpoint (contractAddress: string, blockHash: string): Promise { + const block = await this.getBlockProgress(blockHash); + assert(block); + + return this._baseIndexer.createCheckpoint(this, contractAddress, block); + } + + // Method to be used by fill-state CLI. + async createInit (blockHash: string, blockNumber: number): Promise { + // Create initial state for contracts. + await this._baseIndexer.createInit(this, blockHash, blockNumber); + } + + async saveOrUpdateState (state: State): Promise { + return this._baseIndexer.saveOrUpdateState(state); + } + + async removeStates (blockNumber: number, kind: StateKind): Promise { + await this._baseIndexer.removeStates(blockNumber, kind); + } + + async getSubgraphEntity ( + entity: new () => Entity, + id: string, + block: BlockHeight, + queryInfo: GraphQLResolveInfo + ): Promise { + const data = await this._graphWatcher.getEntity(entity, id, this._relationsMap, block, queryInfo); + + return data; + } + + async getSubgraphEntities ( + entity: new () => Entity, + block: BlockHeight, + where: { [key: string]: any } = {}, + queryOptions: QueryOptions = {}, + queryInfo: GraphQLResolveInfo + ): Promise { + return this._graphWatcher.getEntities(entity, this._relationsMap, block, where, queryOptions, queryInfo); + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + async triggerIndexingOnEvent (event: Event, extraData: ExtraEventData): Promise { + const resultEvent = this.getResultEvent(event); + + console.time('time:indexer#processEvent-mapping_code'); + // Call subgraph handler for event. + await this._graphWatcher.handleEvent(resultEvent, extraData); + console.timeEnd('time:indexer#processEvent-mapping_code'); + + // Call custom hook function for indexing on event. + await handleEvent(this, resultEvent); + } + + async processEvent (event: Event, extraData: ExtraEventData): Promise { + // Trigger indexing of data based on the event. + await this.triggerIndexingOnEvent(event, extraData); + } + + async processBlock (blockProgress: BlockProgress): Promise { + console.time('time:indexer#processBlock-init_state'); + // Call a function to create initial state for contracts. + await this._baseIndexer.createInit(this, blockProgress.blockHash, blockProgress.blockNumber); + console.timeEnd('time:indexer#processBlock-init_state'); + + this._graphWatcher.updateEntityCacheFrothyBlocks(blockProgress); + } + + async processBlockAfterEvents (blockHash: string, blockNumber: number, extraData: ExtraEventData): Promise { + console.time('time:indexer#processBlockAfterEvents-mapping_code'); + // Call subgraph handler for block. + await this._graphWatcher.handleBlock(blockHash, blockNumber, extraData); + console.timeEnd('time:indexer#processBlockAfterEvents-mapping_code'); + + console.time('time:indexer#processBlockAfterEvents-dump_subgraph_state'); + // Persist subgraph state to the DB. + await this.dumpSubgraphState(blockHash); + console.timeEnd('time:indexer#processBlockAfterEvents-dump_subgraph_state'); + } + + parseEventNameAndArgs (kind: string, logObj: any): { eventParsed: boolean, eventDetails: any } { + const { topics, data } = logObj; + + const contract = this._contractMap.get(kind); + assert(contract); + + let logDescription: ethers.utils.LogDescription; + try { + logDescription = contract.parseLog({ data, topics }); + } catch (err) { + // Return if no matching event found + if ((err as Error).message.includes('no matching event')) { + log(`WARNING: Skipping event for contract ${kind} as no matching event found in the ABI`); + return { eventParsed: false, eventDetails: {} }; + } + + throw err; + } + + const { eventName, eventInfo, eventSignature } = this._baseIndexer.parseEvent(logDescription); + + return { + eventParsed: true, + eventDetails: { + eventName, + eventInfo, + eventSignature + } + }; + } + + async getStateSyncStatus (): Promise { + return this._db.getStateSyncStatus(); + } + + async updateStateSyncStatusIndexedBlock (blockNumber: number, force?: boolean): Promise { + if (!this._serverConfig.enableState) { + return; + } + + const dbTx = await this._db.createTransactionRunner(); + let res; + + try { + res = await this._db.updateStateSyncStatusIndexedBlock(dbTx, blockNumber, force); + await dbTx.commitTransaction(); + } catch (error) { + await dbTx.rollbackTransaction(); + throw error; + } finally { + await dbTx.release(); + } + + return res; + } + + async updateStateSyncStatusCheckpointBlock (blockNumber: number, force?: boolean): Promise { + const dbTx = await this._db.createTransactionRunner(); + let res; + + try { + res = await this._db.updateStateSyncStatusCheckpointBlock(dbTx, blockNumber, force); + await dbTx.commitTransaction(); + } catch (error) { + await dbTx.rollbackTransaction(); + throw error; + } finally { + await dbTx.release(); + } + + return res; + } + + async getLatestCanonicalBlock (): Promise { + const syncStatus = await this.getSyncStatus(); + assert(syncStatus); + + if (syncStatus.latestCanonicalBlockHash === constants.HashZero) { + return; + } + + const latestCanonicalBlock = await this.getBlockProgress(syncStatus.latestCanonicalBlockHash); + assert(latestCanonicalBlock); + + return latestCanonicalBlock; + } + + async getLatestStateIndexedBlock (): Promise { + return this._baseIndexer.getLatestStateIndexedBlock(); + } + + async addContracts (): Promise { + // Watching all the contracts in the subgraph. + await this._graphWatcher.addContracts(); + } + + async watchContract (address: string, kind: string, checkpoint: boolean, startingBlock: number, context?: any): Promise { + return this._baseIndexer.watchContract(address, kind, checkpoint, startingBlock, context); + } + + updateStateStatusMap (address: string, stateStatus: StateStatus): void { + this._baseIndexer.updateStateStatusMap(address, stateStatus); + } + + cacheContract (contract: Contract): void { + return this._baseIndexer.cacheContract(contract); + } + + async saveEventEntity (dbEvent: Event): Promise { + return this._baseIndexer.saveEventEntity(dbEvent); + } + + async saveEvents (dbEvents: Event[]): Promise { + return this._baseIndexer.saveEvents(dbEvents); + } + + async getEventsByFilter (blockHash: string, contract?: string, name?: string): Promise> { + return this._baseIndexer.getEventsByFilter(blockHash, contract, name); + } + + isWatchedContract (address : string): Contract | undefined { + return this._baseIndexer.isWatchedContract(address); + } + + getWatchedContracts (): Contract[] { + return this._baseIndexer.getWatchedContracts(); + } + + getContractsByKind (kind: string): Contract[] { + return this._baseIndexer.getContractsByKind(kind); + } + + async getProcessedBlockCountForRange (fromBlockNumber: number, toBlockNumber: number): Promise<{ expected: number, actual: number }> { + return this._baseIndexer.getProcessedBlockCountForRange(fromBlockNumber, toBlockNumber); + } + + async getEventsInRange (fromBlockNumber: number, toBlockNumber: number): Promise> { + return this._baseIndexer.getEventsInRange(fromBlockNumber, toBlockNumber, this._serverConfig.gql.maxEventsBlockRange); + } + + async getSyncStatus (): Promise { + return this._baseIndexer.getSyncStatus(); + } + + async getBlocks (blockFilter: { blockHash?: string, blockNumber?: number }): Promise { + return this._baseIndexer.getBlocks(blockFilter); + } + + async updateSyncStatusIndexedBlock (blockHash: string, blockNumber: number, force = false): Promise { + return this._baseIndexer.updateSyncStatusIndexedBlock(blockHash, blockNumber, force); + } + + async updateSyncStatusChainHead (blockHash: string, blockNumber: number, force = false): Promise { + return this._baseIndexer.updateSyncStatusChainHead(blockHash, blockNumber, force); + } + + async updateSyncStatusCanonicalBlock (blockHash: string, blockNumber: number, force = false): Promise { + const syncStatus = this._baseIndexer.updateSyncStatusCanonicalBlock(blockHash, blockNumber, force); + await this.pruneFrothyEntities(blockNumber); + + return syncStatus; + } + + async updateSyncStatusProcessedBlock (blockHash: string, blockNumber: number, force = false): Promise { + return this._baseIndexer.updateSyncStatusProcessedBlock(blockHash, blockNumber, force); + } + + async updateSyncStatusIndexingError (hasIndexingError: boolean): Promise { + return this._baseIndexer.updateSyncStatusIndexingError(hasIndexingError); + } + + async updateSyncStatus (syncStatus: DeepPartial): Promise { + return this._baseIndexer.updateSyncStatus(syncStatus); + } + + async getEvent (id: string): Promise { + return this._baseIndexer.getEvent(id); + } + + async getBlockProgress (blockHash: string): Promise { + return this._baseIndexer.getBlockProgress(blockHash); + } + + async getBlockProgressEntities (where: FindConditions, options: FindManyOptions): Promise { + return this._baseIndexer.getBlockProgressEntities(where, options); + } + + async getBlocksAtHeight (height: number, isPruned: boolean): Promise { + return this._baseIndexer.getBlocksAtHeight(height, isPruned); + } + + async fetchAndSaveFilteredEventsAndBlocks (startBlock: number, endBlock: number): Promise<{ + blockProgress: BlockProgress, + events: DeepPartial[], + ethFullBlock: EthFullBlock; + ethFullTransactions: EthFullTransaction[]; + }[]> { + return this._baseIndexer.fetchAndSaveFilteredEventsAndBlocks(startBlock, endBlock, this.eventSignaturesMap, this.parseEventNameAndArgs.bind(this)); + } + + async fetchEventsForContracts (blockHash: string, blockNumber: number, addresses: string[]): Promise[]> { + return this._baseIndexer.fetchEventsForContracts(blockHash, blockNumber, addresses, this.eventSignaturesMap, this.parseEventNameAndArgs.bind(this)); + } + + async saveBlockAndFetchEvents (block: DeepPartial): Promise<[ + BlockProgress, + DeepPartial[], + EthFullTransaction[] + ]> { + return this._saveBlockAndFetchEvents(block); + } + + async getBlockEvents (blockHash: string, where: Where, queryOptions: QueryOptions): Promise> { + return this._baseIndexer.getBlockEvents(blockHash, where, queryOptions); + } + + async removeUnknownEvents (block: BlockProgress): Promise { + return this._baseIndexer.removeUnknownEvents(Event, block); + } + + async markBlocksAsPruned (blocks: BlockProgress[]): Promise { + await this._baseIndexer.markBlocksAsPruned(blocks); + + await this._graphWatcher.pruneEntities(FrothyEntity, blocks, SUBGRAPH_ENTITIES); + } + + async pruneFrothyEntities (blockNumber: number): Promise { + await this._graphWatcher.pruneFrothyEntities(FrothyEntity, blockNumber); + } + + async resetLatestEntities (blockNumber: number): Promise { + await this._graphWatcher.resetLatestEntities(blockNumber); + } + + async updateBlockProgress (block: BlockProgress, lastProcessedEventIndex: number): Promise { + return this._baseIndexer.updateBlockProgress(block, lastProcessedEventIndex); + } + + async getAncestorAtHeight (blockHash: string, height: number): Promise { + return this._baseIndexer.getAncestorAtHeight(blockHash, height); + } + + async resetWatcherToBlock (blockNumber: number): Promise { + const entities = [...ENTITIES, FrothyEntity]; + await this._baseIndexer.resetWatcherToBlock(blockNumber, entities); + + await this.resetLatestEntities(blockNumber); + } + + async clearProcessedBlockData (block: BlockProgress): Promise { + const entities = [...ENTITIES, FrothyEntity]; + await this._baseIndexer.clearProcessedBlockData(block, entities); + + await this.resetLatestEntities(block.blockNumber); + } + + getEntityTypesMap (): Map { + return this._entityTypesMap; + } + + getRelationsMap (): Map { + return this._relationsMap; + } + + updateSubgraphState (contractAddress: string, data: any): void { + return updateSubgraphState(this._subgraphStateMap, contractAddress, data); + } + + async dumpSubgraphState (blockHash: string, isStateFinalized = false): Promise { + return dumpSubgraphState(this, this._subgraphStateMap, blockHash, isStateFinalized); + } + + _populateEntityTypesMap (): void { + this._entityTypesMap.set('Factory', { + id: 'ID', + type: 'PairType', + volumeUSD: 'BigDecimal', + volumeNative: 'BigDecimal', + liquidityUSD: 'BigDecimal', + liquidityNative: 'BigDecimal', + feesUSD: 'BigDecimal', + feesNative: 'BigDecimal', + pairCount: 'BigInt', + transactionCount: 'BigInt', + tokenCount: 'BigInt', + userCount: 'BigInt' + }); + this._entityTypesMap.set('Bundle', { + id: 'ID', + nativePrice: 'BigDecimal' + }); + this._entityTypesMap.set('Token', { + id: 'ID', + price: 'TokenPrice', + symbol: 'String', + symbolSuccess: 'Boolean', + name: 'String', + nameSuccess: 'Boolean', + decimals: 'BigInt', + decimalsSuccess: 'Boolean', + liquidity: 'BigInt', + liquidityNative: 'BigDecimal', + liquidityUSD: 'BigDecimal', + volume: 'BigDecimal', + volumeNative: 'BigDecimal', + volumeUSD: 'BigDecimal', + feesNative: 'BigDecimal', + feesUSD: 'BigDecimal', + txCount: 'BigInt', + pairCount: 'BigInt', + whitelistedPairCount: 'BigInt' + }); + this._entityTypesMap.set('TokenPrice', { + id: 'ID', + token: 'Token', + derivedNative: 'BigDecimal', + lastUsdPrice: 'BigDecimal', + pricedOffToken: 'Token', + pricedOffPair: 'Pair' + }); + this._entityTypesMap.set('_TokenPair', { + id: 'ID', + pair: 'Pair', + token: 'Token' + }); + this._entityTypesMap.set('_WhitelistedTokenPair', { + id: 'ID', + pair: 'Pair', + token: 'Token' + }); + this._entityTypesMap.set('Pair', { + id: 'ID', + type: 'PairType', + swapFee: 'BigInt', + twapEnabled: 'Boolean', + name: 'String', + token0: 'Token', + token1: 'Token', + source: 'String', + createdAtBlock: 'BigInt', + createdAtTimestamp: 'BigInt', + reserve0: 'BigInt', + reserve1: 'BigInt', + liquidity: 'BigInt', + liquidityUSD: 'BigDecimal', + liquidityNative: 'BigDecimal', + trackedLiquidityNative: 'BigDecimal', + token0Price: 'BigDecimal', + token1Price: 'BigDecimal', + volumeNative: 'BigDecimal', + volumeUSD: 'BigDecimal', + volumeToken0: 'BigDecimal', + volumeToken1: 'BigDecimal', + feesNative: 'BigDecimal', + feesUSD: 'BigDecimal', + apr: 'BigDecimal', + aprUpdatedAtTimestamp: 'BigInt', + txCount: 'BigInt' + }); + this._entityTypesMap.set('User', { + id: 'ID', + lpSnapshotsCount: 'BigInt' + }); + this._entityTypesMap.set('LiquidityPosition', { + id: 'ID', + pair: 'Pair', + user: 'User', + balance: 'BigInt', + createdAtBlock: 'BigInt', + createdAtTimestamp: 'BigInt' + }); + this._entityTypesMap.set('Mint', { + id: 'ID', + transaction: 'Transaction', + timestamp: 'BigInt', + pair: 'Pair', + to: 'String', + liquidity: 'BigDecimal', + sender: 'Bytes', + amount0: 'BigDecimal', + amount1: 'BigDecimal', + logIndex: 'BigInt', + amountUSD: 'BigDecimal', + feeTo: 'Bytes', + feeLiquidity: 'BigDecimal' + }); + this._entityTypesMap.set('Burn', { + id: 'ID', + transaction: 'Transaction', + timestamp: 'BigInt', + pair: 'Pair', + liquidity: 'BigDecimal', + sender: 'String', + amount0: 'BigDecimal', + amount1: 'BigDecimal', + to: 'String', + logIndex: 'BigInt', + amountUSD: 'BigDecimal', + complete: 'Boolean', + feeTo: 'String', + feeLiquidity: 'BigDecimal' + }); + this._entityTypesMap.set('Swap', { + id: 'ID', + transaction: 'Transaction', + timestamp: 'BigInt', + pair: 'Pair', + sender: 'String', + tokenIn: 'Token', + tokenOut: 'Token', + amountIn: 'BigDecimal', + amountOut: 'BigDecimal', + to: 'String', + logIndex: 'BigInt', + amountUSD: 'BigDecimal' + }); + this._entityTypesMap.set('Transaction', { + id: 'ID', + gasLimit: 'BigInt', + gasPrice: 'BigInt', + mints: 'Mint', + burns: 'Burn', + swaps: 'Swap', + createdAtBlock: 'BigInt', + createdAtTimestamp: 'BigInt' + }); + this._entityTypesMap.set('LiquidityPositionSnapshot', { + id: 'ID', + liquidityPosition: 'LiquidityPosition', + timestamp: 'Int', + block: 'Int', + user: 'User', + pair: 'Pair', + token0PriceUSD: 'BigDecimal', + token1PriceUSD: 'BigDecimal', + reserve0: 'BigInt', + reserve1: 'BigInt', + reserveUSD: 'BigDecimal', + liquidityTokenTotalSupply: 'BigInt', + liquidityTokenBalance: 'BigInt' + }); + this._entityTypesMap.set('PairHourSnapshot', { + id: 'ID', + pair: 'Pair', + date: 'Int', + cumulativeVolumeUSD: 'BigDecimal', + volumeUSD: 'BigDecimal', + volumeNative: 'BigDecimal', + volumeToken0: 'BigDecimal', + volumeToken1: 'BigDecimal', + liquidity: 'BigDecimal', + liquidityNative: 'BigDecimal', + liquidityUSD: 'BigDecimal', + feesNative: 'BigDecimal', + feesUSD: 'BigDecimal', + apr: 'BigDecimal', + transactionCount: 'BigInt' + }); + this._entityTypesMap.set('PairDaySnapshot', { + id: 'ID', + pair: 'Pair', + date: 'Int', + cumulativeVolumeUSD: 'BigDecimal', + volumeUSD: 'BigDecimal', + volumeNative: 'BigDecimal', + volumeToken0: 'BigDecimal', + volumeToken1: 'BigDecimal', + liquidity: 'BigDecimal', + liquidityNative: 'BigDecimal', + liquidityUSD: 'BigDecimal', + feesNative: 'BigDecimal', + feesUSD: 'BigDecimal', + apr: 'BigDecimal', + transactionCount: 'BigInt' + }); + this._entityTypesMap.set('TokenHourSnapshot', { + id: 'ID', + date: 'Int', + token: 'Token', + liquidity: 'BigDecimal', + liquidityNative: 'BigDecimal', + liquidityUSD: 'BigDecimal', + volume: 'BigDecimal', + volumeNative: 'BigDecimal', + volumeUSD: 'BigDecimal', + priceNative: 'BigDecimal', + priceUSD: 'BigDecimal', + feesNative: 'BigDecimal', + feesUSD: 'BigDecimal', + transactionCount: 'BigInt' + }); + this._entityTypesMap.set('TokenDaySnapshot', { + id: 'ID', + date: 'Int', + token: 'Token', + liquidity: 'BigDecimal', + liquidityNative: 'BigDecimal', + liquidityUSD: 'BigDecimal', + volume: 'BigDecimal', + volumeNative: 'BigDecimal', + volumeUSD: 'BigDecimal', + priceNative: 'BigDecimal', + priceUSD: 'BigDecimal', + feesNative: 'BigDecimal', + feesUSD: 'BigDecimal', + transactionCount: 'BigInt' + }); + this._entityTypesMap.set('FactoryHourSnapshot', { + id: 'ID', + factory: 'Factory', + date: 'Int', + volumeUSD: 'BigDecimal', + volumeNative: 'BigDecimal', + liquidityNative: 'BigDecimal', + liquidityUSD: 'BigDecimal', + feesNative: 'BigDecimal', + feesUSD: 'BigDecimal', + transactionCount: 'BigInt' + }); + this._entityTypesMap.set('FactoryDaySnapshot', { + id: 'ID', + factory: 'Factory', + date: 'Int', + volumeUSD: 'BigDecimal', + volumeNative: 'BigDecimal', + liquidityNative: 'BigDecimal', + liquidityUSD: 'BigDecimal', + feesNative: 'BigDecimal', + feesUSD: 'BigDecimal', + transactionCount: 'BigInt' + }); + } + + _populateRelationsMap (): void { + this._relationsMap.set(Token, { + price: { + entity: TokenPrice, + isArray: false, + isDerived: false + }, + pairs: { + entity: _TokenPair, + isArray: true, + isDerived: true, + field: 'token' + }, + whitelistedPairs: { + entity: _WhitelistedTokenPair, + isArray: true, + isDerived: true, + field: 'token' + } + }); + this._relationsMap.set(TokenPrice, { + token: { + entity: Token, + isArray: false, + isDerived: false + }, + pricedOffToken: { + entity: Token, + isArray: false, + isDerived: false + }, + pricedOffPair: { + entity: Pair, + isArray: false, + isDerived: false + } + }); + this._relationsMap.set(_TokenPair, { + pair: { + entity: Pair, + isArray: false, + isDerived: false + }, + token: { + entity: Token, + isArray: false, + isDerived: false + } + }); + this._relationsMap.set(_WhitelistedTokenPair, { + pair: { + entity: Pair, + isArray: false, + isDerived: false + }, + token: { + entity: Token, + isArray: false, + isDerived: false + } + }); + this._relationsMap.set(Pair, { + token0: { + entity: Token, + isArray: false, + isDerived: false + }, + token1: { + entity: Token, + isArray: false, + isDerived: false + }, + liquidityPositions: { + entity: LiquidityPosition, + isArray: true, + isDerived: true, + field: 'pair' + }, + liquidityPositionSnapshots: { + entity: LiquidityPositionSnapshot, + isArray: true, + isDerived: true, + field: 'pair' + }, + hourSnapshots: { + entity: PairHourSnapshot, + isArray: true, + isDerived: true, + field: 'pair' + }, + daySnapshots: { + entity: PairDaySnapshot, + isArray: true, + isDerived: true, + field: 'pair' + } + }); + this._relationsMap.set(User, { + liquidityPositions: { + entity: LiquidityPosition, + isArray: true, + isDerived: true, + field: 'user' + } + }); + this._relationsMap.set(LiquidityPosition, { + pair: { + entity: Pair, + isArray: false, + isDerived: false + }, + user: { + entity: User, + isArray: false, + isDerived: false + } + }); + this._relationsMap.set(Mint, { + transaction: { + entity: Transaction, + isArray: false, + isDerived: false + }, + pair: { + entity: Pair, + isArray: false, + isDerived: false + } + }); + this._relationsMap.set(Burn, { + transaction: { + entity: Transaction, + isArray: false, + isDerived: false + }, + pair: { + entity: Pair, + isArray: false, + isDerived: false + } + }); + this._relationsMap.set(Swap, { + transaction: { + entity: Transaction, + isArray: false, + isDerived: false + }, + pair: { + entity: Pair, + isArray: false, + isDerived: false + }, + tokenIn: { + entity: Token, + isArray: false, + isDerived: false + }, + tokenOut: { + entity: Token, + isArray: false, + isDerived: false + } + }); + this._relationsMap.set(Transaction, { + mints: { + entity: Mint, + isArray: true, + isDerived: false + }, + burns: { + entity: Burn, + isArray: true, + isDerived: false + }, + swaps: { + entity: Swap, + isArray: true, + isDerived: false + } + }); + this._relationsMap.set(LiquidityPositionSnapshot, { + liquidityPosition: { + entity: LiquidityPosition, + isArray: false, + isDerived: false + }, + user: { + entity: User, + isArray: false, + isDerived: false + }, + pair: { + entity: Pair, + isArray: false, + isDerived: false + } + }); + this._relationsMap.set(PairHourSnapshot, { + pair: { + entity: Pair, + isArray: false, + isDerived: false + } + }); + this._relationsMap.set(PairDaySnapshot, { + pair: { + entity: Pair, + isArray: false, + isDerived: false + } + }); + this._relationsMap.set(TokenHourSnapshot, { + token: { + entity: Token, + isArray: false, + isDerived: false + } + }); + this._relationsMap.set(TokenDaySnapshot, { + token: { + entity: Token, + isArray: false, + isDerived: false + } + }); + this._relationsMap.set(FactoryHourSnapshot, { + factory: { + entity: Factory, + isArray: false, + isDerived: false + } + }); + this._relationsMap.set(FactoryDaySnapshot, { + factory: { + entity: Factory, + isArray: false, + isDerived: false + } + }); + } + + async _saveBlockAndFetchEvents ({ + cid: blockCid, + blockHash, + blockNumber, + blockTimestamp, + parentHash + }: DeepPartial): Promise<[ + BlockProgress, + DeepPartial[], + EthFullTransaction[] + ]> { + assert(blockHash); + assert(blockNumber); + + const { events: dbEvents, transactions } = await this._baseIndexer.fetchEvents(blockHash, blockNumber, this.eventSignaturesMap, this.parseEventNameAndArgs.bind(this)); + + const dbTx = await this._db.createTransactionRunner(); + try { + const block = { + cid: blockCid, + blockHash, + blockNumber, + blockTimestamp, + parentHash + }; + + console.time(`time:indexer#_saveBlockAndFetchEvents-db-save-${blockNumber}`); + const blockProgress = await this._db.saveBlockWithEvents(dbTx, block, dbEvents); + await dbTx.commitTransaction(); + console.timeEnd(`time:indexer#_saveBlockAndFetchEvents-db-save-${blockNumber}`); + + return [blockProgress, [], transactions]; + } catch (error) { + await dbTx.rollbackTransaction(); + throw error; + } finally { + await dbTx.release(); + } + } + + async getFullTransactions (txHashList: string[]): Promise { + return this._baseIndexer.getFullTransactions(txHashList); + } +} diff --git a/packages/sushiswap-watcher/src/job-runner.ts b/packages/sushiswap-watcher/src/job-runner.ts new file mode 100644 index 0000000..93d6820 --- /dev/null +++ b/packages/sushiswap-watcher/src/job-runner.ts @@ -0,0 +1,48 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import debug from 'debug'; + +import { JobRunnerCmd } from '@cerc-io/cli'; +import { JobRunner } from '@cerc-io/util'; +import { getGraphDbAndWatcher } from '@cerc-io/graph-node'; + +import { Indexer } from './indexer'; +import { Database, ENTITY_QUERY_TYPE_MAP, ENTITY_TO_LATEST_ENTITY_MAP } from './database'; + +const log = debug('vulcanize:job-runner'); + +export const main = async (): Promise => { + const jobRunnerCmd = new JobRunnerCmd(); + await jobRunnerCmd.init(Database); + + const { graphWatcher } = await getGraphDbAndWatcher( + jobRunnerCmd.config.server, + jobRunnerCmd.clients.ethClient, + jobRunnerCmd.ethProvider, + jobRunnerCmd.database.baseDatabase, + ENTITY_QUERY_TYPE_MAP, + ENTITY_TO_LATEST_ENTITY_MAP + ); + + await jobRunnerCmd.initIndexer(Indexer, graphWatcher); + + await jobRunnerCmd.exec(async (jobRunner: JobRunner): Promise => { + await jobRunner.subscribeBlockProcessingQueue(); + await jobRunner.subscribeHistoricalProcessingQueue(); + await jobRunner.subscribeEventProcessingQueue(); + await jobRunner.subscribeBlockCheckpointQueue(); + await jobRunner.subscribeHooksQueue(); + }); +}; + +main().then(() => { + log('Starting job runner...'); +}).catch(err => { + log(err); +}); + +process.on('uncaughtException', err => { + log('uncaughtException', err); +}); diff --git a/packages/sushiswap-watcher/src/resolvers.ts b/packages/sushiswap-watcher/src/resolvers.ts new file mode 100644 index 0000000..96e248e --- /dev/null +++ b/packages/sushiswap-watcher/src/resolvers.ts @@ -0,0 +1,1179 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import assert from 'assert'; +import debug from 'debug'; +import { GraphQLResolveInfo } from 'graphql'; +import { ExpressContext } from 'apollo-server-express'; +import winston from 'winston'; + +import { + gqlTotalQueryCount, + gqlQueryCount, + gqlQueryDuration, + getResultState, + IndexerInterface, + GraphQLBigInt, + GraphQLBigDecimal, + BlockHeight, + OrderDirection, + jsonBigIntStringReplacer, + EventWatcher, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + setGQLCacheHints +} from '@cerc-io/util'; + +import { Indexer } from './indexer'; + +import { Factory } from './entity/Factory'; +import { Bundle } from './entity/Bundle'; +import { Token } from './entity/Token'; +import { TokenPrice } from './entity/TokenPrice'; +import { _TokenPair } from './entity/_TokenPair'; +import { _WhitelistedTokenPair } from './entity/_WhitelistedTokenPair'; +import { Pair } from './entity/Pair'; +import { User } from './entity/User'; +import { LiquidityPosition } from './entity/LiquidityPosition'; +import { Mint } from './entity/Mint'; +import { Burn } from './entity/Burn'; +import { Swap } from './entity/Swap'; +import { Transaction } from './entity/Transaction'; +import { LiquidityPositionSnapshot } from './entity/LiquidityPositionSnapshot'; +import { PairHourSnapshot } from './entity/PairHourSnapshot'; +import { PairDaySnapshot } from './entity/PairDaySnapshot'; +import { TokenHourSnapshot } from './entity/TokenHourSnapshot'; +import { TokenDaySnapshot } from './entity/TokenDaySnapshot'; +import { FactoryHourSnapshot } from './entity/FactoryHourSnapshot'; +import { FactoryDaySnapshot } from './entity/FactoryDaySnapshot'; + +const log = debug('vulcanize:resolver'); + +const executeAndRecordMetrics = async ( + indexer: Indexer, + gqlLogger: winston.Logger, + opName: string, + expressContext: ExpressContext, + operation: () => Promise +) => { + gqlTotalQueryCount.inc(1); + gqlQueryCount.labels(opName).inc(1); + const endTimer = gqlQueryDuration.labels(opName).startTimer(); + + try { + const [result, syncStatus] = await Promise.all([ + operation(), + indexer.getSyncStatus() + ]); + + gqlLogger.info({ + opName, + query: expressContext.req.body.query, + variables: expressContext.req.body.variables, + latestIndexedBlockNumber: syncStatus?.latestIndexedBlockNumber, + urlPath: expressContext.req.path, + apiKey: expressContext.req.header('x-api-key'), + origin: expressContext.req.headers.origin + }); + return result; + } catch (error) { + gqlLogger.error({ + opName, + error, + query: expressContext.req.body.query, + variables: expressContext.req.body.variables, + urlPath: expressContext.req.path, + apiKey: expressContext.req.header('x-api-key'), + origin: expressContext.req.headers.origin + }); + } finally { + endTimer(); + } +}; + +export const createResolvers = async ( + indexerArg: IndexerInterface, + eventWatcher: EventWatcher, + gqlLogger: winston.Logger +): Promise => { + const indexer = indexerArg as Indexer; + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const gqlCacheConfig = indexer.serverConfig.gql.cache; + + return { + BigInt: GraphQLBigInt, + + BigDecimal: GraphQLBigDecimal, + + Event: { + __resolveType: (obj: any) => { + assert(obj.__typename); + + return obj.__typename; + } + }, + + Subscription: { + onEvent: { + subscribe: () => eventWatcher.getEventIterator() + } + }, + + Mutation: { + watchContract: async (_: any, { address, kind, checkpoint, startingBlock = 1 }: { address: string, kind: string, checkpoint: boolean, startingBlock: number }): Promise => { + log('watchContract', address, kind, checkpoint, startingBlock); + await indexer.watchContract(address, kind, checkpoint, startingBlock); + + return true; + } + }, + + Query: { + factory: async ( + _: any, + { id, block = {} }: { id: string, block: BlockHeight }, + expressContext: ExpressContext, + info: GraphQLResolveInfo + ) => { + log('factory', id, JSON.stringify(block, jsonBigIntStringReplacer)); + + // Set cache-control hints + // setGQLCacheHints(info, block, gqlCacheConfig); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'factory', + expressContext, + async () => indexer.getSubgraphEntity(Factory, id, block, info) + ); + }, + + factories: async ( + _: any, + { block = {}, where, first, skip, orderBy, orderDirection }: { block: BlockHeight, where: { [key: string]: any }, first: number, skip: number, orderBy: string, orderDirection: OrderDirection }, + expressContext: ExpressContext, + info: GraphQLResolveInfo + ) => { + log('factories', JSON.stringify(block, jsonBigIntStringReplacer), JSON.stringify(where, jsonBigIntStringReplacer), first, skip, orderBy, orderDirection); + + // Set cache-control hints + // setGQLCacheHints(info, block, gqlCacheConfig); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'factories', + expressContext, + async () => indexer.getSubgraphEntities( + Factory, + block, + where, + { limit: first, skip, orderBy, orderDirection }, + info + ) + ); + }, + + bundle: async ( + _: any, + { id, block = {} }: { id: string, block: BlockHeight }, + expressContext: ExpressContext, + info: GraphQLResolveInfo + ) => { + log('bundle', id, JSON.stringify(block, jsonBigIntStringReplacer)); + + // Set cache-control hints + // setGQLCacheHints(info, block, gqlCacheConfig); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'bundle', + expressContext, + async () => indexer.getSubgraphEntity(Bundle, id, block, info) + ); + }, + + bundles: async ( + _: any, + { block = {}, where, first, skip, orderBy, orderDirection }: { block: BlockHeight, where: { [key: string]: any }, first: number, skip: number, orderBy: string, orderDirection: OrderDirection }, + expressContext: ExpressContext, + info: GraphQLResolveInfo + ) => { + log('bundles', JSON.stringify(block, jsonBigIntStringReplacer), JSON.stringify(where, jsonBigIntStringReplacer), first, skip, orderBy, orderDirection); + + // Set cache-control hints + // setGQLCacheHints(info, block, gqlCacheConfig); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'bundles', + expressContext, + async () => indexer.getSubgraphEntities( + Bundle, + block, + where, + { limit: first, skip, orderBy, orderDirection }, + info + ) + ); + }, + + token: async ( + _: any, + { id, block = {} }: { id: string, block: BlockHeight }, + expressContext: ExpressContext, + info: GraphQLResolveInfo + ) => { + log('token', id, JSON.stringify(block, jsonBigIntStringReplacer)); + + // Set cache-control hints + // setGQLCacheHints(info, block, gqlCacheConfig); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'token', + expressContext, + async () => indexer.getSubgraphEntity(Token, id, block, info) + ); + }, + + tokens: async ( + _: any, + { block = {}, where, first, skip, orderBy, orderDirection }: { block: BlockHeight, where: { [key: string]: any }, first: number, skip: number, orderBy: string, orderDirection: OrderDirection }, + expressContext: ExpressContext, + info: GraphQLResolveInfo + ) => { + log('tokens', JSON.stringify(block, jsonBigIntStringReplacer), JSON.stringify(where, jsonBigIntStringReplacer), first, skip, orderBy, orderDirection); + + // Set cache-control hints + // setGQLCacheHints(info, block, gqlCacheConfig); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'tokens', + expressContext, + async () => indexer.getSubgraphEntities( + Token, + block, + where, + { limit: first, skip, orderBy, orderDirection }, + info + ) + ); + }, + + tokenPrice: async ( + _: any, + { id, block = {} }: { id: string, block: BlockHeight }, + expressContext: ExpressContext, + info: GraphQLResolveInfo + ) => { + log('tokenPrice', id, JSON.stringify(block, jsonBigIntStringReplacer)); + + // Set cache-control hints + // setGQLCacheHints(info, block, gqlCacheConfig); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'tokenPrice', + expressContext, + async () => indexer.getSubgraphEntity(TokenPrice, id, block, info) + ); + }, + + tokenPrices: async ( + _: any, + { block = {}, where, first, skip, orderBy, orderDirection }: { block: BlockHeight, where: { [key: string]: any }, first: number, skip: number, orderBy: string, orderDirection: OrderDirection }, + expressContext: ExpressContext, + info: GraphQLResolveInfo + ) => { + log('tokenPrices', JSON.stringify(block, jsonBigIntStringReplacer), JSON.stringify(where, jsonBigIntStringReplacer), first, skip, orderBy, orderDirection); + + // Set cache-control hints + // setGQLCacheHints(info, block, gqlCacheConfig); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'tokenPrices', + expressContext, + async () => indexer.getSubgraphEntities( + TokenPrice, + block, + where, + { limit: first, skip, orderBy, orderDirection }, + info + ) + ); + }, + + _TokenPair: async ( + _: any, + { id, block = {} }: { id: string, block: BlockHeight }, + expressContext: ExpressContext, + info: GraphQLResolveInfo + ) => { + log('_TokenPair', id, JSON.stringify(block, jsonBigIntStringReplacer)); + + // Set cache-control hints + // setGQLCacheHints(info, block, gqlCacheConfig); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + '_TokenPair', + expressContext, + async () => indexer.getSubgraphEntity(_TokenPair, id, block, info) + ); + }, + + _TokenPairs: async ( + _: any, + { block = {}, where, first, skip, orderBy, orderDirection }: { block: BlockHeight, where: { [key: string]: any }, first: number, skip: number, orderBy: string, orderDirection: OrderDirection }, + expressContext: ExpressContext, + info: GraphQLResolveInfo + ) => { + log('_TokenPairs', JSON.stringify(block, jsonBigIntStringReplacer), JSON.stringify(where, jsonBigIntStringReplacer), first, skip, orderBy, orderDirection); + + // Set cache-control hints + // setGQLCacheHints(info, block, gqlCacheConfig); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + '_TokenPairs', + expressContext, + async () => indexer.getSubgraphEntities( + _TokenPair, + block, + where, + { limit: first, skip, orderBy, orderDirection }, + info + ) + ); + }, + + _WhitelistedTokenPair: async ( + _: any, + { id, block = {} }: { id: string, block: BlockHeight }, + expressContext: ExpressContext, + info: GraphQLResolveInfo + ) => { + log('_WhitelistedTokenPair', id, JSON.stringify(block, jsonBigIntStringReplacer)); + + // Set cache-control hints + // setGQLCacheHints(info, block, gqlCacheConfig); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + '_WhitelistedTokenPair', + expressContext, + async () => indexer.getSubgraphEntity(_WhitelistedTokenPair, id, block, info) + ); + }, + + _WhitelistedTokenPairs: async ( + _: any, + { block = {}, where, first, skip, orderBy, orderDirection }: { block: BlockHeight, where: { [key: string]: any }, first: number, skip: number, orderBy: string, orderDirection: OrderDirection }, + expressContext: ExpressContext, + info: GraphQLResolveInfo + ) => { + log('_WhitelistedTokenPairs', JSON.stringify(block, jsonBigIntStringReplacer), JSON.stringify(where, jsonBigIntStringReplacer), first, skip, orderBy, orderDirection); + + // Set cache-control hints + // setGQLCacheHints(info, block, gqlCacheConfig); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + '_WhitelistedTokenPairs', + expressContext, + async () => indexer.getSubgraphEntities( + _WhitelistedTokenPair, + block, + where, + { limit: first, skip, orderBy, orderDirection }, + info + ) + ); + }, + + pair: async ( + _: any, + { id, block = {} }: { id: string, block: BlockHeight }, + expressContext: ExpressContext, + info: GraphQLResolveInfo + ) => { + log('pair', id, JSON.stringify(block, jsonBigIntStringReplacer)); + + // Set cache-control hints + // setGQLCacheHints(info, block, gqlCacheConfig); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'pair', + expressContext, + async () => indexer.getSubgraphEntity(Pair, id, block, info) + ); + }, + + pairs: async ( + _: any, + { block = {}, where, first, skip, orderBy, orderDirection }: { block: BlockHeight, where: { [key: string]: any }, first: number, skip: number, orderBy: string, orderDirection: OrderDirection }, + expressContext: ExpressContext, + info: GraphQLResolveInfo + ) => { + log('pairs', JSON.stringify(block, jsonBigIntStringReplacer), JSON.stringify(where, jsonBigIntStringReplacer), first, skip, orderBy, orderDirection); + + // Set cache-control hints + // setGQLCacheHints(info, block, gqlCacheConfig); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'pairs', + expressContext, + async () => indexer.getSubgraphEntities( + Pair, + block, + where, + { limit: first, skip, orderBy, orderDirection }, + info + ) + ); + }, + + user: async ( + _: any, + { id, block = {} }: { id: string, block: BlockHeight }, + expressContext: ExpressContext, + info: GraphQLResolveInfo + ) => { + log('user', id, JSON.stringify(block, jsonBigIntStringReplacer)); + + // Set cache-control hints + // setGQLCacheHints(info, block, gqlCacheConfig); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'user', + expressContext, + async () => indexer.getSubgraphEntity(User, id, block, info) + ); + }, + + users: async ( + _: any, + { block = {}, where, first, skip, orderBy, orderDirection }: { block: BlockHeight, where: { [key: string]: any }, first: number, skip: number, orderBy: string, orderDirection: OrderDirection }, + expressContext: ExpressContext, + info: GraphQLResolveInfo + ) => { + log('users', JSON.stringify(block, jsonBigIntStringReplacer), JSON.stringify(where, jsonBigIntStringReplacer), first, skip, orderBy, orderDirection); + + // Set cache-control hints + // setGQLCacheHints(info, block, gqlCacheConfig); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'users', + expressContext, + async () => indexer.getSubgraphEntities( + User, + block, + where, + { limit: first, skip, orderBy, orderDirection }, + info + ) + ); + }, + + liquidityPosition: async ( + _: any, + { id, block = {} }: { id: string, block: BlockHeight }, + expressContext: ExpressContext, + info: GraphQLResolveInfo + ) => { + log('liquidityPosition', id, JSON.stringify(block, jsonBigIntStringReplacer)); + + // Set cache-control hints + // setGQLCacheHints(info, block, gqlCacheConfig); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'liquidityPosition', + expressContext, + async () => indexer.getSubgraphEntity(LiquidityPosition, id, block, info) + ); + }, + + liquidityPositions: async ( + _: any, + { block = {}, where, first, skip, orderBy, orderDirection }: { block: BlockHeight, where: { [key: string]: any }, first: number, skip: number, orderBy: string, orderDirection: OrderDirection }, + expressContext: ExpressContext, + info: GraphQLResolveInfo + ) => { + log('liquidityPositions', JSON.stringify(block, jsonBigIntStringReplacer), JSON.stringify(where, jsonBigIntStringReplacer), first, skip, orderBy, orderDirection); + + // Set cache-control hints + // setGQLCacheHints(info, block, gqlCacheConfig); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'liquidityPositions', + expressContext, + async () => indexer.getSubgraphEntities( + LiquidityPosition, + block, + where, + { limit: first, skip, orderBy, orderDirection }, + info + ) + ); + }, + + mint: async ( + _: any, + { id, block = {} }: { id: string, block: BlockHeight }, + expressContext: ExpressContext, + info: GraphQLResolveInfo + ) => { + log('mint', id, JSON.stringify(block, jsonBigIntStringReplacer)); + + // Set cache-control hints + // setGQLCacheHints(info, block, gqlCacheConfig); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'mint', + expressContext, + async () => indexer.getSubgraphEntity(Mint, id, block, info) + ); + }, + + mints: async ( + _: any, + { block = {}, where, first, skip, orderBy, orderDirection }: { block: BlockHeight, where: { [key: string]: any }, first: number, skip: number, orderBy: string, orderDirection: OrderDirection }, + expressContext: ExpressContext, + info: GraphQLResolveInfo + ) => { + log('mints', JSON.stringify(block, jsonBigIntStringReplacer), JSON.stringify(where, jsonBigIntStringReplacer), first, skip, orderBy, orderDirection); + + // Set cache-control hints + // setGQLCacheHints(info, block, gqlCacheConfig); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'mints', + expressContext, + async () => indexer.getSubgraphEntities( + Mint, + block, + where, + { limit: first, skip, orderBy, orderDirection }, + info + ) + ); + }, + + burn: async ( + _: any, + { id, block = {} }: { id: string, block: BlockHeight }, + expressContext: ExpressContext, + info: GraphQLResolveInfo + ) => { + log('burn', id, JSON.stringify(block, jsonBigIntStringReplacer)); + + // Set cache-control hints + // setGQLCacheHints(info, block, gqlCacheConfig); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'burn', + expressContext, + async () => indexer.getSubgraphEntity(Burn, id, block, info) + ); + }, + + burns: async ( + _: any, + { block = {}, where, first, skip, orderBy, orderDirection }: { block: BlockHeight, where: { [key: string]: any }, first: number, skip: number, orderBy: string, orderDirection: OrderDirection }, + expressContext: ExpressContext, + info: GraphQLResolveInfo + ) => { + log('burns', JSON.stringify(block, jsonBigIntStringReplacer), JSON.stringify(where, jsonBigIntStringReplacer), first, skip, orderBy, orderDirection); + + // Set cache-control hints + // setGQLCacheHints(info, block, gqlCacheConfig); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'burns', + expressContext, + async () => indexer.getSubgraphEntities( + Burn, + block, + where, + { limit: first, skip, orderBy, orderDirection }, + info + ) + ); + }, + + swap: async ( + _: any, + { id, block = {} }: { id: string, block: BlockHeight }, + expressContext: ExpressContext, + info: GraphQLResolveInfo + ) => { + log('swap', id, JSON.stringify(block, jsonBigIntStringReplacer)); + + // Set cache-control hints + // setGQLCacheHints(info, block, gqlCacheConfig); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'swap', + expressContext, + async () => indexer.getSubgraphEntity(Swap, id, block, info) + ); + }, + + swaps: async ( + _: any, + { block = {}, where, first, skip, orderBy, orderDirection }: { block: BlockHeight, where: { [key: string]: any }, first: number, skip: number, orderBy: string, orderDirection: OrderDirection }, + expressContext: ExpressContext, + info: GraphQLResolveInfo + ) => { + log('swaps', JSON.stringify(block, jsonBigIntStringReplacer), JSON.stringify(where, jsonBigIntStringReplacer), first, skip, orderBy, orderDirection); + + // Set cache-control hints + // setGQLCacheHints(info, block, gqlCacheConfig); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'swaps', + expressContext, + async () => indexer.getSubgraphEntities( + Swap, + block, + where, + { limit: first, skip, orderBy, orderDirection }, + info + ) + ); + }, + + transaction: async ( + _: any, + { id, block = {} }: { id: string, block: BlockHeight }, + expressContext: ExpressContext, + info: GraphQLResolveInfo + ) => { + log('transaction', id, JSON.stringify(block, jsonBigIntStringReplacer)); + + // Set cache-control hints + // setGQLCacheHints(info, block, gqlCacheConfig); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'transaction', + expressContext, + async () => indexer.getSubgraphEntity(Transaction, id, block, info) + ); + }, + + transactions: async ( + _: any, + { block = {}, where, first, skip, orderBy, orderDirection }: { block: BlockHeight, where: { [key: string]: any }, first: number, skip: number, orderBy: string, orderDirection: OrderDirection }, + expressContext: ExpressContext, + info: GraphQLResolveInfo + ) => { + log('transactions', JSON.stringify(block, jsonBigIntStringReplacer), JSON.stringify(where, jsonBigIntStringReplacer), first, skip, orderBy, orderDirection); + + // Set cache-control hints + // setGQLCacheHints(info, block, gqlCacheConfig); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'transactions', + expressContext, + async () => indexer.getSubgraphEntities( + Transaction, + block, + where, + { limit: first, skip, orderBy, orderDirection }, + info + ) + ); + }, + + liquidityPositionSnapshot: async ( + _: any, + { id, block = {} }: { id: string, block: BlockHeight }, + expressContext: ExpressContext, + info: GraphQLResolveInfo + ) => { + log('liquidityPositionSnapshot', id, JSON.stringify(block, jsonBigIntStringReplacer)); + + // Set cache-control hints + // setGQLCacheHints(info, block, gqlCacheConfig); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'liquidityPositionSnapshot', + expressContext, + async () => indexer.getSubgraphEntity(LiquidityPositionSnapshot, id, block, info) + ); + }, + + liquidityPositionSnapshots: async ( + _: any, + { block = {}, where, first, skip, orderBy, orderDirection }: { block: BlockHeight, where: { [key: string]: any }, first: number, skip: number, orderBy: string, orderDirection: OrderDirection }, + expressContext: ExpressContext, + info: GraphQLResolveInfo + ) => { + log('liquidityPositionSnapshots', JSON.stringify(block, jsonBigIntStringReplacer), JSON.stringify(where, jsonBigIntStringReplacer), first, skip, orderBy, orderDirection); + + // Set cache-control hints + // setGQLCacheHints(info, block, gqlCacheConfig); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'liquidityPositionSnapshots', + expressContext, + async () => indexer.getSubgraphEntities( + LiquidityPositionSnapshot, + block, + where, + { limit: first, skip, orderBy, orderDirection }, + info + ) + ); + }, + + pairHourSnapshot: async ( + _: any, + { id, block = {} }: { id: string, block: BlockHeight }, + expressContext: ExpressContext, + info: GraphQLResolveInfo + ) => { + log('pairHourSnapshot', id, JSON.stringify(block, jsonBigIntStringReplacer)); + + // Set cache-control hints + // setGQLCacheHints(info, block, gqlCacheConfig); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'pairHourSnapshot', + expressContext, + async () => indexer.getSubgraphEntity(PairHourSnapshot, id, block, info) + ); + }, + + pairHourSnapshots: async ( + _: any, + { block = {}, where, first, skip, orderBy, orderDirection }: { block: BlockHeight, where: { [key: string]: any }, first: number, skip: number, orderBy: string, orderDirection: OrderDirection }, + expressContext: ExpressContext, + info: GraphQLResolveInfo + ) => { + log('pairHourSnapshots', JSON.stringify(block, jsonBigIntStringReplacer), JSON.stringify(where, jsonBigIntStringReplacer), first, skip, orderBy, orderDirection); + + // Set cache-control hints + // setGQLCacheHints(info, block, gqlCacheConfig); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'pairHourSnapshots', + expressContext, + async () => indexer.getSubgraphEntities( + PairHourSnapshot, + block, + where, + { limit: first, skip, orderBy, orderDirection }, + info + ) + ); + }, + + pairDaySnapshot: async ( + _: any, + { id, block = {} }: { id: string, block: BlockHeight }, + expressContext: ExpressContext, + info: GraphQLResolveInfo + ) => { + log('pairDaySnapshot', id, JSON.stringify(block, jsonBigIntStringReplacer)); + + // Set cache-control hints + // setGQLCacheHints(info, block, gqlCacheConfig); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'pairDaySnapshot', + expressContext, + async () => indexer.getSubgraphEntity(PairDaySnapshot, id, block, info) + ); + }, + + pairDaySnapshots: async ( + _: any, + { block = {}, where, first, skip, orderBy, orderDirection }: { block: BlockHeight, where: { [key: string]: any }, first: number, skip: number, orderBy: string, orderDirection: OrderDirection }, + expressContext: ExpressContext, + info: GraphQLResolveInfo + ) => { + log('pairDaySnapshots', JSON.stringify(block, jsonBigIntStringReplacer), JSON.stringify(where, jsonBigIntStringReplacer), first, skip, orderBy, orderDirection); + + // Set cache-control hints + // setGQLCacheHints(info, block, gqlCacheConfig); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'pairDaySnapshots', + expressContext, + async () => indexer.getSubgraphEntities( + PairDaySnapshot, + block, + where, + { limit: first, skip, orderBy, orderDirection }, + info + ) + ); + }, + + tokenHourSnapshot: async ( + _: any, + { id, block = {} }: { id: string, block: BlockHeight }, + expressContext: ExpressContext, + info: GraphQLResolveInfo + ) => { + log('tokenHourSnapshot', id, JSON.stringify(block, jsonBigIntStringReplacer)); + + // Set cache-control hints + // setGQLCacheHints(info, block, gqlCacheConfig); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'tokenHourSnapshot', + expressContext, + async () => indexer.getSubgraphEntity(TokenHourSnapshot, id, block, info) + ); + }, + + tokenHourSnapshots: async ( + _: any, + { block = {}, where, first, skip, orderBy, orderDirection }: { block: BlockHeight, where: { [key: string]: any }, first: number, skip: number, orderBy: string, orderDirection: OrderDirection }, + expressContext: ExpressContext, + info: GraphQLResolveInfo + ) => { + log('tokenHourSnapshots', JSON.stringify(block, jsonBigIntStringReplacer), JSON.stringify(where, jsonBigIntStringReplacer), first, skip, orderBy, orderDirection); + + // Set cache-control hints + // setGQLCacheHints(info, block, gqlCacheConfig); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'tokenHourSnapshots', + expressContext, + async () => indexer.getSubgraphEntities( + TokenHourSnapshot, + block, + where, + { limit: first, skip, orderBy, orderDirection }, + info + ) + ); + }, + + tokenDaySnapshot: async ( + _: any, + { id, block = {} }: { id: string, block: BlockHeight }, + expressContext: ExpressContext, + info: GraphQLResolveInfo + ) => { + log('tokenDaySnapshot', id, JSON.stringify(block, jsonBigIntStringReplacer)); + + // Set cache-control hints + // setGQLCacheHints(info, block, gqlCacheConfig); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'tokenDaySnapshot', + expressContext, + async () => indexer.getSubgraphEntity(TokenDaySnapshot, id, block, info) + ); + }, + + tokenDaySnapshots: async ( + _: any, + { block = {}, where, first, skip, orderBy, orderDirection }: { block: BlockHeight, where: { [key: string]: any }, first: number, skip: number, orderBy: string, orderDirection: OrderDirection }, + expressContext: ExpressContext, + info: GraphQLResolveInfo + ) => { + log('tokenDaySnapshots', JSON.stringify(block, jsonBigIntStringReplacer), JSON.stringify(where, jsonBigIntStringReplacer), first, skip, orderBy, orderDirection); + + // Set cache-control hints + // setGQLCacheHints(info, block, gqlCacheConfig); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'tokenDaySnapshots', + expressContext, + async () => indexer.getSubgraphEntities( + TokenDaySnapshot, + block, + where, + { limit: first, skip, orderBy, orderDirection }, + info + ) + ); + }, + + factoryHourSnapshot: async ( + _: any, + { id, block = {} }: { id: string, block: BlockHeight }, + expressContext: ExpressContext, + info: GraphQLResolveInfo + ) => { + log('factoryHourSnapshot', id, JSON.stringify(block, jsonBigIntStringReplacer)); + + // Set cache-control hints + // setGQLCacheHints(info, block, gqlCacheConfig); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'factoryHourSnapshot', + expressContext, + async () => indexer.getSubgraphEntity(FactoryHourSnapshot, id, block, info) + ); + }, + + factoryHourSnapshots: async ( + _: any, + { block = {}, where, first, skip, orderBy, orderDirection }: { block: BlockHeight, where: { [key: string]: any }, first: number, skip: number, orderBy: string, orderDirection: OrderDirection }, + expressContext: ExpressContext, + info: GraphQLResolveInfo + ) => { + log('factoryHourSnapshots', JSON.stringify(block, jsonBigIntStringReplacer), JSON.stringify(where, jsonBigIntStringReplacer), first, skip, orderBy, orderDirection); + + // Set cache-control hints + // setGQLCacheHints(info, block, gqlCacheConfig); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'factoryHourSnapshots', + expressContext, + async () => indexer.getSubgraphEntities( + FactoryHourSnapshot, + block, + where, + { limit: first, skip, orderBy, orderDirection }, + info + ) + ); + }, + + factoryDaySnapshot: async ( + _: any, + { id, block = {} }: { id: string, block: BlockHeight }, + expressContext: ExpressContext, + info: GraphQLResolveInfo + ) => { + log('factoryDaySnapshot', id, JSON.stringify(block, jsonBigIntStringReplacer)); + + // Set cache-control hints + // setGQLCacheHints(info, block, gqlCacheConfig); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'factoryDaySnapshot', + expressContext, + async () => indexer.getSubgraphEntity(FactoryDaySnapshot, id, block, info) + ); + }, + + factoryDaySnapshots: async ( + _: any, + { block = {}, where, first, skip, orderBy, orderDirection }: { block: BlockHeight, where: { [key: string]: any }, first: number, skip: number, orderBy: string, orderDirection: OrderDirection }, + expressContext: ExpressContext, + info: GraphQLResolveInfo + ) => { + log('factoryDaySnapshots', JSON.stringify(block, jsonBigIntStringReplacer), JSON.stringify(where, jsonBigIntStringReplacer), first, skip, orderBy, orderDirection); + + // Set cache-control hints + // setGQLCacheHints(info, block, gqlCacheConfig); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'factoryDaySnapshots', + expressContext, + async () => indexer.getSubgraphEntities( + FactoryDaySnapshot, + block, + where, + { limit: first, skip, orderBy, orderDirection }, + info + ) + ); + }, + + events: async ( + _: any, + { blockHash, contractAddress, name }: { blockHash: string, contractAddress: string, name?: string }, + expressContext: ExpressContext + ) => { + log('events', blockHash, contractAddress, name); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'events', + expressContext, + async () => { + const block = await indexer.getBlockProgress(blockHash); + if (!block || !block.isComplete) { + throw new Error(`Block hash ${blockHash} number ${block?.blockNumber} not processed yet`); + } + + const events = await indexer.getEventsByFilter(blockHash, contractAddress, name); + return events.map(event => indexer.getResultEvent(event)); + } + ); + }, + + eventsInRange: async ( + _: any, + { fromBlockNumber, toBlockNumber }: { fromBlockNumber: number, toBlockNumber: number }, + expressContext: ExpressContext + ) => { + log('eventsInRange', fromBlockNumber, toBlockNumber); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'eventsInRange', + expressContext, + async () => { + const syncStatus = await indexer.getSyncStatus(); + + if (!syncStatus) { + throw new Error('No blocks processed yet'); + } + + if ((fromBlockNumber < syncStatus.initialIndexedBlockNumber) || (toBlockNumber > syncStatus.latestProcessedBlockNumber)) { + throw new Error(`Block range should be between ${syncStatus.initialIndexedBlockNumber} and ${syncStatus.latestProcessedBlockNumber}`); + } + + const events = await indexer.getEventsInRange(fromBlockNumber, toBlockNumber); + return events.map(event => indexer.getResultEvent(event)); + } + ); + }, + + getStateByCID: async ( + _: any, + { cid }: { cid: string }, + expressContext: ExpressContext + ) => { + log('getStateByCID', cid); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'getStateByCID', + expressContext, + async () => { + const state = await indexer.getStateByCID(cid); + + return state && state.block.isComplete ? getResultState(state) : undefined; + } + ); + }, + + getState: async ( + _: any, + { blockHash, contractAddress, kind }: { blockHash: string, contractAddress: string, kind: string }, + expressContext: ExpressContext + ) => { + log('getState', blockHash, contractAddress, kind); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'getState', + expressContext, + async () => { + const state = await indexer.getPrevState(blockHash, contractAddress, kind); + + return state && state.block.isComplete ? getResultState(state) : undefined; + } + ); + }, + + _meta: async ( + _: any, + { block = {} }: { block: BlockHeight }, + expressContext: ExpressContext + ) => { + log('_meta'); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + '_meta', + expressContext, + async () => indexer.getMetaData(block) + ); + }, + + getSyncStatus: async ( + _: any, + __: Record, + expressContext: ExpressContext + ) => { + log('getSyncStatus'); + + return executeAndRecordMetrics( + indexer, + gqlLogger, + 'getSyncStatus', + expressContext, + async () => indexer.getSyncStatus() + ); + } + } + }; +}; diff --git a/packages/sushiswap-watcher/src/schema.gql b/packages/sushiswap-watcher/src/schema.gql new file mode 100644 index 0000000..978e951 --- /dev/null +++ b/packages/sushiswap-watcher/src/schema.gql @@ -0,0 +1,3798 @@ +directive @cacheControl(maxAge: Int, inheritMaxAge: Boolean, scope: CacheControlScope) on FIELD_DEFINITION | OBJECT | INTERFACE | UNION + +enum CacheControlScope { + PUBLIC + PRIVATE +} + +scalar BigInt + +scalar BigDecimal + +scalar Bytes + +type Proof { + data: String! +} + +type _Block_ { + cid: String + hash: String! + number: Int! + timestamp: Int! + parentHash: String! +} + +type _Transaction_ { + hash: String! + index: Int! + from: String! + to: String! +} + +type ResultEvent { + block: _Block_! + tx: _Transaction_! + contract: String! + eventIndex: Int! + event: Event! + proof: Proof +} + +union Event = PairCreatedEvent | ApprovalEvent | BurnEvent | MintEvent | SwapEvent | SyncEvent | TransferEvent + +type PairCreatedEvent { + token0: String! + token1: String! + pair: String! + null: BigInt! +} + +type ApprovalEvent { + owner: String! + spender: String! + value: BigInt! +} + +type BurnEvent { + sender: String! + amount0: BigInt! + amount1: BigInt! + to: String! +} + +type MintEvent { + sender: String! + amount0: BigInt! + amount1: BigInt! +} + +type SwapEvent { + sender: String! + amount0In: BigInt! + amount1In: BigInt! + amount0Out: BigInt! + amount1Out: BigInt! + to: String! +} + +type SyncEvent { + reserve0: BigInt! + reserve1: BigInt! +} + +type TransferEvent { + from: String! + to: String! + value: BigInt! +} + +input Block_height { + hash: Bytes + number: Int +} + +input BlockChangedFilter { + number_gte: Int! +} + +enum OrderDirection { + asc + desc +} + +enum Factory_orderBy { + id + type + volumeUSD + volumeNative + liquidityUSD + liquidityNative + feesUSD + feesNative + pairCount + transactionCount + tokenCount + userCount +} + +input Factory_filter { + id: ID + id_not: ID + id_gt: ID + id_lt: ID + id_gte: ID + id_lte: ID + id_in: [ID!] + id_not_in: [ID!] + type: PairType + type_not: PairType + type_gt: PairType + type_lt: PairType + type_gte: PairType + type_lte: PairType + type_in: [PairType!] + type_not_in: [PairType!] + volumeUSD: BigDecimal + volumeUSD_not: BigDecimal + volumeUSD_gt: BigDecimal + volumeUSD_lt: BigDecimal + volumeUSD_gte: BigDecimal + volumeUSD_lte: BigDecimal + volumeUSD_in: [BigDecimal!] + volumeUSD_not_in: [BigDecimal!] + volumeNative: BigDecimal + volumeNative_not: BigDecimal + volumeNative_gt: BigDecimal + volumeNative_lt: BigDecimal + volumeNative_gte: BigDecimal + volumeNative_lte: BigDecimal + volumeNative_in: [BigDecimal!] + volumeNative_not_in: [BigDecimal!] + liquidityUSD: BigDecimal + liquidityUSD_not: BigDecimal + liquidityUSD_gt: BigDecimal + liquidityUSD_lt: BigDecimal + liquidityUSD_gte: BigDecimal + liquidityUSD_lte: BigDecimal + liquidityUSD_in: [BigDecimal!] + liquidityUSD_not_in: [BigDecimal!] + liquidityNative: BigDecimal + liquidityNative_not: BigDecimal + liquidityNative_gt: BigDecimal + liquidityNative_lt: BigDecimal + liquidityNative_gte: BigDecimal + liquidityNative_lte: BigDecimal + liquidityNative_in: [BigDecimal!] + liquidityNative_not_in: [BigDecimal!] + feesUSD: BigDecimal + feesUSD_not: BigDecimal + feesUSD_gt: BigDecimal + feesUSD_lt: BigDecimal + feesUSD_gte: BigDecimal + feesUSD_lte: BigDecimal + feesUSD_in: [BigDecimal!] + feesUSD_not_in: [BigDecimal!] + feesNative: BigDecimal + feesNative_not: BigDecimal + feesNative_gt: BigDecimal + feesNative_lt: BigDecimal + feesNative_gte: BigDecimal + feesNative_lte: BigDecimal + feesNative_in: [BigDecimal!] + feesNative_not_in: [BigDecimal!] + pairCount: BigInt + pairCount_not: BigInt + pairCount_gt: BigInt + pairCount_lt: BigInt + pairCount_gte: BigInt + pairCount_lte: BigInt + pairCount_in: [BigInt!] + pairCount_not_in: [BigInt!] + transactionCount: BigInt + transactionCount_not: BigInt + transactionCount_gt: BigInt + transactionCount_lt: BigInt + transactionCount_gte: BigInt + transactionCount_lte: BigInt + transactionCount_in: [BigInt!] + transactionCount_not_in: [BigInt!] + tokenCount: BigInt + tokenCount_not: BigInt + tokenCount_gt: BigInt + tokenCount_lt: BigInt + tokenCount_gte: BigInt + tokenCount_lte: BigInt + tokenCount_in: [BigInt!] + tokenCount_not_in: [BigInt!] + userCount: BigInt + userCount_not: BigInt + userCount_gt: BigInt + userCount_lt: BigInt + userCount_gte: BigInt + userCount_lte: BigInt + userCount_in: [BigInt!] + userCount_not_in: [BigInt!] + _change_block: BlockChangedFilter + and: [Factory_filter] + or: [Factory_filter] +} + +enum PairType { + CONSTANT_PRODUCT_POOL +} + +enum Bundle_orderBy { + id + nativePrice +} + +input Bundle_filter { + id: ID + id_not: ID + id_gt: ID + id_lt: ID + id_gte: ID + id_lte: ID + id_in: [ID!] + id_not_in: [ID!] + nativePrice: BigDecimal + nativePrice_not: BigDecimal + nativePrice_gt: BigDecimal + nativePrice_lt: BigDecimal + nativePrice_gte: BigDecimal + nativePrice_lte: BigDecimal + nativePrice_in: [BigDecimal!] + nativePrice_not_in: [BigDecimal!] + _change_block: BlockChangedFilter + and: [Bundle_filter] + or: [Bundle_filter] +} + +enum Token_orderBy { + id + price + price__id + price__derivedNative + price__lastUsdPrice + symbol + symbolSuccess + name + nameSuccess + decimals + decimalsSuccess + liquidity + liquidityNative + liquidityUSD + volume + volumeNative + volumeUSD + feesNative + feesUSD + txCount + pairCount + whitelistedPairCount + pairs + whitelistedPairs +} + +input Token_filter { + id: ID + id_not: ID + id_gt: ID + id_lt: ID + id_gte: ID + id_lte: ID + id_in: [ID!] + id_not_in: [ID!] + price: String + price_not: String + price_gt: String + price_lt: String + price_gte: String + price_lte: String + price_in: [String!] + price_not_in: [String!] + price_starts_with: String + price_starts_with_nocase: String + price_not_starts_with: String + price_not_starts_with_nocase: String + price_ends_with: String + price_ends_with_nocase: String + price_not_ends_with: String + price_not_ends_with_nocase: String + price_contains: String + price_not_contains: String + price_contains_nocase: String + price_not_contains_nocase: String + price_: TokenPrice_filter + symbol: String + symbol_not: String + symbol_gt: String + symbol_lt: String + symbol_gte: String + symbol_lte: String + symbol_in: [String!] + symbol_not_in: [String!] + symbol_starts_with: String + symbol_starts_with_nocase: String + symbol_not_starts_with: String + symbol_not_starts_with_nocase: String + symbol_ends_with: String + symbol_ends_with_nocase: String + symbol_not_ends_with: String + symbol_not_ends_with_nocase: String + symbol_contains: String + symbol_not_contains: String + symbol_contains_nocase: String + symbol_not_contains_nocase: String + symbolSuccess: Boolean + symbolSuccess_not: Boolean + symbolSuccess_gt: Boolean + symbolSuccess_lt: Boolean + symbolSuccess_gte: Boolean + symbolSuccess_lte: Boolean + symbolSuccess_in: [Boolean!] + symbolSuccess_not_in: [Boolean!] + name: String + name_not: String + name_gt: String + name_lt: String + name_gte: String + name_lte: String + name_in: [String!] + name_not_in: [String!] + name_starts_with: String + name_starts_with_nocase: String + name_not_starts_with: String + name_not_starts_with_nocase: String + name_ends_with: String + name_ends_with_nocase: String + name_not_ends_with: String + name_not_ends_with_nocase: String + name_contains: String + name_not_contains: String + name_contains_nocase: String + name_not_contains_nocase: String + nameSuccess: Boolean + nameSuccess_not: Boolean + nameSuccess_gt: Boolean + nameSuccess_lt: Boolean + nameSuccess_gte: Boolean + nameSuccess_lte: Boolean + nameSuccess_in: [Boolean!] + nameSuccess_not_in: [Boolean!] + decimals: BigInt + decimals_not: BigInt + decimals_gt: BigInt + decimals_lt: BigInt + decimals_gte: BigInt + decimals_lte: BigInt + decimals_in: [BigInt!] + decimals_not_in: [BigInt!] + decimalsSuccess: Boolean + decimalsSuccess_not: Boolean + decimalsSuccess_gt: Boolean + decimalsSuccess_lt: Boolean + decimalsSuccess_gte: Boolean + decimalsSuccess_lte: Boolean + decimalsSuccess_in: [Boolean!] + decimalsSuccess_not_in: [Boolean!] + liquidity: BigInt + liquidity_not: BigInt + liquidity_gt: BigInt + liquidity_lt: BigInt + liquidity_gte: BigInt + liquidity_lte: BigInt + liquidity_in: [BigInt!] + liquidity_not_in: [BigInt!] + liquidityNative: BigDecimal + liquidityNative_not: BigDecimal + liquidityNative_gt: BigDecimal + liquidityNative_lt: BigDecimal + liquidityNative_gte: BigDecimal + liquidityNative_lte: BigDecimal + liquidityNative_in: [BigDecimal!] + liquidityNative_not_in: [BigDecimal!] + liquidityUSD: BigDecimal + liquidityUSD_not: BigDecimal + liquidityUSD_gt: BigDecimal + liquidityUSD_lt: BigDecimal + liquidityUSD_gte: BigDecimal + liquidityUSD_lte: BigDecimal + liquidityUSD_in: [BigDecimal!] + liquidityUSD_not_in: [BigDecimal!] + volume: BigDecimal + volume_not: BigDecimal + volume_gt: BigDecimal + volume_lt: BigDecimal + volume_gte: BigDecimal + volume_lte: BigDecimal + volume_in: [BigDecimal!] + volume_not_in: [BigDecimal!] + volumeNative: BigDecimal + volumeNative_not: BigDecimal + volumeNative_gt: BigDecimal + volumeNative_lt: BigDecimal + volumeNative_gte: BigDecimal + volumeNative_lte: BigDecimal + volumeNative_in: [BigDecimal!] + volumeNative_not_in: [BigDecimal!] + volumeUSD: BigDecimal + volumeUSD_not: BigDecimal + volumeUSD_gt: BigDecimal + volumeUSD_lt: BigDecimal + volumeUSD_gte: BigDecimal + volumeUSD_lte: BigDecimal + volumeUSD_in: [BigDecimal!] + volumeUSD_not_in: [BigDecimal!] + feesNative: BigDecimal + feesNative_not: BigDecimal + feesNative_gt: BigDecimal + feesNative_lt: BigDecimal + feesNative_gte: BigDecimal + feesNative_lte: BigDecimal + feesNative_in: [BigDecimal!] + feesNative_not_in: [BigDecimal!] + feesUSD: BigDecimal + feesUSD_not: BigDecimal + feesUSD_gt: BigDecimal + feesUSD_lt: BigDecimal + feesUSD_gte: BigDecimal + feesUSD_lte: BigDecimal + feesUSD_in: [BigDecimal!] + feesUSD_not_in: [BigDecimal!] + txCount: BigInt + txCount_not: BigInt + txCount_gt: BigInt + txCount_lt: BigInt + txCount_gte: BigInt + txCount_lte: BigInt + txCount_in: [BigInt!] + txCount_not_in: [BigInt!] + pairCount: BigInt + pairCount_not: BigInt + pairCount_gt: BigInt + pairCount_lt: BigInt + pairCount_gte: BigInt + pairCount_lte: BigInt + pairCount_in: [BigInt!] + pairCount_not_in: [BigInt!] + whitelistedPairCount: BigInt + whitelistedPairCount_not: BigInt + whitelistedPairCount_gt: BigInt + whitelistedPairCount_lt: BigInt + whitelistedPairCount_gte: BigInt + whitelistedPairCount_lte: BigInt + whitelistedPairCount_in: [BigInt!] + whitelistedPairCount_not_in: [BigInt!] + pairs_: _TokenPair_filter + whitelistedPairs_: _WhitelistedTokenPair_filter + _change_block: BlockChangedFilter + and: [Token_filter] + or: [Token_filter] +} + +enum TokenPrice_orderBy { + id + token + token__id + token__symbol + token__symbolSuccess + token__name + token__nameSuccess + token__decimals + token__decimalsSuccess + token__liquidity + token__liquidityNative + token__liquidityUSD + token__volume + token__volumeNative + token__volumeUSD + token__feesNative + token__feesUSD + token__txCount + token__pairCount + token__whitelistedPairCount + derivedNative + lastUsdPrice + pricedOffToken + pricedOffToken__id + pricedOffToken__symbol + pricedOffToken__symbolSuccess + pricedOffToken__name + pricedOffToken__nameSuccess + pricedOffToken__decimals + pricedOffToken__decimalsSuccess + pricedOffToken__liquidity + pricedOffToken__liquidityNative + pricedOffToken__liquidityUSD + pricedOffToken__volume + pricedOffToken__volumeNative + pricedOffToken__volumeUSD + pricedOffToken__feesNative + pricedOffToken__feesUSD + pricedOffToken__txCount + pricedOffToken__pairCount + pricedOffToken__whitelistedPairCount + pricedOffPair + pricedOffPair__id + pricedOffPair__type + pricedOffPair__swapFee + pricedOffPair__twapEnabled + pricedOffPair__name + pricedOffPair__source + pricedOffPair__createdAtBlock + pricedOffPair__createdAtTimestamp + pricedOffPair__reserve0 + pricedOffPair__reserve1 + pricedOffPair__liquidity + pricedOffPair__liquidityUSD + pricedOffPair__liquidityNative + pricedOffPair__trackedLiquidityNative + pricedOffPair__token0Price + pricedOffPair__token1Price + pricedOffPair__volumeNative + pricedOffPair__volumeUSD + pricedOffPair__volumeToken0 + pricedOffPair__volumeToken1 + pricedOffPair__feesNative + pricedOffPair__feesUSD + pricedOffPair__apr + pricedOffPair__aprUpdatedAtTimestamp + pricedOffPair__txCount +} + +input TokenPrice_filter { + id: ID + id_not: ID + id_gt: ID + id_lt: ID + id_gte: ID + id_lte: ID + id_in: [ID!] + id_not_in: [ID!] + token: String + token_not: String + token_gt: String + token_lt: String + token_gte: String + token_lte: String + token_in: [String!] + token_not_in: [String!] + token_starts_with: String + token_starts_with_nocase: String + token_not_starts_with: String + token_not_starts_with_nocase: String + token_ends_with: String + token_ends_with_nocase: String + token_not_ends_with: String + token_not_ends_with_nocase: String + token_contains: String + token_not_contains: String + token_contains_nocase: String + token_not_contains_nocase: String + token_: Token_filter + derivedNative: BigDecimal + derivedNative_not: BigDecimal + derivedNative_gt: BigDecimal + derivedNative_lt: BigDecimal + derivedNative_gte: BigDecimal + derivedNative_lte: BigDecimal + derivedNative_in: [BigDecimal!] + derivedNative_not_in: [BigDecimal!] + lastUsdPrice: BigDecimal + lastUsdPrice_not: BigDecimal + lastUsdPrice_gt: BigDecimal + lastUsdPrice_lt: BigDecimal + lastUsdPrice_gte: BigDecimal + lastUsdPrice_lte: BigDecimal + lastUsdPrice_in: [BigDecimal!] + lastUsdPrice_not_in: [BigDecimal!] + pricedOffToken: String + pricedOffToken_not: String + pricedOffToken_gt: String + pricedOffToken_lt: String + pricedOffToken_gte: String + pricedOffToken_lte: String + pricedOffToken_in: [String!] + pricedOffToken_not_in: [String!] + pricedOffToken_starts_with: String + pricedOffToken_starts_with_nocase: String + pricedOffToken_not_starts_with: String + pricedOffToken_not_starts_with_nocase: String + pricedOffToken_ends_with: String + pricedOffToken_ends_with_nocase: String + pricedOffToken_not_ends_with: String + pricedOffToken_not_ends_with_nocase: String + pricedOffToken_contains: String + pricedOffToken_not_contains: String + pricedOffToken_contains_nocase: String + pricedOffToken_not_contains_nocase: String + pricedOffToken_: Token_filter + pricedOffPair: String + pricedOffPair_not: String + pricedOffPair_gt: String + pricedOffPair_lt: String + pricedOffPair_gte: String + pricedOffPair_lte: String + pricedOffPair_in: [String!] + pricedOffPair_not_in: [String!] + pricedOffPair_starts_with: String + pricedOffPair_starts_with_nocase: String + pricedOffPair_not_starts_with: String + pricedOffPair_not_starts_with_nocase: String + pricedOffPair_ends_with: String + pricedOffPair_ends_with_nocase: String + pricedOffPair_not_ends_with: String + pricedOffPair_not_ends_with_nocase: String + pricedOffPair_contains: String + pricedOffPair_not_contains: String + pricedOffPair_contains_nocase: String + pricedOffPair_not_contains_nocase: String + pricedOffPair_: Pair_filter + _change_block: BlockChangedFilter + and: [TokenPrice_filter] + or: [TokenPrice_filter] +} + +enum _TokenPair_orderBy { + id + pair + pair__id + pair__type + pair__swapFee + pair__twapEnabled + pair__name + pair__source + pair__createdAtBlock + pair__createdAtTimestamp + pair__reserve0 + pair__reserve1 + pair__liquidity + pair__liquidityUSD + pair__liquidityNative + pair__trackedLiquidityNative + pair__token0Price + pair__token1Price + pair__volumeNative + pair__volumeUSD + pair__volumeToken0 + pair__volumeToken1 + pair__feesNative + pair__feesUSD + pair__apr + pair__aprUpdatedAtTimestamp + pair__txCount + token + token__id + token__symbol + token__symbolSuccess + token__name + token__nameSuccess + token__decimals + token__decimalsSuccess + token__liquidity + token__liquidityNative + token__liquidityUSD + token__volume + token__volumeNative + token__volumeUSD + token__feesNative + token__feesUSD + token__txCount + token__pairCount + token__whitelistedPairCount +} + +input _TokenPair_filter { + id: ID + id_not: ID + id_gt: ID + id_lt: ID + id_gte: ID + id_lte: ID + id_in: [ID!] + id_not_in: [ID!] + pair: String + pair_not: String + pair_gt: String + pair_lt: String + pair_gte: String + pair_lte: String + pair_in: [String!] + pair_not_in: [String!] + pair_starts_with: String + pair_starts_with_nocase: String + pair_not_starts_with: String + pair_not_starts_with_nocase: String + pair_ends_with: String + pair_ends_with_nocase: String + pair_not_ends_with: String + pair_not_ends_with_nocase: String + pair_contains: String + pair_not_contains: String + pair_contains_nocase: String + pair_not_contains_nocase: String + pair_: Pair_filter + token: String + token_not: String + token_gt: String + token_lt: String + token_gte: String + token_lte: String + token_in: [String!] + token_not_in: [String!] + token_starts_with: String + token_starts_with_nocase: String + token_not_starts_with: String + token_not_starts_with_nocase: String + token_ends_with: String + token_ends_with_nocase: String + token_not_ends_with: String + token_not_ends_with_nocase: String + token_contains: String + token_not_contains: String + token_contains_nocase: String + token_not_contains_nocase: String + token_: Token_filter + _change_block: BlockChangedFilter + and: [_TokenPair_filter] + or: [_TokenPair_filter] +} + +enum _WhitelistedTokenPair_orderBy { + id + pair + pair__id + pair__type + pair__swapFee + pair__twapEnabled + pair__name + pair__source + pair__createdAtBlock + pair__createdAtTimestamp + pair__reserve0 + pair__reserve1 + pair__liquidity + pair__liquidityUSD + pair__liquidityNative + pair__trackedLiquidityNative + pair__token0Price + pair__token1Price + pair__volumeNative + pair__volumeUSD + pair__volumeToken0 + pair__volumeToken1 + pair__feesNative + pair__feesUSD + pair__apr + pair__aprUpdatedAtTimestamp + pair__txCount + token + token__id + token__symbol + token__symbolSuccess + token__name + token__nameSuccess + token__decimals + token__decimalsSuccess + token__liquidity + token__liquidityNative + token__liquidityUSD + token__volume + token__volumeNative + token__volumeUSD + token__feesNative + token__feesUSD + token__txCount + token__pairCount + token__whitelistedPairCount +} + +input _WhitelistedTokenPair_filter { + id: ID + id_not: ID + id_gt: ID + id_lt: ID + id_gte: ID + id_lte: ID + id_in: [ID!] + id_not_in: [ID!] + pair: String + pair_not: String + pair_gt: String + pair_lt: String + pair_gte: String + pair_lte: String + pair_in: [String!] + pair_not_in: [String!] + pair_starts_with: String + pair_starts_with_nocase: String + pair_not_starts_with: String + pair_not_starts_with_nocase: String + pair_ends_with: String + pair_ends_with_nocase: String + pair_not_ends_with: String + pair_not_ends_with_nocase: String + pair_contains: String + pair_not_contains: String + pair_contains_nocase: String + pair_not_contains_nocase: String + pair_: Pair_filter + token: String + token_not: String + token_gt: String + token_lt: String + token_gte: String + token_lte: String + token_in: [String!] + token_not_in: [String!] + token_starts_with: String + token_starts_with_nocase: String + token_not_starts_with: String + token_not_starts_with_nocase: String + token_ends_with: String + token_ends_with_nocase: String + token_not_ends_with: String + token_not_ends_with_nocase: String + token_contains: String + token_not_contains: String + token_contains_nocase: String + token_not_contains_nocase: String + token_: Token_filter + _change_block: BlockChangedFilter + and: [_WhitelistedTokenPair_filter] + or: [_WhitelistedTokenPair_filter] +} + +enum Pair_orderBy { + id + type + swapFee + twapEnabled + name + token0 + token0__id + token0__symbol + token0__symbolSuccess + token0__name + token0__nameSuccess + token0__decimals + token0__decimalsSuccess + token0__liquidity + token0__liquidityNative + token0__liquidityUSD + token0__volume + token0__volumeNative + token0__volumeUSD + token0__feesNative + token0__feesUSD + token0__txCount + token0__pairCount + token0__whitelistedPairCount + token1 + token1__id + token1__symbol + token1__symbolSuccess + token1__name + token1__nameSuccess + token1__decimals + token1__decimalsSuccess + token1__liquidity + token1__liquidityNative + token1__liquidityUSD + token1__volume + token1__volumeNative + token1__volumeUSD + token1__feesNative + token1__feesUSD + token1__txCount + token1__pairCount + token1__whitelistedPairCount + source + createdAtBlock + createdAtTimestamp + reserve0 + reserve1 + liquidity + liquidityUSD + liquidityNative + trackedLiquidityNative + token0Price + token1Price + volumeNative + volumeUSD + volumeToken0 + volumeToken1 + feesNative + feesUSD + apr + aprUpdatedAtTimestamp + txCount + liquidityPositions + liquidityPositionSnapshots + hourSnapshots + daySnapshots +} + +input Pair_filter { + id: ID + id_not: ID + id_gt: ID + id_lt: ID + id_gte: ID + id_lte: ID + id_in: [ID!] + id_not_in: [ID!] + type: PairType + type_not: PairType + type_gt: PairType + type_lt: PairType + type_gte: PairType + type_lte: PairType + type_in: [PairType!] + type_not_in: [PairType!] + swapFee: BigInt + swapFee_not: BigInt + swapFee_gt: BigInt + swapFee_lt: BigInt + swapFee_gte: BigInt + swapFee_lte: BigInt + swapFee_in: [BigInt!] + swapFee_not_in: [BigInt!] + twapEnabled: Boolean + twapEnabled_not: Boolean + twapEnabled_gt: Boolean + twapEnabled_lt: Boolean + twapEnabled_gte: Boolean + twapEnabled_lte: Boolean + twapEnabled_in: [Boolean!] + twapEnabled_not_in: [Boolean!] + name: String + name_not: String + name_gt: String + name_lt: String + name_gte: String + name_lte: String + name_in: [String!] + name_not_in: [String!] + name_starts_with: String + name_starts_with_nocase: String + name_not_starts_with: String + name_not_starts_with_nocase: String + name_ends_with: String + name_ends_with_nocase: String + name_not_ends_with: String + name_not_ends_with_nocase: String + name_contains: String + name_not_contains: String + name_contains_nocase: String + name_not_contains_nocase: String + token0: String + token0_not: String + token0_gt: String + token0_lt: String + token0_gte: String + token0_lte: String + token0_in: [String!] + token0_not_in: [String!] + token0_starts_with: String + token0_starts_with_nocase: String + token0_not_starts_with: String + token0_not_starts_with_nocase: String + token0_ends_with: String + token0_ends_with_nocase: String + token0_not_ends_with: String + token0_not_ends_with_nocase: String + token0_contains: String + token0_not_contains: String + token0_contains_nocase: String + token0_not_contains_nocase: String + token0_: Token_filter + token1: String + token1_not: String + token1_gt: String + token1_lt: String + token1_gte: String + token1_lte: String + token1_in: [String!] + token1_not_in: [String!] + token1_starts_with: String + token1_starts_with_nocase: String + token1_not_starts_with: String + token1_not_starts_with_nocase: String + token1_ends_with: String + token1_ends_with_nocase: String + token1_not_ends_with: String + token1_not_ends_with_nocase: String + token1_contains: String + token1_not_contains: String + token1_contains_nocase: String + token1_not_contains_nocase: String + token1_: Token_filter + source: String + source_not: String + source_gt: String + source_lt: String + source_gte: String + source_lte: String + source_in: [String!] + source_not_in: [String!] + source_starts_with: String + source_starts_with_nocase: String + source_not_starts_with: String + source_not_starts_with_nocase: String + source_ends_with: String + source_ends_with_nocase: String + source_not_ends_with: String + source_not_ends_with_nocase: String + source_contains: String + source_not_contains: String + source_contains_nocase: String + source_not_contains_nocase: String + createdAtBlock: BigInt + createdAtBlock_not: BigInt + createdAtBlock_gt: BigInt + createdAtBlock_lt: BigInt + createdAtBlock_gte: BigInt + createdAtBlock_lte: BigInt + createdAtBlock_in: [BigInt!] + createdAtBlock_not_in: [BigInt!] + createdAtTimestamp: BigInt + createdAtTimestamp_not: BigInt + createdAtTimestamp_gt: BigInt + createdAtTimestamp_lt: BigInt + createdAtTimestamp_gte: BigInt + createdAtTimestamp_lte: BigInt + createdAtTimestamp_in: [BigInt!] + createdAtTimestamp_not_in: [BigInt!] + reserve0: BigInt + reserve0_not: BigInt + reserve0_gt: BigInt + reserve0_lt: BigInt + reserve0_gte: BigInt + reserve0_lte: BigInt + reserve0_in: [BigInt!] + reserve0_not_in: [BigInt!] + reserve1: BigInt + reserve1_not: BigInt + reserve1_gt: BigInt + reserve1_lt: BigInt + reserve1_gte: BigInt + reserve1_lte: BigInt + reserve1_in: [BigInt!] + reserve1_not_in: [BigInt!] + liquidity: BigInt + liquidity_not: BigInt + liquidity_gt: BigInt + liquidity_lt: BigInt + liquidity_gte: BigInt + liquidity_lte: BigInt + liquidity_in: [BigInt!] + liquidity_not_in: [BigInt!] + liquidityUSD: BigDecimal + liquidityUSD_not: BigDecimal + liquidityUSD_gt: BigDecimal + liquidityUSD_lt: BigDecimal + liquidityUSD_gte: BigDecimal + liquidityUSD_lte: BigDecimal + liquidityUSD_in: [BigDecimal!] + liquidityUSD_not_in: [BigDecimal!] + liquidityNative: BigDecimal + liquidityNative_not: BigDecimal + liquidityNative_gt: BigDecimal + liquidityNative_lt: BigDecimal + liquidityNative_gte: BigDecimal + liquidityNative_lte: BigDecimal + liquidityNative_in: [BigDecimal!] + liquidityNative_not_in: [BigDecimal!] + trackedLiquidityNative: BigDecimal + trackedLiquidityNative_not: BigDecimal + trackedLiquidityNative_gt: BigDecimal + trackedLiquidityNative_lt: BigDecimal + trackedLiquidityNative_gte: BigDecimal + trackedLiquidityNative_lte: BigDecimal + trackedLiquidityNative_in: [BigDecimal!] + trackedLiquidityNative_not_in: [BigDecimal!] + token0Price: BigDecimal + token0Price_not: BigDecimal + token0Price_gt: BigDecimal + token0Price_lt: BigDecimal + token0Price_gte: BigDecimal + token0Price_lte: BigDecimal + token0Price_in: [BigDecimal!] + token0Price_not_in: [BigDecimal!] + token1Price: BigDecimal + token1Price_not: BigDecimal + token1Price_gt: BigDecimal + token1Price_lt: BigDecimal + token1Price_gte: BigDecimal + token1Price_lte: BigDecimal + token1Price_in: [BigDecimal!] + token1Price_not_in: [BigDecimal!] + volumeNative: BigDecimal + volumeNative_not: BigDecimal + volumeNative_gt: BigDecimal + volumeNative_lt: BigDecimal + volumeNative_gte: BigDecimal + volumeNative_lte: BigDecimal + volumeNative_in: [BigDecimal!] + volumeNative_not_in: [BigDecimal!] + volumeUSD: BigDecimal + volumeUSD_not: BigDecimal + volumeUSD_gt: BigDecimal + volumeUSD_lt: BigDecimal + volumeUSD_gte: BigDecimal + volumeUSD_lte: BigDecimal + volumeUSD_in: [BigDecimal!] + volumeUSD_not_in: [BigDecimal!] + volumeToken0: BigDecimal + volumeToken0_not: BigDecimal + volumeToken0_gt: BigDecimal + volumeToken0_lt: BigDecimal + volumeToken0_gte: BigDecimal + volumeToken0_lte: BigDecimal + volumeToken0_in: [BigDecimal!] + volumeToken0_not_in: [BigDecimal!] + volumeToken1: BigDecimal + volumeToken1_not: BigDecimal + volumeToken1_gt: BigDecimal + volumeToken1_lt: BigDecimal + volumeToken1_gte: BigDecimal + volumeToken1_lte: BigDecimal + volumeToken1_in: [BigDecimal!] + volumeToken1_not_in: [BigDecimal!] + feesNative: BigDecimal + feesNative_not: BigDecimal + feesNative_gt: BigDecimal + feesNative_lt: BigDecimal + feesNative_gte: BigDecimal + feesNative_lte: BigDecimal + feesNative_in: [BigDecimal!] + feesNative_not_in: [BigDecimal!] + feesUSD: BigDecimal + feesUSD_not: BigDecimal + feesUSD_gt: BigDecimal + feesUSD_lt: BigDecimal + feesUSD_gte: BigDecimal + feesUSD_lte: BigDecimal + feesUSD_in: [BigDecimal!] + feesUSD_not_in: [BigDecimal!] + apr: BigDecimal + apr_not: BigDecimal + apr_gt: BigDecimal + apr_lt: BigDecimal + apr_gte: BigDecimal + apr_lte: BigDecimal + apr_in: [BigDecimal!] + apr_not_in: [BigDecimal!] + aprUpdatedAtTimestamp: BigInt + aprUpdatedAtTimestamp_not: BigInt + aprUpdatedAtTimestamp_gt: BigInt + aprUpdatedAtTimestamp_lt: BigInt + aprUpdatedAtTimestamp_gte: BigInt + aprUpdatedAtTimestamp_lte: BigInt + aprUpdatedAtTimestamp_in: [BigInt!] + aprUpdatedAtTimestamp_not_in: [BigInt!] + txCount: BigInt + txCount_not: BigInt + txCount_gt: BigInt + txCount_lt: BigInt + txCount_gte: BigInt + txCount_lte: BigInt + txCount_in: [BigInt!] + txCount_not_in: [BigInt!] + liquidityPositions_: LiquidityPosition_filter + liquidityPositionSnapshots_: LiquidityPositionSnapshot_filter + hourSnapshots_: PairHourSnapshot_filter + daySnapshots_: PairDaySnapshot_filter + _change_block: BlockChangedFilter + and: [Pair_filter] + or: [Pair_filter] +} + +enum User_orderBy { + id + lpSnapshotsCount + liquidityPositions +} + +input User_filter { + id: ID + id_not: ID + id_gt: ID + id_lt: ID + id_gte: ID + id_lte: ID + id_in: [ID!] + id_not_in: [ID!] + lpSnapshotsCount: BigInt + lpSnapshotsCount_not: BigInt + lpSnapshotsCount_gt: BigInt + lpSnapshotsCount_lt: BigInt + lpSnapshotsCount_gte: BigInt + lpSnapshotsCount_lte: BigInt + lpSnapshotsCount_in: [BigInt!] + lpSnapshotsCount_not_in: [BigInt!] + liquidityPositions_: LiquidityPosition_filter + _change_block: BlockChangedFilter + and: [User_filter] + or: [User_filter] +} + +enum LiquidityPosition_orderBy { + id + pair + pair__id + pair__type + pair__swapFee + pair__twapEnabled + pair__name + pair__source + pair__createdAtBlock + pair__createdAtTimestamp + pair__reserve0 + pair__reserve1 + pair__liquidity + pair__liquidityUSD + pair__liquidityNative + pair__trackedLiquidityNative + pair__token0Price + pair__token1Price + pair__volumeNative + pair__volumeUSD + pair__volumeToken0 + pair__volumeToken1 + pair__feesNative + pair__feesUSD + pair__apr + pair__aprUpdatedAtTimestamp + pair__txCount + user + user__id + user__lpSnapshotsCount + balance + createdAtBlock + createdAtTimestamp +} + +input LiquidityPosition_filter { + id: ID + id_not: ID + id_gt: ID + id_lt: ID + id_gte: ID + id_lte: ID + id_in: [ID!] + id_not_in: [ID!] + pair: String + pair_not: String + pair_gt: String + pair_lt: String + pair_gte: String + pair_lte: String + pair_in: [String!] + pair_not_in: [String!] + pair_starts_with: String + pair_starts_with_nocase: String + pair_not_starts_with: String + pair_not_starts_with_nocase: String + pair_ends_with: String + pair_ends_with_nocase: String + pair_not_ends_with: String + pair_not_ends_with_nocase: String + pair_contains: String + pair_not_contains: String + pair_contains_nocase: String + pair_not_contains_nocase: String + pair_: Pair_filter + user: String + user_not: String + user_gt: String + user_lt: String + user_gte: String + user_lte: String + user_in: [String!] + user_not_in: [String!] + user_starts_with: String + user_starts_with_nocase: String + user_not_starts_with: String + user_not_starts_with_nocase: String + user_ends_with: String + user_ends_with_nocase: String + user_not_ends_with: String + user_not_ends_with_nocase: String + user_contains: String + user_not_contains: String + user_contains_nocase: String + user_not_contains_nocase: String + user_: User_filter + balance: BigInt + balance_not: BigInt + balance_gt: BigInt + balance_lt: BigInt + balance_gte: BigInt + balance_lte: BigInt + balance_in: [BigInt!] + balance_not_in: [BigInt!] + createdAtBlock: BigInt + createdAtBlock_not: BigInt + createdAtBlock_gt: BigInt + createdAtBlock_lt: BigInt + createdAtBlock_gte: BigInt + createdAtBlock_lte: BigInt + createdAtBlock_in: [BigInt!] + createdAtBlock_not_in: [BigInt!] + createdAtTimestamp: BigInt + createdAtTimestamp_not: BigInt + createdAtTimestamp_gt: BigInt + createdAtTimestamp_lt: BigInt + createdAtTimestamp_gte: BigInt + createdAtTimestamp_lte: BigInt + createdAtTimestamp_in: [BigInt!] + createdAtTimestamp_not_in: [BigInt!] + _change_block: BlockChangedFilter + and: [LiquidityPosition_filter] + or: [LiquidityPosition_filter] +} + +enum Mint_orderBy { + id + transaction + transaction__id + transaction__gasLimit + transaction__gasPrice + transaction__createdAtBlock + transaction__createdAtTimestamp + timestamp + pair + pair__id + pair__type + pair__swapFee + pair__twapEnabled + pair__name + pair__source + pair__createdAtBlock + pair__createdAtTimestamp + pair__reserve0 + pair__reserve1 + pair__liquidity + pair__liquidityUSD + pair__liquidityNative + pair__trackedLiquidityNative + pair__token0Price + pair__token1Price + pair__volumeNative + pair__volumeUSD + pair__volumeToken0 + pair__volumeToken1 + pair__feesNative + pair__feesUSD + pair__apr + pair__aprUpdatedAtTimestamp + pair__txCount + to + liquidity + sender + amount0 + amount1 + logIndex + amountUSD + feeTo + feeLiquidity +} + +input Mint_filter { + id: ID + id_not: ID + id_gt: ID + id_lt: ID + id_gte: ID + id_lte: ID + id_in: [ID!] + id_not_in: [ID!] + transaction: String + transaction_not: String + transaction_gt: String + transaction_lt: String + transaction_gte: String + transaction_lte: String + transaction_in: [String!] + transaction_not_in: [String!] + transaction_starts_with: String + transaction_starts_with_nocase: String + transaction_not_starts_with: String + transaction_not_starts_with_nocase: String + transaction_ends_with: String + transaction_ends_with_nocase: String + transaction_not_ends_with: String + transaction_not_ends_with_nocase: String + transaction_contains: String + transaction_not_contains: String + transaction_contains_nocase: String + transaction_not_contains_nocase: String + transaction_: Transaction_filter + timestamp: BigInt + timestamp_not: BigInt + timestamp_gt: BigInt + timestamp_lt: BigInt + timestamp_gte: BigInt + timestamp_lte: BigInt + timestamp_in: [BigInt!] + timestamp_not_in: [BigInt!] + pair: String + pair_not: String + pair_gt: String + pair_lt: String + pair_gte: String + pair_lte: String + pair_in: [String!] + pair_not_in: [String!] + pair_starts_with: String + pair_starts_with_nocase: String + pair_not_starts_with: String + pair_not_starts_with_nocase: String + pair_ends_with: String + pair_ends_with_nocase: String + pair_not_ends_with: String + pair_not_ends_with_nocase: String + pair_contains: String + pair_not_contains: String + pair_contains_nocase: String + pair_not_contains_nocase: String + pair_: Pair_filter + to: String + to_not: String + to_gt: String + to_lt: String + to_gte: String + to_lte: String + to_in: [String!] + to_not_in: [String!] + to_starts_with: String + to_starts_with_nocase: String + to_not_starts_with: String + to_not_starts_with_nocase: String + to_ends_with: String + to_ends_with_nocase: String + to_not_ends_with: String + to_not_ends_with_nocase: String + to_contains: String + to_not_contains: String + to_contains_nocase: String + to_not_contains_nocase: String + liquidity: BigDecimal + liquidity_not: BigDecimal + liquidity_gt: BigDecimal + liquidity_lt: BigDecimal + liquidity_gte: BigDecimal + liquidity_lte: BigDecimal + liquidity_in: [BigDecimal!] + liquidity_not_in: [BigDecimal!] + sender: Bytes + sender_not: Bytes + sender_gt: Bytes + sender_lt: Bytes + sender_gte: Bytes + sender_lte: Bytes + sender_in: [Bytes!] + sender_not_in: [Bytes!] + sender_contains: Bytes + sender_not_contains: Bytes + amount0: BigDecimal + amount0_not: BigDecimal + amount0_gt: BigDecimal + amount0_lt: BigDecimal + amount0_gte: BigDecimal + amount0_lte: BigDecimal + amount0_in: [BigDecimal!] + amount0_not_in: [BigDecimal!] + amount1: BigDecimal + amount1_not: BigDecimal + amount1_gt: BigDecimal + amount1_lt: BigDecimal + amount1_gte: BigDecimal + amount1_lte: BigDecimal + amount1_in: [BigDecimal!] + amount1_not_in: [BigDecimal!] + logIndex: BigInt + logIndex_not: BigInt + logIndex_gt: BigInt + logIndex_lt: BigInt + logIndex_gte: BigInt + logIndex_lte: BigInt + logIndex_in: [BigInt!] + logIndex_not_in: [BigInt!] + amountUSD: BigDecimal + amountUSD_not: BigDecimal + amountUSD_gt: BigDecimal + amountUSD_lt: BigDecimal + amountUSD_gte: BigDecimal + amountUSD_lte: BigDecimal + amountUSD_in: [BigDecimal!] + amountUSD_not_in: [BigDecimal!] + feeTo: Bytes + feeTo_not: Bytes + feeTo_gt: Bytes + feeTo_lt: Bytes + feeTo_gte: Bytes + feeTo_lte: Bytes + feeTo_in: [Bytes!] + feeTo_not_in: [Bytes!] + feeTo_contains: Bytes + feeTo_not_contains: Bytes + feeLiquidity: BigDecimal + feeLiquidity_not: BigDecimal + feeLiquidity_gt: BigDecimal + feeLiquidity_lt: BigDecimal + feeLiquidity_gte: BigDecimal + feeLiquidity_lte: BigDecimal + feeLiquidity_in: [BigDecimal!] + feeLiquidity_not_in: [BigDecimal!] + _change_block: BlockChangedFilter + and: [Mint_filter] + or: [Mint_filter] +} + +enum Burn_orderBy { + id + transaction + transaction__id + transaction__gasLimit + transaction__gasPrice + transaction__createdAtBlock + transaction__createdAtTimestamp + timestamp + pair + pair__id + pair__type + pair__swapFee + pair__twapEnabled + pair__name + pair__source + pair__createdAtBlock + pair__createdAtTimestamp + pair__reserve0 + pair__reserve1 + pair__liquidity + pair__liquidityUSD + pair__liquidityNative + pair__trackedLiquidityNative + pair__token0Price + pair__token1Price + pair__volumeNative + pair__volumeUSD + pair__volumeToken0 + pair__volumeToken1 + pair__feesNative + pair__feesUSD + pair__apr + pair__aprUpdatedAtTimestamp + pair__txCount + liquidity + sender + amount0 + amount1 + to + logIndex + amountUSD + complete + feeTo + feeLiquidity +} + +input Burn_filter { + id: ID + id_not: ID + id_gt: ID + id_lt: ID + id_gte: ID + id_lte: ID + id_in: [ID!] + id_not_in: [ID!] + transaction: String + transaction_not: String + transaction_gt: String + transaction_lt: String + transaction_gte: String + transaction_lte: String + transaction_in: [String!] + transaction_not_in: [String!] + transaction_starts_with: String + transaction_starts_with_nocase: String + transaction_not_starts_with: String + transaction_not_starts_with_nocase: String + transaction_ends_with: String + transaction_ends_with_nocase: String + transaction_not_ends_with: String + transaction_not_ends_with_nocase: String + transaction_contains: String + transaction_not_contains: String + transaction_contains_nocase: String + transaction_not_contains_nocase: String + transaction_: Transaction_filter + timestamp: BigInt + timestamp_not: BigInt + timestamp_gt: BigInt + timestamp_lt: BigInt + timestamp_gte: BigInt + timestamp_lte: BigInt + timestamp_in: [BigInt!] + timestamp_not_in: [BigInt!] + pair: String + pair_not: String + pair_gt: String + pair_lt: String + pair_gte: String + pair_lte: String + pair_in: [String!] + pair_not_in: [String!] + pair_starts_with: String + pair_starts_with_nocase: String + pair_not_starts_with: String + pair_not_starts_with_nocase: String + pair_ends_with: String + pair_ends_with_nocase: String + pair_not_ends_with: String + pair_not_ends_with_nocase: String + pair_contains: String + pair_not_contains: String + pair_contains_nocase: String + pair_not_contains_nocase: String + pair_: Pair_filter + liquidity: BigDecimal + liquidity_not: BigDecimal + liquidity_gt: BigDecimal + liquidity_lt: BigDecimal + liquidity_gte: BigDecimal + liquidity_lte: BigDecimal + liquidity_in: [BigDecimal!] + liquidity_not_in: [BigDecimal!] + sender: String + sender_not: String + sender_gt: String + sender_lt: String + sender_gte: String + sender_lte: String + sender_in: [String!] + sender_not_in: [String!] + sender_starts_with: String + sender_starts_with_nocase: String + sender_not_starts_with: String + sender_not_starts_with_nocase: String + sender_ends_with: String + sender_ends_with_nocase: String + sender_not_ends_with: String + sender_not_ends_with_nocase: String + sender_contains: String + sender_not_contains: String + sender_contains_nocase: String + sender_not_contains_nocase: String + amount0: BigDecimal + amount0_not: BigDecimal + amount0_gt: BigDecimal + amount0_lt: BigDecimal + amount0_gte: BigDecimal + amount0_lte: BigDecimal + amount0_in: [BigDecimal!] + amount0_not_in: [BigDecimal!] + amount1: BigDecimal + amount1_not: BigDecimal + amount1_gt: BigDecimal + amount1_lt: BigDecimal + amount1_gte: BigDecimal + amount1_lte: BigDecimal + amount1_in: [BigDecimal!] + amount1_not_in: [BigDecimal!] + to: String + to_not: String + to_gt: String + to_lt: String + to_gte: String + to_lte: String + to_in: [String!] + to_not_in: [String!] + to_starts_with: String + to_starts_with_nocase: String + to_not_starts_with: String + to_not_starts_with_nocase: String + to_ends_with: String + to_ends_with_nocase: String + to_not_ends_with: String + to_not_ends_with_nocase: String + to_contains: String + to_not_contains: String + to_contains_nocase: String + to_not_contains_nocase: String + logIndex: BigInt + logIndex_not: BigInt + logIndex_gt: BigInt + logIndex_lt: BigInt + logIndex_gte: BigInt + logIndex_lte: BigInt + logIndex_in: [BigInt!] + logIndex_not_in: [BigInt!] + amountUSD: BigDecimal + amountUSD_not: BigDecimal + amountUSD_gt: BigDecimal + amountUSD_lt: BigDecimal + amountUSD_gte: BigDecimal + amountUSD_lte: BigDecimal + amountUSD_in: [BigDecimal!] + amountUSD_not_in: [BigDecimal!] + complete: Boolean + complete_not: Boolean + complete_gt: Boolean + complete_lt: Boolean + complete_gte: Boolean + complete_lte: Boolean + complete_in: [Boolean!] + complete_not_in: [Boolean!] + feeTo: String + feeTo_not: String + feeTo_gt: String + feeTo_lt: String + feeTo_gte: String + feeTo_lte: String + feeTo_in: [String!] + feeTo_not_in: [String!] + feeTo_starts_with: String + feeTo_starts_with_nocase: String + feeTo_not_starts_with: String + feeTo_not_starts_with_nocase: String + feeTo_ends_with: String + feeTo_ends_with_nocase: String + feeTo_not_ends_with: String + feeTo_not_ends_with_nocase: String + feeTo_contains: String + feeTo_not_contains: String + feeTo_contains_nocase: String + feeTo_not_contains_nocase: String + feeLiquidity: BigDecimal + feeLiquidity_not: BigDecimal + feeLiquidity_gt: BigDecimal + feeLiquidity_lt: BigDecimal + feeLiquidity_gte: BigDecimal + feeLiquidity_lte: BigDecimal + feeLiquidity_in: [BigDecimal!] + feeLiquidity_not_in: [BigDecimal!] + _change_block: BlockChangedFilter + and: [Burn_filter] + or: [Burn_filter] +} + +enum Swap_orderBy { + id + transaction + transaction__id + transaction__gasLimit + transaction__gasPrice + transaction__createdAtBlock + transaction__createdAtTimestamp + timestamp + pair + pair__id + pair__type + pair__swapFee + pair__twapEnabled + pair__name + pair__source + pair__createdAtBlock + pair__createdAtTimestamp + pair__reserve0 + pair__reserve1 + pair__liquidity + pair__liquidityUSD + pair__liquidityNative + pair__trackedLiquidityNative + pair__token0Price + pair__token1Price + pair__volumeNative + pair__volumeUSD + pair__volumeToken0 + pair__volumeToken1 + pair__feesNative + pair__feesUSD + pair__apr + pair__aprUpdatedAtTimestamp + pair__txCount + sender + tokenIn + tokenIn__id + tokenIn__symbol + tokenIn__symbolSuccess + tokenIn__name + tokenIn__nameSuccess + tokenIn__decimals + tokenIn__decimalsSuccess + tokenIn__liquidity + tokenIn__liquidityNative + tokenIn__liquidityUSD + tokenIn__volume + tokenIn__volumeNative + tokenIn__volumeUSD + tokenIn__feesNative + tokenIn__feesUSD + tokenIn__txCount + tokenIn__pairCount + tokenIn__whitelistedPairCount + tokenOut + tokenOut__id + tokenOut__symbol + tokenOut__symbolSuccess + tokenOut__name + tokenOut__nameSuccess + tokenOut__decimals + tokenOut__decimalsSuccess + tokenOut__liquidity + tokenOut__liquidityNative + tokenOut__liquidityUSD + tokenOut__volume + tokenOut__volumeNative + tokenOut__volumeUSD + tokenOut__feesNative + tokenOut__feesUSD + tokenOut__txCount + tokenOut__pairCount + tokenOut__whitelistedPairCount + amountIn + amountOut + to + logIndex + amountUSD +} + +input Swap_filter { + id: ID + id_not: ID + id_gt: ID + id_lt: ID + id_gte: ID + id_lte: ID + id_in: [ID!] + id_not_in: [ID!] + transaction: String + transaction_not: String + transaction_gt: String + transaction_lt: String + transaction_gte: String + transaction_lte: String + transaction_in: [String!] + transaction_not_in: [String!] + transaction_starts_with: String + transaction_starts_with_nocase: String + transaction_not_starts_with: String + transaction_not_starts_with_nocase: String + transaction_ends_with: String + transaction_ends_with_nocase: String + transaction_not_ends_with: String + transaction_not_ends_with_nocase: String + transaction_contains: String + transaction_not_contains: String + transaction_contains_nocase: String + transaction_not_contains_nocase: String + transaction_: Transaction_filter + timestamp: BigInt + timestamp_not: BigInt + timestamp_gt: BigInt + timestamp_lt: BigInt + timestamp_gte: BigInt + timestamp_lte: BigInt + timestamp_in: [BigInt!] + timestamp_not_in: [BigInt!] + pair: String + pair_not: String + pair_gt: String + pair_lt: String + pair_gte: String + pair_lte: String + pair_in: [String!] + pair_not_in: [String!] + pair_starts_with: String + pair_starts_with_nocase: String + pair_not_starts_with: String + pair_not_starts_with_nocase: String + pair_ends_with: String + pair_ends_with_nocase: String + pair_not_ends_with: String + pair_not_ends_with_nocase: String + pair_contains: String + pair_not_contains: String + pair_contains_nocase: String + pair_not_contains_nocase: String + pair_: Pair_filter + sender: String + sender_not: String + sender_gt: String + sender_lt: String + sender_gte: String + sender_lte: String + sender_in: [String!] + sender_not_in: [String!] + sender_starts_with: String + sender_starts_with_nocase: String + sender_not_starts_with: String + sender_not_starts_with_nocase: String + sender_ends_with: String + sender_ends_with_nocase: String + sender_not_ends_with: String + sender_not_ends_with_nocase: String + sender_contains: String + sender_not_contains: String + sender_contains_nocase: String + sender_not_contains_nocase: String + tokenIn: String + tokenIn_not: String + tokenIn_gt: String + tokenIn_lt: String + tokenIn_gte: String + tokenIn_lte: String + tokenIn_in: [String!] + tokenIn_not_in: [String!] + tokenIn_starts_with: String + tokenIn_starts_with_nocase: String + tokenIn_not_starts_with: String + tokenIn_not_starts_with_nocase: String + tokenIn_ends_with: String + tokenIn_ends_with_nocase: String + tokenIn_not_ends_with: String + tokenIn_not_ends_with_nocase: String + tokenIn_contains: String + tokenIn_not_contains: String + tokenIn_contains_nocase: String + tokenIn_not_contains_nocase: String + tokenIn_: Token_filter + tokenOut: String + tokenOut_not: String + tokenOut_gt: String + tokenOut_lt: String + tokenOut_gte: String + tokenOut_lte: String + tokenOut_in: [String!] + tokenOut_not_in: [String!] + tokenOut_starts_with: String + tokenOut_starts_with_nocase: String + tokenOut_not_starts_with: String + tokenOut_not_starts_with_nocase: String + tokenOut_ends_with: String + tokenOut_ends_with_nocase: String + tokenOut_not_ends_with: String + tokenOut_not_ends_with_nocase: String + tokenOut_contains: String + tokenOut_not_contains: String + tokenOut_contains_nocase: String + tokenOut_not_contains_nocase: String + tokenOut_: Token_filter + amountIn: BigDecimal + amountIn_not: BigDecimal + amountIn_gt: BigDecimal + amountIn_lt: BigDecimal + amountIn_gte: BigDecimal + amountIn_lte: BigDecimal + amountIn_in: [BigDecimal!] + amountIn_not_in: [BigDecimal!] + amountOut: BigDecimal + amountOut_not: BigDecimal + amountOut_gt: BigDecimal + amountOut_lt: BigDecimal + amountOut_gte: BigDecimal + amountOut_lte: BigDecimal + amountOut_in: [BigDecimal!] + amountOut_not_in: [BigDecimal!] + to: String + to_not: String + to_gt: String + to_lt: String + to_gte: String + to_lte: String + to_in: [String!] + to_not_in: [String!] + to_starts_with: String + to_starts_with_nocase: String + to_not_starts_with: String + to_not_starts_with_nocase: String + to_ends_with: String + to_ends_with_nocase: String + to_not_ends_with: String + to_not_ends_with_nocase: String + to_contains: String + to_not_contains: String + to_contains_nocase: String + to_not_contains_nocase: String + logIndex: BigInt + logIndex_not: BigInt + logIndex_gt: BigInt + logIndex_lt: BigInt + logIndex_gte: BigInt + logIndex_lte: BigInt + logIndex_in: [BigInt!] + logIndex_not_in: [BigInt!] + amountUSD: BigDecimal + amountUSD_not: BigDecimal + amountUSD_gt: BigDecimal + amountUSD_lt: BigDecimal + amountUSD_gte: BigDecimal + amountUSD_lte: BigDecimal + amountUSD_in: [BigDecimal!] + amountUSD_not_in: [BigDecimal!] + _change_block: BlockChangedFilter + and: [Swap_filter] + or: [Swap_filter] +} + +enum Transaction_orderBy { + id + gasLimit + gasPrice + mints + burns + swaps + createdAtBlock + createdAtTimestamp +} + +input Transaction_filter { + id: ID + id_not: ID + id_gt: ID + id_lt: ID + id_gte: ID + id_lte: ID + id_in: [ID!] + id_not_in: [ID!] + gasLimit: BigInt + gasLimit_not: BigInt + gasLimit_gt: BigInt + gasLimit_lt: BigInt + gasLimit_gte: BigInt + gasLimit_lte: BigInt + gasLimit_in: [BigInt!] + gasLimit_not_in: [BigInt!] + gasPrice: BigInt + gasPrice_not: BigInt + gasPrice_gt: BigInt + gasPrice_lt: BigInt + gasPrice_gte: BigInt + gasPrice_lte: BigInt + gasPrice_in: [BigInt!] + gasPrice_not_in: [BigInt!] + mints: [String!] + mints_not: [String!] + mints_contains: [String!] + mints_not_contains: [String!] + mints_contains_nocase: [String!] + mints_not_contains_nocase: [String!] + mints_: Mint_filter + burns: [String!] + burns_not: [String!] + burns_contains: [String!] + burns_not_contains: [String!] + burns_contains_nocase: [String!] + burns_not_contains_nocase: [String!] + burns_: Burn_filter + swaps: [String!] + swaps_not: [String!] + swaps_contains: [String!] + swaps_not_contains: [String!] + swaps_contains_nocase: [String!] + swaps_not_contains_nocase: [String!] + swaps_: Swap_filter + createdAtBlock: BigInt + createdAtBlock_not: BigInt + createdAtBlock_gt: BigInt + createdAtBlock_lt: BigInt + createdAtBlock_gte: BigInt + createdAtBlock_lte: BigInt + createdAtBlock_in: [BigInt!] + createdAtBlock_not_in: [BigInt!] + createdAtTimestamp: BigInt + createdAtTimestamp_not: BigInt + createdAtTimestamp_gt: BigInt + createdAtTimestamp_lt: BigInt + createdAtTimestamp_gte: BigInt + createdAtTimestamp_lte: BigInt + createdAtTimestamp_in: [BigInt!] + createdAtTimestamp_not_in: [BigInt!] + _change_block: BlockChangedFilter + and: [Transaction_filter] + or: [Transaction_filter] +} + +enum LiquidityPositionSnapshot_orderBy { + id + liquidityPosition + liquidityPosition__id + liquidityPosition__balance + liquidityPosition__createdAtBlock + liquidityPosition__createdAtTimestamp + timestamp + block + user + user__id + user__lpSnapshotsCount + pair + pair__id + pair__type + pair__swapFee + pair__twapEnabled + pair__name + pair__source + pair__createdAtBlock + pair__createdAtTimestamp + pair__reserve0 + pair__reserve1 + pair__liquidity + pair__liquidityUSD + pair__liquidityNative + pair__trackedLiquidityNative + pair__token0Price + pair__token1Price + pair__volumeNative + pair__volumeUSD + pair__volumeToken0 + pair__volumeToken1 + pair__feesNative + pair__feesUSD + pair__apr + pair__aprUpdatedAtTimestamp + pair__txCount + token0PriceUSD + token1PriceUSD + reserve0 + reserve1 + reserveUSD + liquidityTokenTotalSupply + liquidityTokenBalance +} + +input LiquidityPositionSnapshot_filter { + id: ID + id_not: ID + id_gt: ID + id_lt: ID + id_gte: ID + id_lte: ID + id_in: [ID!] + id_not_in: [ID!] + liquidityPosition: String + liquidityPosition_not: String + liquidityPosition_gt: String + liquidityPosition_lt: String + liquidityPosition_gte: String + liquidityPosition_lte: String + liquidityPosition_in: [String!] + liquidityPosition_not_in: [String!] + liquidityPosition_starts_with: String + liquidityPosition_starts_with_nocase: String + liquidityPosition_not_starts_with: String + liquidityPosition_not_starts_with_nocase: String + liquidityPosition_ends_with: String + liquidityPosition_ends_with_nocase: String + liquidityPosition_not_ends_with: String + liquidityPosition_not_ends_with_nocase: String + liquidityPosition_contains: String + liquidityPosition_not_contains: String + liquidityPosition_contains_nocase: String + liquidityPosition_not_contains_nocase: String + liquidityPosition_: LiquidityPosition_filter + timestamp: Int + timestamp_not: Int + timestamp_gt: Int + timestamp_lt: Int + timestamp_gte: Int + timestamp_lte: Int + timestamp_in: [Int!] + timestamp_not_in: [Int!] + block: Int + block_not: Int + block_gt: Int + block_lt: Int + block_gte: Int + block_lte: Int + block_in: [Int!] + block_not_in: [Int!] + user: String + user_not: String + user_gt: String + user_lt: String + user_gte: String + user_lte: String + user_in: [String!] + user_not_in: [String!] + user_starts_with: String + user_starts_with_nocase: String + user_not_starts_with: String + user_not_starts_with_nocase: String + user_ends_with: String + user_ends_with_nocase: String + user_not_ends_with: String + user_not_ends_with_nocase: String + user_contains: String + user_not_contains: String + user_contains_nocase: String + user_not_contains_nocase: String + user_: User_filter + pair: String + pair_not: String + pair_gt: String + pair_lt: String + pair_gte: String + pair_lte: String + pair_in: [String!] + pair_not_in: [String!] + pair_starts_with: String + pair_starts_with_nocase: String + pair_not_starts_with: String + pair_not_starts_with_nocase: String + pair_ends_with: String + pair_ends_with_nocase: String + pair_not_ends_with: String + pair_not_ends_with_nocase: String + pair_contains: String + pair_not_contains: String + pair_contains_nocase: String + pair_not_contains_nocase: String + pair_: Pair_filter + token0PriceUSD: BigDecimal + token0PriceUSD_not: BigDecimal + token0PriceUSD_gt: BigDecimal + token0PriceUSD_lt: BigDecimal + token0PriceUSD_gte: BigDecimal + token0PriceUSD_lte: BigDecimal + token0PriceUSD_in: [BigDecimal!] + token0PriceUSD_not_in: [BigDecimal!] + token1PriceUSD: BigDecimal + token1PriceUSD_not: BigDecimal + token1PriceUSD_gt: BigDecimal + token1PriceUSD_lt: BigDecimal + token1PriceUSD_gte: BigDecimal + token1PriceUSD_lte: BigDecimal + token1PriceUSD_in: [BigDecimal!] + token1PriceUSD_not_in: [BigDecimal!] + reserve0: BigInt + reserve0_not: BigInt + reserve0_gt: BigInt + reserve0_lt: BigInt + reserve0_gte: BigInt + reserve0_lte: BigInt + reserve0_in: [BigInt!] + reserve0_not_in: [BigInt!] + reserve1: BigInt + reserve1_not: BigInt + reserve1_gt: BigInt + reserve1_lt: BigInt + reserve1_gte: BigInt + reserve1_lte: BigInt + reserve1_in: [BigInt!] + reserve1_not_in: [BigInt!] + reserveUSD: BigDecimal + reserveUSD_not: BigDecimal + reserveUSD_gt: BigDecimal + reserveUSD_lt: BigDecimal + reserveUSD_gte: BigDecimal + reserveUSD_lte: BigDecimal + reserveUSD_in: [BigDecimal!] + reserveUSD_not_in: [BigDecimal!] + liquidityTokenTotalSupply: BigInt + liquidityTokenTotalSupply_not: BigInt + liquidityTokenTotalSupply_gt: BigInt + liquidityTokenTotalSupply_lt: BigInt + liquidityTokenTotalSupply_gte: BigInt + liquidityTokenTotalSupply_lte: BigInt + liquidityTokenTotalSupply_in: [BigInt!] + liquidityTokenTotalSupply_not_in: [BigInt!] + liquidityTokenBalance: BigInt + liquidityTokenBalance_not: BigInt + liquidityTokenBalance_gt: BigInt + liquidityTokenBalance_lt: BigInt + liquidityTokenBalance_gte: BigInt + liquidityTokenBalance_lte: BigInt + liquidityTokenBalance_in: [BigInt!] + liquidityTokenBalance_not_in: [BigInt!] + _change_block: BlockChangedFilter + and: [LiquidityPositionSnapshot_filter] + or: [LiquidityPositionSnapshot_filter] +} + +enum PairHourSnapshot_orderBy { + id + pair + pair__id + pair__type + pair__swapFee + pair__twapEnabled + pair__name + pair__source + pair__createdAtBlock + pair__createdAtTimestamp + pair__reserve0 + pair__reserve1 + pair__liquidity + pair__liquidityUSD + pair__liquidityNative + pair__trackedLiquidityNative + pair__token0Price + pair__token1Price + pair__volumeNative + pair__volumeUSD + pair__volumeToken0 + pair__volumeToken1 + pair__feesNative + pair__feesUSD + pair__apr + pair__aprUpdatedAtTimestamp + pair__txCount + date + cumulativeVolumeUSD + volumeUSD + volumeNative + volumeToken0 + volumeToken1 + liquidity + liquidityNative + liquidityUSD + feesNative + feesUSD + apr + transactionCount +} + +input PairHourSnapshot_filter { + id: ID + id_not: ID + id_gt: ID + id_lt: ID + id_gte: ID + id_lte: ID + id_in: [ID!] + id_not_in: [ID!] + pair: String + pair_not: String + pair_gt: String + pair_lt: String + pair_gte: String + pair_lte: String + pair_in: [String!] + pair_not_in: [String!] + pair_starts_with: String + pair_starts_with_nocase: String + pair_not_starts_with: String + pair_not_starts_with_nocase: String + pair_ends_with: String + pair_ends_with_nocase: String + pair_not_ends_with: String + pair_not_ends_with_nocase: String + pair_contains: String + pair_not_contains: String + pair_contains_nocase: String + pair_not_contains_nocase: String + pair_: Pair_filter + date: Int + date_not: Int + date_gt: Int + date_lt: Int + date_gte: Int + date_lte: Int + date_in: [Int!] + date_not_in: [Int!] + cumulativeVolumeUSD: BigDecimal + cumulativeVolumeUSD_not: BigDecimal + cumulativeVolumeUSD_gt: BigDecimal + cumulativeVolumeUSD_lt: BigDecimal + cumulativeVolumeUSD_gte: BigDecimal + cumulativeVolumeUSD_lte: BigDecimal + cumulativeVolumeUSD_in: [BigDecimal!] + cumulativeVolumeUSD_not_in: [BigDecimal!] + volumeUSD: BigDecimal + volumeUSD_not: BigDecimal + volumeUSD_gt: BigDecimal + volumeUSD_lt: BigDecimal + volumeUSD_gte: BigDecimal + volumeUSD_lte: BigDecimal + volumeUSD_in: [BigDecimal!] + volumeUSD_not_in: [BigDecimal!] + volumeNative: BigDecimal + volumeNative_not: BigDecimal + volumeNative_gt: BigDecimal + volumeNative_lt: BigDecimal + volumeNative_gte: BigDecimal + volumeNative_lte: BigDecimal + volumeNative_in: [BigDecimal!] + volumeNative_not_in: [BigDecimal!] + volumeToken0: BigDecimal + volumeToken0_not: BigDecimal + volumeToken0_gt: BigDecimal + volumeToken0_lt: BigDecimal + volumeToken0_gte: BigDecimal + volumeToken0_lte: BigDecimal + volumeToken0_in: [BigDecimal!] + volumeToken0_not_in: [BigDecimal!] + volumeToken1: BigDecimal + volumeToken1_not: BigDecimal + volumeToken1_gt: BigDecimal + volumeToken1_lt: BigDecimal + volumeToken1_gte: BigDecimal + volumeToken1_lte: BigDecimal + volumeToken1_in: [BigDecimal!] + volumeToken1_not_in: [BigDecimal!] + liquidity: BigDecimal + liquidity_not: BigDecimal + liquidity_gt: BigDecimal + liquidity_lt: BigDecimal + liquidity_gte: BigDecimal + liquidity_lte: BigDecimal + liquidity_in: [BigDecimal!] + liquidity_not_in: [BigDecimal!] + liquidityNative: BigDecimal + liquidityNative_not: BigDecimal + liquidityNative_gt: BigDecimal + liquidityNative_lt: BigDecimal + liquidityNative_gte: BigDecimal + liquidityNative_lte: BigDecimal + liquidityNative_in: [BigDecimal!] + liquidityNative_not_in: [BigDecimal!] + liquidityUSD: BigDecimal + liquidityUSD_not: BigDecimal + liquidityUSD_gt: BigDecimal + liquidityUSD_lt: BigDecimal + liquidityUSD_gte: BigDecimal + liquidityUSD_lte: BigDecimal + liquidityUSD_in: [BigDecimal!] + liquidityUSD_not_in: [BigDecimal!] + feesNative: BigDecimal + feesNative_not: BigDecimal + feesNative_gt: BigDecimal + feesNative_lt: BigDecimal + feesNative_gte: BigDecimal + feesNative_lte: BigDecimal + feesNative_in: [BigDecimal!] + feesNative_not_in: [BigDecimal!] + feesUSD: BigDecimal + feesUSD_not: BigDecimal + feesUSD_gt: BigDecimal + feesUSD_lt: BigDecimal + feesUSD_gte: BigDecimal + feesUSD_lte: BigDecimal + feesUSD_in: [BigDecimal!] + feesUSD_not_in: [BigDecimal!] + apr: BigDecimal + apr_not: BigDecimal + apr_gt: BigDecimal + apr_lt: BigDecimal + apr_gte: BigDecimal + apr_lte: BigDecimal + apr_in: [BigDecimal!] + apr_not_in: [BigDecimal!] + transactionCount: BigInt + transactionCount_not: BigInt + transactionCount_gt: BigInt + transactionCount_lt: BigInt + transactionCount_gte: BigInt + transactionCount_lte: BigInt + transactionCount_in: [BigInt!] + transactionCount_not_in: [BigInt!] + _change_block: BlockChangedFilter + and: [PairHourSnapshot_filter] + or: [PairHourSnapshot_filter] +} + +enum PairDaySnapshot_orderBy { + id + pair + pair__id + pair__type + pair__swapFee + pair__twapEnabled + pair__name + pair__source + pair__createdAtBlock + pair__createdAtTimestamp + pair__reserve0 + pair__reserve1 + pair__liquidity + pair__liquidityUSD + pair__liquidityNative + pair__trackedLiquidityNative + pair__token0Price + pair__token1Price + pair__volumeNative + pair__volumeUSD + pair__volumeToken0 + pair__volumeToken1 + pair__feesNative + pair__feesUSD + pair__apr + pair__aprUpdatedAtTimestamp + pair__txCount + date + cumulativeVolumeUSD + volumeUSD + volumeNative + volumeToken0 + volumeToken1 + liquidity + liquidityNative + liquidityUSD + feesNative + feesUSD + apr + transactionCount +} + +input PairDaySnapshot_filter { + id: ID + id_not: ID + id_gt: ID + id_lt: ID + id_gte: ID + id_lte: ID + id_in: [ID!] + id_not_in: [ID!] + pair: String + pair_not: String + pair_gt: String + pair_lt: String + pair_gte: String + pair_lte: String + pair_in: [String!] + pair_not_in: [String!] + pair_starts_with: String + pair_starts_with_nocase: String + pair_not_starts_with: String + pair_not_starts_with_nocase: String + pair_ends_with: String + pair_ends_with_nocase: String + pair_not_ends_with: String + pair_not_ends_with_nocase: String + pair_contains: String + pair_not_contains: String + pair_contains_nocase: String + pair_not_contains_nocase: String + pair_: Pair_filter + date: Int + date_not: Int + date_gt: Int + date_lt: Int + date_gte: Int + date_lte: Int + date_in: [Int!] + date_not_in: [Int!] + cumulativeVolumeUSD: BigDecimal + cumulativeVolumeUSD_not: BigDecimal + cumulativeVolumeUSD_gt: BigDecimal + cumulativeVolumeUSD_lt: BigDecimal + cumulativeVolumeUSD_gte: BigDecimal + cumulativeVolumeUSD_lte: BigDecimal + cumulativeVolumeUSD_in: [BigDecimal!] + cumulativeVolumeUSD_not_in: [BigDecimal!] + volumeUSD: BigDecimal + volumeUSD_not: BigDecimal + volumeUSD_gt: BigDecimal + volumeUSD_lt: BigDecimal + volumeUSD_gte: BigDecimal + volumeUSD_lte: BigDecimal + volumeUSD_in: [BigDecimal!] + volumeUSD_not_in: [BigDecimal!] + volumeNative: BigDecimal + volumeNative_not: BigDecimal + volumeNative_gt: BigDecimal + volumeNative_lt: BigDecimal + volumeNative_gte: BigDecimal + volumeNative_lte: BigDecimal + volumeNative_in: [BigDecimal!] + volumeNative_not_in: [BigDecimal!] + volumeToken0: BigDecimal + volumeToken0_not: BigDecimal + volumeToken0_gt: BigDecimal + volumeToken0_lt: BigDecimal + volumeToken0_gte: BigDecimal + volumeToken0_lte: BigDecimal + volumeToken0_in: [BigDecimal!] + volumeToken0_not_in: [BigDecimal!] + volumeToken1: BigDecimal + volumeToken1_not: BigDecimal + volumeToken1_gt: BigDecimal + volumeToken1_lt: BigDecimal + volumeToken1_gte: BigDecimal + volumeToken1_lte: BigDecimal + volumeToken1_in: [BigDecimal!] + volumeToken1_not_in: [BigDecimal!] + liquidity: BigDecimal + liquidity_not: BigDecimal + liquidity_gt: BigDecimal + liquidity_lt: BigDecimal + liquidity_gte: BigDecimal + liquidity_lte: BigDecimal + liquidity_in: [BigDecimal!] + liquidity_not_in: [BigDecimal!] + liquidityNative: BigDecimal + liquidityNative_not: BigDecimal + liquidityNative_gt: BigDecimal + liquidityNative_lt: BigDecimal + liquidityNative_gte: BigDecimal + liquidityNative_lte: BigDecimal + liquidityNative_in: [BigDecimal!] + liquidityNative_not_in: [BigDecimal!] + liquidityUSD: BigDecimal + liquidityUSD_not: BigDecimal + liquidityUSD_gt: BigDecimal + liquidityUSD_lt: BigDecimal + liquidityUSD_gte: BigDecimal + liquidityUSD_lte: BigDecimal + liquidityUSD_in: [BigDecimal!] + liquidityUSD_not_in: [BigDecimal!] + feesNative: BigDecimal + feesNative_not: BigDecimal + feesNative_gt: BigDecimal + feesNative_lt: BigDecimal + feesNative_gte: BigDecimal + feesNative_lte: BigDecimal + feesNative_in: [BigDecimal!] + feesNative_not_in: [BigDecimal!] + feesUSD: BigDecimal + feesUSD_not: BigDecimal + feesUSD_gt: BigDecimal + feesUSD_lt: BigDecimal + feesUSD_gte: BigDecimal + feesUSD_lte: BigDecimal + feesUSD_in: [BigDecimal!] + feesUSD_not_in: [BigDecimal!] + apr: BigDecimal + apr_not: BigDecimal + apr_gt: BigDecimal + apr_lt: BigDecimal + apr_gte: BigDecimal + apr_lte: BigDecimal + apr_in: [BigDecimal!] + apr_not_in: [BigDecimal!] + transactionCount: BigInt + transactionCount_not: BigInt + transactionCount_gt: BigInt + transactionCount_lt: BigInt + transactionCount_gte: BigInt + transactionCount_lte: BigInt + transactionCount_in: [BigInt!] + transactionCount_not_in: [BigInt!] + _change_block: BlockChangedFilter + and: [PairDaySnapshot_filter] + or: [PairDaySnapshot_filter] +} + +enum TokenHourSnapshot_orderBy { + id + date + token + token__id + token__symbol + token__symbolSuccess + token__name + token__nameSuccess + token__decimals + token__decimalsSuccess + token__liquidity + token__liquidityNative + token__liquidityUSD + token__volume + token__volumeNative + token__volumeUSD + token__feesNative + token__feesUSD + token__txCount + token__pairCount + token__whitelistedPairCount + liquidity + liquidityNative + liquidityUSD + volume + volumeNative + volumeUSD + priceNative + priceUSD + feesNative + feesUSD + transactionCount +} + +input TokenHourSnapshot_filter { + id: ID + id_not: ID + id_gt: ID + id_lt: ID + id_gte: ID + id_lte: ID + id_in: [ID!] + id_not_in: [ID!] + date: Int + date_not: Int + date_gt: Int + date_lt: Int + date_gte: Int + date_lte: Int + date_in: [Int!] + date_not_in: [Int!] + token: String + token_not: String + token_gt: String + token_lt: String + token_gte: String + token_lte: String + token_in: [String!] + token_not_in: [String!] + token_starts_with: String + token_starts_with_nocase: String + token_not_starts_with: String + token_not_starts_with_nocase: String + token_ends_with: String + token_ends_with_nocase: String + token_not_ends_with: String + token_not_ends_with_nocase: String + token_contains: String + token_not_contains: String + token_contains_nocase: String + token_not_contains_nocase: String + token_: Token_filter + liquidity: BigDecimal + liquidity_not: BigDecimal + liquidity_gt: BigDecimal + liquidity_lt: BigDecimal + liquidity_gte: BigDecimal + liquidity_lte: BigDecimal + liquidity_in: [BigDecimal!] + liquidity_not_in: [BigDecimal!] + liquidityNative: BigDecimal + liquidityNative_not: BigDecimal + liquidityNative_gt: BigDecimal + liquidityNative_lt: BigDecimal + liquidityNative_gte: BigDecimal + liquidityNative_lte: BigDecimal + liquidityNative_in: [BigDecimal!] + liquidityNative_not_in: [BigDecimal!] + liquidityUSD: BigDecimal + liquidityUSD_not: BigDecimal + liquidityUSD_gt: BigDecimal + liquidityUSD_lt: BigDecimal + liquidityUSD_gte: BigDecimal + liquidityUSD_lte: BigDecimal + liquidityUSD_in: [BigDecimal!] + liquidityUSD_not_in: [BigDecimal!] + volume: BigDecimal + volume_not: BigDecimal + volume_gt: BigDecimal + volume_lt: BigDecimal + volume_gte: BigDecimal + volume_lte: BigDecimal + volume_in: [BigDecimal!] + volume_not_in: [BigDecimal!] + volumeNative: BigDecimal + volumeNative_not: BigDecimal + volumeNative_gt: BigDecimal + volumeNative_lt: BigDecimal + volumeNative_gte: BigDecimal + volumeNative_lte: BigDecimal + volumeNative_in: [BigDecimal!] + volumeNative_not_in: [BigDecimal!] + volumeUSD: BigDecimal + volumeUSD_not: BigDecimal + volumeUSD_gt: BigDecimal + volumeUSD_lt: BigDecimal + volumeUSD_gte: BigDecimal + volumeUSD_lte: BigDecimal + volumeUSD_in: [BigDecimal!] + volumeUSD_not_in: [BigDecimal!] + priceNative: BigDecimal + priceNative_not: BigDecimal + priceNative_gt: BigDecimal + priceNative_lt: BigDecimal + priceNative_gte: BigDecimal + priceNative_lte: BigDecimal + priceNative_in: [BigDecimal!] + priceNative_not_in: [BigDecimal!] + priceUSD: BigDecimal + priceUSD_not: BigDecimal + priceUSD_gt: BigDecimal + priceUSD_lt: BigDecimal + priceUSD_gte: BigDecimal + priceUSD_lte: BigDecimal + priceUSD_in: [BigDecimal!] + priceUSD_not_in: [BigDecimal!] + feesNative: BigDecimal + feesNative_not: BigDecimal + feesNative_gt: BigDecimal + feesNative_lt: BigDecimal + feesNative_gte: BigDecimal + feesNative_lte: BigDecimal + feesNative_in: [BigDecimal!] + feesNative_not_in: [BigDecimal!] + feesUSD: BigDecimal + feesUSD_not: BigDecimal + feesUSD_gt: BigDecimal + feesUSD_lt: BigDecimal + feesUSD_gte: BigDecimal + feesUSD_lte: BigDecimal + feesUSD_in: [BigDecimal!] + feesUSD_not_in: [BigDecimal!] + transactionCount: BigInt + transactionCount_not: BigInt + transactionCount_gt: BigInt + transactionCount_lt: BigInt + transactionCount_gte: BigInt + transactionCount_lte: BigInt + transactionCount_in: [BigInt!] + transactionCount_not_in: [BigInt!] + _change_block: BlockChangedFilter + and: [TokenHourSnapshot_filter] + or: [TokenHourSnapshot_filter] +} + +enum TokenDaySnapshot_orderBy { + id + date + token + token__id + token__symbol + token__symbolSuccess + token__name + token__nameSuccess + token__decimals + token__decimalsSuccess + token__liquidity + token__liquidityNative + token__liquidityUSD + token__volume + token__volumeNative + token__volumeUSD + token__feesNative + token__feesUSD + token__txCount + token__pairCount + token__whitelistedPairCount + liquidity + liquidityNative + liquidityUSD + volume + volumeNative + volumeUSD + priceNative + priceUSD + feesNative + feesUSD + transactionCount +} + +input TokenDaySnapshot_filter { + id: ID + id_not: ID + id_gt: ID + id_lt: ID + id_gte: ID + id_lte: ID + id_in: [ID!] + id_not_in: [ID!] + date: Int + date_not: Int + date_gt: Int + date_lt: Int + date_gte: Int + date_lte: Int + date_in: [Int!] + date_not_in: [Int!] + token: String + token_not: String + token_gt: String + token_lt: String + token_gte: String + token_lte: String + token_in: [String!] + token_not_in: [String!] + token_starts_with: String + token_starts_with_nocase: String + token_not_starts_with: String + token_not_starts_with_nocase: String + token_ends_with: String + token_ends_with_nocase: String + token_not_ends_with: String + token_not_ends_with_nocase: String + token_contains: String + token_not_contains: String + token_contains_nocase: String + token_not_contains_nocase: String + token_: Token_filter + liquidity: BigDecimal + liquidity_not: BigDecimal + liquidity_gt: BigDecimal + liquidity_lt: BigDecimal + liquidity_gte: BigDecimal + liquidity_lte: BigDecimal + liquidity_in: [BigDecimal!] + liquidity_not_in: [BigDecimal!] + liquidityNative: BigDecimal + liquidityNative_not: BigDecimal + liquidityNative_gt: BigDecimal + liquidityNative_lt: BigDecimal + liquidityNative_gte: BigDecimal + liquidityNative_lte: BigDecimal + liquidityNative_in: [BigDecimal!] + liquidityNative_not_in: [BigDecimal!] + liquidityUSD: BigDecimal + liquidityUSD_not: BigDecimal + liquidityUSD_gt: BigDecimal + liquidityUSD_lt: BigDecimal + liquidityUSD_gte: BigDecimal + liquidityUSD_lte: BigDecimal + liquidityUSD_in: [BigDecimal!] + liquidityUSD_not_in: [BigDecimal!] + volume: BigDecimal + volume_not: BigDecimal + volume_gt: BigDecimal + volume_lt: BigDecimal + volume_gte: BigDecimal + volume_lte: BigDecimal + volume_in: [BigDecimal!] + volume_not_in: [BigDecimal!] + volumeNative: BigDecimal + volumeNative_not: BigDecimal + volumeNative_gt: BigDecimal + volumeNative_lt: BigDecimal + volumeNative_gte: BigDecimal + volumeNative_lte: BigDecimal + volumeNative_in: [BigDecimal!] + volumeNative_not_in: [BigDecimal!] + volumeUSD: BigDecimal + volumeUSD_not: BigDecimal + volumeUSD_gt: BigDecimal + volumeUSD_lt: BigDecimal + volumeUSD_gte: BigDecimal + volumeUSD_lte: BigDecimal + volumeUSD_in: [BigDecimal!] + volumeUSD_not_in: [BigDecimal!] + priceNative: BigDecimal + priceNative_not: BigDecimal + priceNative_gt: BigDecimal + priceNative_lt: BigDecimal + priceNative_gte: BigDecimal + priceNative_lte: BigDecimal + priceNative_in: [BigDecimal!] + priceNative_not_in: [BigDecimal!] + priceUSD: BigDecimal + priceUSD_not: BigDecimal + priceUSD_gt: BigDecimal + priceUSD_lt: BigDecimal + priceUSD_gte: BigDecimal + priceUSD_lte: BigDecimal + priceUSD_in: [BigDecimal!] + priceUSD_not_in: [BigDecimal!] + feesNative: BigDecimal + feesNative_not: BigDecimal + feesNative_gt: BigDecimal + feesNative_lt: BigDecimal + feesNative_gte: BigDecimal + feesNative_lte: BigDecimal + feesNative_in: [BigDecimal!] + feesNative_not_in: [BigDecimal!] + feesUSD: BigDecimal + feesUSD_not: BigDecimal + feesUSD_gt: BigDecimal + feesUSD_lt: BigDecimal + feesUSD_gte: BigDecimal + feesUSD_lte: BigDecimal + feesUSD_in: [BigDecimal!] + feesUSD_not_in: [BigDecimal!] + transactionCount: BigInt + transactionCount_not: BigInt + transactionCount_gt: BigInt + transactionCount_lt: BigInt + transactionCount_gte: BigInt + transactionCount_lte: BigInt + transactionCount_in: [BigInt!] + transactionCount_not_in: [BigInt!] + _change_block: BlockChangedFilter + and: [TokenDaySnapshot_filter] + or: [TokenDaySnapshot_filter] +} + +enum FactoryHourSnapshot_orderBy { + id + factory + factory__id + factory__type + factory__volumeUSD + factory__volumeNative + factory__liquidityUSD + factory__liquidityNative + factory__feesUSD + factory__feesNative + factory__pairCount + factory__transactionCount + factory__tokenCount + factory__userCount + date + volumeUSD + volumeNative + liquidityNative + liquidityUSD + feesNative + feesUSD + transactionCount +} + +input FactoryHourSnapshot_filter { + id: ID + id_not: ID + id_gt: ID + id_lt: ID + id_gte: ID + id_lte: ID + id_in: [ID!] + id_not_in: [ID!] + factory: String + factory_not: String + factory_gt: String + factory_lt: String + factory_gte: String + factory_lte: String + factory_in: [String!] + factory_not_in: [String!] + factory_starts_with: String + factory_starts_with_nocase: String + factory_not_starts_with: String + factory_not_starts_with_nocase: String + factory_ends_with: String + factory_ends_with_nocase: String + factory_not_ends_with: String + factory_not_ends_with_nocase: String + factory_contains: String + factory_not_contains: String + factory_contains_nocase: String + factory_not_contains_nocase: String + factory_: Factory_filter + date: Int + date_not: Int + date_gt: Int + date_lt: Int + date_gte: Int + date_lte: Int + date_in: [Int!] + date_not_in: [Int!] + volumeUSD: BigDecimal + volumeUSD_not: BigDecimal + volumeUSD_gt: BigDecimal + volumeUSD_lt: BigDecimal + volumeUSD_gte: BigDecimal + volumeUSD_lte: BigDecimal + volumeUSD_in: [BigDecimal!] + volumeUSD_not_in: [BigDecimal!] + volumeNative: BigDecimal + volumeNative_not: BigDecimal + volumeNative_gt: BigDecimal + volumeNative_lt: BigDecimal + volumeNative_gte: BigDecimal + volumeNative_lte: BigDecimal + volumeNative_in: [BigDecimal!] + volumeNative_not_in: [BigDecimal!] + liquidityNative: BigDecimal + liquidityNative_not: BigDecimal + liquidityNative_gt: BigDecimal + liquidityNative_lt: BigDecimal + liquidityNative_gte: BigDecimal + liquidityNative_lte: BigDecimal + liquidityNative_in: [BigDecimal!] + liquidityNative_not_in: [BigDecimal!] + liquidityUSD: BigDecimal + liquidityUSD_not: BigDecimal + liquidityUSD_gt: BigDecimal + liquidityUSD_lt: BigDecimal + liquidityUSD_gte: BigDecimal + liquidityUSD_lte: BigDecimal + liquidityUSD_in: [BigDecimal!] + liquidityUSD_not_in: [BigDecimal!] + feesNative: BigDecimal + feesNative_not: BigDecimal + feesNative_gt: BigDecimal + feesNative_lt: BigDecimal + feesNative_gte: BigDecimal + feesNative_lte: BigDecimal + feesNative_in: [BigDecimal!] + feesNative_not_in: [BigDecimal!] + feesUSD: BigDecimal + feesUSD_not: BigDecimal + feesUSD_gt: BigDecimal + feesUSD_lt: BigDecimal + feesUSD_gte: BigDecimal + feesUSD_lte: BigDecimal + feesUSD_in: [BigDecimal!] + feesUSD_not_in: [BigDecimal!] + transactionCount: BigInt + transactionCount_not: BigInt + transactionCount_gt: BigInt + transactionCount_lt: BigInt + transactionCount_gte: BigInt + transactionCount_lte: BigInt + transactionCount_in: [BigInt!] + transactionCount_not_in: [BigInt!] + _change_block: BlockChangedFilter + and: [FactoryHourSnapshot_filter] + or: [FactoryHourSnapshot_filter] +} + +enum FactoryDaySnapshot_orderBy { + id + factory + factory__id + factory__type + factory__volumeUSD + factory__volumeNative + factory__liquidityUSD + factory__liquidityNative + factory__feesUSD + factory__feesNative + factory__pairCount + factory__transactionCount + factory__tokenCount + factory__userCount + date + volumeUSD + volumeNative + liquidityNative + liquidityUSD + feesNative + feesUSD + transactionCount +} + +input FactoryDaySnapshot_filter { + id: ID + id_not: ID + id_gt: ID + id_lt: ID + id_gte: ID + id_lte: ID + id_in: [ID!] + id_not_in: [ID!] + factory: String + factory_not: String + factory_gt: String + factory_lt: String + factory_gte: String + factory_lte: String + factory_in: [String!] + factory_not_in: [String!] + factory_starts_with: String + factory_starts_with_nocase: String + factory_not_starts_with: String + factory_not_starts_with_nocase: String + factory_ends_with: String + factory_ends_with_nocase: String + factory_not_ends_with: String + factory_not_ends_with_nocase: String + factory_contains: String + factory_not_contains: String + factory_contains_nocase: String + factory_not_contains_nocase: String + factory_: Factory_filter + date: Int + date_not: Int + date_gt: Int + date_lt: Int + date_gte: Int + date_lte: Int + date_in: [Int!] + date_not_in: [Int!] + volumeUSD: BigDecimal + volumeUSD_not: BigDecimal + volumeUSD_gt: BigDecimal + volumeUSD_lt: BigDecimal + volumeUSD_gte: BigDecimal + volumeUSD_lte: BigDecimal + volumeUSD_in: [BigDecimal!] + volumeUSD_not_in: [BigDecimal!] + volumeNative: BigDecimal + volumeNative_not: BigDecimal + volumeNative_gt: BigDecimal + volumeNative_lt: BigDecimal + volumeNative_gte: BigDecimal + volumeNative_lte: BigDecimal + volumeNative_in: [BigDecimal!] + volumeNative_not_in: [BigDecimal!] + liquidityNative: BigDecimal + liquidityNative_not: BigDecimal + liquidityNative_gt: BigDecimal + liquidityNative_lt: BigDecimal + liquidityNative_gte: BigDecimal + liquidityNative_lte: BigDecimal + liquidityNative_in: [BigDecimal!] + liquidityNative_not_in: [BigDecimal!] + liquidityUSD: BigDecimal + liquidityUSD_not: BigDecimal + liquidityUSD_gt: BigDecimal + liquidityUSD_lt: BigDecimal + liquidityUSD_gte: BigDecimal + liquidityUSD_lte: BigDecimal + liquidityUSD_in: [BigDecimal!] + liquidityUSD_not_in: [BigDecimal!] + feesNative: BigDecimal + feesNative_not: BigDecimal + feesNative_gt: BigDecimal + feesNative_lt: BigDecimal + feesNative_gte: BigDecimal + feesNative_lte: BigDecimal + feesNative_in: [BigDecimal!] + feesNative_not_in: [BigDecimal!] + feesUSD: BigDecimal + feesUSD_not: BigDecimal + feesUSD_gt: BigDecimal + feesUSD_lt: BigDecimal + feesUSD_gte: BigDecimal + feesUSD_lte: BigDecimal + feesUSD_in: [BigDecimal!] + feesUSD_not_in: [BigDecimal!] + transactionCount: BigInt + transactionCount_not: BigInt + transactionCount_gt: BigInt + transactionCount_lt: BigInt + transactionCount_gte: BigInt + transactionCount_lte: BigInt + transactionCount_in: [BigInt!] + transactionCount_not_in: [BigInt!] + _change_block: BlockChangedFilter + and: [FactoryDaySnapshot_filter] + or: [FactoryDaySnapshot_filter] +} + +type _MetaBlock_ { + hash: Bytes + number: Int! + timestamp: Int +} + +type _Meta_ { + block: _MetaBlock_! + deployment: String! + hasIndexingErrors: Boolean! +} + +type ResultState { + block: _Block_! + contractAddress: String! + cid: String! + kind: String! + data: String! +} + +type SyncStatus { + latestIndexedBlockHash: String! + latestIndexedBlockNumber: Int! + latestCanonicalBlockHash: String! + latestCanonicalBlockNumber: Int! + initialIndexedBlockHash: String! + initialIndexedBlockNumber: Int! + latestProcessedBlockHash: String! + latestProcessedBlockNumber: Int! +} + +type Query { + events(blockHash: String!, contractAddress: String!, name: String): [ResultEvent!] + eventsInRange(fromBlockNumber: Int!, toBlockNumber: Int!): [ResultEvent!] + factory(id: ID!, block: Block_height): Factory + factories(block: Block_height, where: Factory_filter, orderBy: Factory_orderBy, orderDirection: OrderDirection, first: Int = 100, skip: Int = 0): [Factory!]! + bundle(id: ID!, block: Block_height): Bundle + bundles(block: Block_height, where: Bundle_filter, orderBy: Bundle_orderBy, orderDirection: OrderDirection, first: Int = 100, skip: Int = 0): [Bundle!]! + token(id: ID!, block: Block_height): Token + tokens(block: Block_height, where: Token_filter, orderBy: Token_orderBy, orderDirection: OrderDirection, first: Int = 100, skip: Int = 0): [Token!]! + tokenPrice(id: ID!, block: Block_height): TokenPrice + tokenPrices(block: Block_height, where: TokenPrice_filter, orderBy: TokenPrice_orderBy, orderDirection: OrderDirection, first: Int = 100, skip: Int = 0): [TokenPrice!]! + _TokenPair(id: ID!, block: Block_height): _TokenPair + _TokenPairs(block: Block_height, where: _TokenPair_filter, orderBy: _TokenPair_orderBy, orderDirection: OrderDirection, first: Int = 100, skip: Int = 0): [_TokenPair!]! + _WhitelistedTokenPair(id: ID!, block: Block_height): _WhitelistedTokenPair + _WhitelistedTokenPairs(block: Block_height, where: _WhitelistedTokenPair_filter, orderBy: _WhitelistedTokenPair_orderBy, orderDirection: OrderDirection, first: Int = 100, skip: Int = 0): [_WhitelistedTokenPair!]! + pair(id: ID!, block: Block_height): Pair + pairs(block: Block_height, where: Pair_filter, orderBy: Pair_orderBy, orderDirection: OrderDirection, first: Int = 100, skip: Int = 0): [Pair!]! + user(id: ID!, block: Block_height): User + users(block: Block_height, where: User_filter, orderBy: User_orderBy, orderDirection: OrderDirection, first: Int = 100, skip: Int = 0): [User!]! + liquidityPosition(id: ID!, block: Block_height): LiquidityPosition + liquidityPositions(block: Block_height, where: LiquidityPosition_filter, orderBy: LiquidityPosition_orderBy, orderDirection: OrderDirection, first: Int = 100, skip: Int = 0): [LiquidityPosition!]! + mint(id: ID!, block: Block_height): Mint + mints(block: Block_height, where: Mint_filter, orderBy: Mint_orderBy, orderDirection: OrderDirection, first: Int = 100, skip: Int = 0): [Mint!]! + burn(id: ID!, block: Block_height): Burn + burns(block: Block_height, where: Burn_filter, orderBy: Burn_orderBy, orderDirection: OrderDirection, first: Int = 100, skip: Int = 0): [Burn!]! + swap(id: ID!, block: Block_height): Swap + swaps(block: Block_height, where: Swap_filter, orderBy: Swap_orderBy, orderDirection: OrderDirection, first: Int = 100, skip: Int = 0): [Swap!]! + transaction(id: ID!, block: Block_height): Transaction + transactions(block: Block_height, where: Transaction_filter, orderBy: Transaction_orderBy, orderDirection: OrderDirection, first: Int = 100, skip: Int = 0): [Transaction!]! + liquidityPositionSnapshot(id: ID!, block: Block_height): LiquidityPositionSnapshot + liquidityPositionSnapshots(block: Block_height, where: LiquidityPositionSnapshot_filter, orderBy: LiquidityPositionSnapshot_orderBy, orderDirection: OrderDirection, first: Int = 100, skip: Int = 0): [LiquidityPositionSnapshot!]! + pairHourSnapshot(id: ID!, block: Block_height): PairHourSnapshot + pairHourSnapshots(block: Block_height, where: PairHourSnapshot_filter, orderBy: PairHourSnapshot_orderBy, orderDirection: OrderDirection, first: Int = 100, skip: Int = 0): [PairHourSnapshot!]! + pairDaySnapshot(id: ID!, block: Block_height): PairDaySnapshot + pairDaySnapshots(block: Block_height, where: PairDaySnapshot_filter, orderBy: PairDaySnapshot_orderBy, orderDirection: OrderDirection, first: Int = 100, skip: Int = 0): [PairDaySnapshot!]! + tokenHourSnapshot(id: ID!, block: Block_height): TokenHourSnapshot + tokenHourSnapshots(block: Block_height, where: TokenHourSnapshot_filter, orderBy: TokenHourSnapshot_orderBy, orderDirection: OrderDirection, first: Int = 100, skip: Int = 0): [TokenHourSnapshot!]! + tokenDaySnapshot(id: ID!, block: Block_height): TokenDaySnapshot + tokenDaySnapshots(block: Block_height, where: TokenDaySnapshot_filter, orderBy: TokenDaySnapshot_orderBy, orderDirection: OrderDirection, first: Int = 100, skip: Int = 0): [TokenDaySnapshot!]! + factoryHourSnapshot(id: ID!, block: Block_height): FactoryHourSnapshot + factoryHourSnapshots(block: Block_height, where: FactoryHourSnapshot_filter, orderBy: FactoryHourSnapshot_orderBy, orderDirection: OrderDirection, first: Int = 100, skip: Int = 0): [FactoryHourSnapshot!]! + factoryDaySnapshot(id: ID!, block: Block_height): FactoryDaySnapshot + factoryDaySnapshots(block: Block_height, where: FactoryDaySnapshot_filter, orderBy: FactoryDaySnapshot_orderBy, orderDirection: OrderDirection, first: Int = 100, skip: Int = 0): [FactoryDaySnapshot!]! + _meta(block: Block_height): _Meta_ + getStateByCID(cid: String!): ResultState + getState(blockHash: String!, contractAddress: String!, kind: String): ResultState + getSyncStatus: SyncStatus +} + +type Factory { + """ Contract address """ + id: ID! + + """ Factory type """ + type: PairType! + + """ Volume USD """ + volumeUSD: BigDecimal! + + """ Volume Native """ + volumeNative: BigDecimal! + + """ Liquidity USD """ + liquidityUSD: BigDecimal! + + """ Liquidity NATIVE """ + liquidityNative: BigDecimal! + + """ Fees USD """ + feesUSD: BigDecimal! + + """ Fees NATIVE """ + feesNative: BigDecimal! + + """ Pair count """ + pairCount: BigInt! + + """ Transaction count """ + transactionCount: BigInt! + + """ Token count """ + tokenCount: BigInt! + + """ User count """ + userCount: BigInt! +} + +""" Bundle - should only ever be one created""" +type Bundle { + """ hardcoded to '1'""" + id: ID! + + """ Price of native """ + nativePrice: BigDecimal! +} + +type Token { + """ Token address """ + id: ID! + + """ Token Price """ + price: TokenPrice! + + """ Symbol of the token """ + symbol: String! + + """ if symbol was successfully retrieved """ + symbolSuccess: Boolean! + + """ Name of the token """ + name: String! + + """ if name was successfully retrieved """ + nameSuccess: Boolean! + + """ Decimals of the token """ + decimals: BigInt! + + """ if decimals were successfully retrieved """ + decimalsSuccess: Boolean! + + """ Liquidity """ + liquidity: BigInt! + + """ Liquidity in native """ + liquidityNative: BigDecimal! + + """ Liquidity in USD """ + liquidityUSD: BigDecimal! + + """ Volume """ + volume: BigDecimal! + + """ Volume in native """ + volumeNative: BigDecimal! + + """ Volume in USD """ + volumeUSD: BigDecimal! + + """ Fee in USD """ + feesNative: BigDecimal! + + """ Volume in USD """ + feesUSD: BigDecimal! + + """ Count of all the transactions """ + txCount: BigInt! + + """ Count of all the pairs """ + pairCount: BigInt! + + """ Count of all the whitelisted pairs """ + whitelistedPairCount: BigInt! + + """ All pairs where this token is involved in """ + pairs: [_TokenPair!]! + + """ All whitelisted pairs where this token is involved in """ + whitelistedPairs: [_WhitelistedTokenPair!]! +} + +type TokenPrice { + """ same as token entity id, address of token """ + id: ID! + + """ Token """ + token: Token! + + """ derived native, this is useful for calculating price. (derivedNative * bundle.nativePrice = USD price) + """ + derivedNative: BigDecimal! + + """ price in USD. NOTE: this will not always be up to date, it only updates when onSync event is emitted, bundle.nativePrice could have changed. + """ + lastUsdPrice: BigDecimal! + + """ Which token this price is based on """ + pricedOffToken: Token + + """ Which pair this price is based on """ + pricedOffPair: Pair +} + +type Pair { + """ Pair address (contract address) """ + id: ID! + + """ Pair type """ + type: PairType! + + """ Swap fee """ + swapFee: BigInt! + + """ TWAP - time weighted average price """ + twapEnabled: Boolean! + + """ name of the pair, this combines symbol of both tokens, e.g. WETH/SUSHI + """ + name: String! + + """ First Token """ + token0: Token! + + """ Second Token """ + token1: Token! + + """ Which source this pair comes from, in this case it will always be 'LEGACY' + """ + source: String! + + """ Which block this pair was created on """ + createdAtBlock: BigInt! + + """ When this pair was created """ + createdAtTimestamp: BigInt! + + """ Liquidity of first token """ + reserve0: BigInt! + + """ Liquidity of second token """ + reserve1: BigInt! + + """ Liquidity, Total supply of all LP in this pool """ + liquidity: BigInt! + + """ USD liquidity""" + liquidityUSD: BigDecimal! + + """ Native Liquidity """ + liquidityNative: BigDecimal! + + """ Tracked Liquidity native """ + trackedLiquidityNative: BigDecimal! + + """ Price of the first token in this pair, not to be confused with TokenPrice entity + """ + token0Price: BigDecimal! + + """ Price of the second token in this pair, not to be confused with TokenPrice entity + """ + token1Price: BigDecimal! + volumeNative: BigDecimal! + volumeUSD: BigDecimal! + volumeToken0: BigDecimal! + volumeToken1: BigDecimal! + + """ Fee in Native """ + feesNative: BigDecimal! + + """ Fee in USD """ + feesUSD: BigDecimal! + + """ APR """ + apr: BigDecimal! + + """ When APR was last updated """ + aprUpdatedAtTimestamp: BigInt! + + """ Transaction count """ + txCount: BigInt! + + """ Liquidity Positions """ + liquidityPositions: [LiquidityPosition!]! + + """ Liquidity position snapshots """ + liquidityPositionSnapshots: [LiquidityPositionSnapshot!]! + + """ Pair Hour Snapshot """ + hourSnapshots: [PairHourSnapshot!]! + + """ Pair Day Snapshot """ + daySnapshots: [PairDaySnapshot!]! +} + +type LiquidityPosition { + """pair.id:user.id""" + id: ID! + pair: Pair! + user: User! + balance: BigInt! + createdAtBlock: BigInt! + createdAtTimestamp: BigInt! +} + +type User { + id: ID! + lpSnapshotsCount: BigInt! + liquidityPositions: [LiquidityPosition!] +} + +type LiquidityPositionSnapshot { + """ {lp.id}-{timestamp} """ + id: ID! + liquidityPosition: LiquidityPosition! + + """ saved for fast historical lookups """ + timestamp: Int! + + """ saved for fast historical lookups """ + block: Int! + + """ reference to user """ + user: User! + + """ reference to pair """ + pair: Pair! + + """ snapshot of token0 price """ + token0PriceUSD: BigDecimal! + + """ snapshot of token1 price """ + token1PriceUSD: BigDecimal! + + """ snapshot of pair token0 reserves """ + reserve0: BigInt! + + """ snapshot of pair token1 reserves """ + reserve1: BigInt! + + """ snapshot of pair reserves in USD """ + reserveUSD: BigDecimal! + + """ snapshot of pool token supply """ + liquidityTokenTotalSupply: BigInt! + + """ snapshot of users pool token balance """ + liquidityTokenBalance: BigInt! +} + +type PairHourSnapshot { + """ {pairId}-hour-{timestamp} """ + id: ID! + pair: Pair! + date: Int! + + """ Used to calculate apr """ + cumulativeVolumeUSD: BigDecimal! + volumeUSD: BigDecimal! + volumeNative: BigDecimal! + volumeToken0: BigDecimal! + volumeToken1: BigDecimal! + liquidity: BigDecimal! + liquidityNative: BigDecimal! + liquidityUSD: BigDecimal! + feesNative: BigDecimal! + feesUSD: BigDecimal! + apr: BigDecimal! + transactionCount: BigInt! +} + +type PairDaySnapshot { + """ {pairId}-day-{timestamp} """ + id: ID! + pair: Pair! + date: Int! + + """ Used to calculate apr """ + cumulativeVolumeUSD: BigDecimal! + volumeUSD: BigDecimal! + volumeNative: BigDecimal! + volumeToken0: BigDecimal! + volumeToken1: BigDecimal! + liquidity: BigDecimal! + liquidityNative: BigDecimal! + liquidityUSD: BigDecimal! + feesNative: BigDecimal! + feesUSD: BigDecimal! + apr: BigDecimal! + transactionCount: BigInt! +} + +type _TokenPair { + """ id is created by combining token.id and count, e.g. 0x00x00:1 """ + id: ID! + + """ Pair """ + pair: Pair! + + """ Token """ + token: Token! +} + +type _WhitelistedTokenPair { + """ id is created by combining token.id and count, e.g. 0x00x00:1 """ + id: ID! + + """ Pair """ + pair: Pair! + + """ Token """ + token: Token! +} + +type Mint { + """ transaction.id:transaction.mints.length """ + id: ID! + transaction: Transaction! + timestamp: BigInt! + pair: Pair! + to: String! + liquidity: BigDecimal! + sender: Bytes + amount0: BigDecimal + amount1: BigDecimal + logIndex: BigInt + amountUSD: BigDecimal + feeTo: Bytes + feeLiquidity: BigDecimal +} + +type Transaction { + """ Tx hash """ + id: ID! + gasLimit: BigInt! + gasPrice: BigInt! + mints: [Mint!]! + burns: [Burn!]! + swaps: [Swap!]! + createdAtBlock: BigInt! + createdAtTimestamp: BigInt! +} + +type Burn { + """ transaction.id:transaction.burns.length """ + id: ID! + transaction: Transaction! + timestamp: BigInt! + pair: Pair! + liquidity: BigDecimal! + sender: String + amount0: BigDecimal + amount1: BigDecimal + to: String + logIndex: BigInt + amountUSD: BigDecimal + complete: Boolean! + feeTo: String + feeLiquidity: BigDecimal +} + +type Swap { + id: ID! + transaction: Transaction! + timestamp: BigInt! + pair: Pair! + sender: String! + tokenIn: Token! + tokenOut: Token! + amountIn: BigDecimal! + amountOut: BigDecimal! + to: String! + logIndex: BigInt + amountUSD: BigDecimal! +} + +type TokenHourSnapshot { + """ {tokenId}-hour-{timestamp} """ + id: ID! + date: Int! + token: Token! + liquidity: BigDecimal! + liquidityNative: BigDecimal! + liquidityUSD: BigDecimal! + volume: BigDecimal! + volumeNative: BigDecimal! + volumeUSD: BigDecimal! + priceNative: BigDecimal! + priceUSD: BigDecimal! + feesNative: BigDecimal! + feesUSD: BigDecimal! + transactionCount: BigInt! +} + +type TokenDaySnapshot { + """ {tokenId}-day-{timestamp} """ + id: ID! + date: Int! + token: Token! + liquidity: BigDecimal! + liquidityNative: BigDecimal! + liquidityUSD: BigDecimal! + volume: BigDecimal! + volumeNative: BigDecimal! + volumeUSD: BigDecimal! + priceNative: BigDecimal! + priceUSD: BigDecimal! + feesNative: BigDecimal! + feesUSD: BigDecimal! + transactionCount: BigInt! +} + +type FactoryHourSnapshot { + """ {factoryId}-hour-{timestamp} """ + id: ID! + factory: Factory! + date: Int! + volumeUSD: BigDecimal! + volumeNative: BigDecimal! + liquidityNative: BigDecimal! + liquidityUSD: BigDecimal! + feesNative: BigDecimal! + feesUSD: BigDecimal! + transactionCount: BigInt! +} + +type FactoryDaySnapshot { + """ {factoryId}-day-{timestamp} """ + id: ID! + factory: Factory! + date: Int! + volumeUSD: BigDecimal! + volumeNative: BigDecimal! + liquidityNative: BigDecimal! + liquidityUSD: BigDecimal! + feesNative: BigDecimal! + feesUSD: BigDecimal! + transactionCount: BigInt! +} + +type Mutation { + watchContract(address: String!, kind: String!, checkpoint: Boolean!, startingBlock: Int): Boolean! +} + +type Subscription { + onEvent: ResultEvent! +} diff --git a/packages/sushiswap-watcher/src/server.ts b/packages/sushiswap-watcher/src/server.ts new file mode 100644 index 0000000..679134f --- /dev/null +++ b/packages/sushiswap-watcher/src/server.ts @@ -0,0 +1,43 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +import fs from 'fs'; +import path from 'path'; +import 'reflect-metadata'; +import debug from 'debug'; + +import { ServerCmd } from '@cerc-io/cli'; +import { getGraphDbAndWatcher } from '@cerc-io/graph-node'; + +import { createResolvers } from './resolvers'; +import { Indexer } from './indexer'; +import { Database, ENTITY_QUERY_TYPE_MAP, ENTITY_TO_LATEST_ENTITY_MAP } from './database'; + +const log = debug('vulcanize:server'); + +export const main = async (): Promise => { + const serverCmd = new ServerCmd(); + await serverCmd.init(Database); + + const { graphWatcher } = await getGraphDbAndWatcher( + serverCmd.config.server, + serverCmd.clients.ethClient, + serverCmd.ethProvider, + serverCmd.database.baseDatabase, + ENTITY_QUERY_TYPE_MAP, + ENTITY_TO_LATEST_ENTITY_MAP + ); + + await serverCmd.initIndexer(Indexer, graphWatcher); + + const typeDefs = fs.readFileSync(path.join(__dirname, 'schema.gql')).toString(); + + return serverCmd.exec(createResolvers, typeDefs); +}; + +main().then(() => { + log('Starting server...'); +}).catch(err => { + log(err); +}); diff --git a/packages/sushiswap-watcher/src/types.ts b/packages/sushiswap-watcher/src/types.ts new file mode 100644 index 0000000..6fcd13e --- /dev/null +++ b/packages/sushiswap-watcher/src/types.ts @@ -0,0 +1,7 @@ +// +// Copyright 2021 Vulcanize, Inc. +// + +export enum PairType { + CONSTANT_PRODUCT_POOL = 'CONSTANT_PRODUCT_POOL', +} diff --git a/packages/sushiswap-watcher/subgraph-build/Factory/Factory.wasm b/packages/sushiswap-watcher/subgraph-build/Factory/Factory.wasm new file mode 100644 index 0000000..1e1b5f4 Binary files /dev/null and b/packages/sushiswap-watcher/subgraph-build/Factory/Factory.wasm differ diff --git a/packages/sushiswap-watcher/subgraph-build/schema.graphql b/packages/sushiswap-watcher/subgraph-build/schema.graphql new file mode 100644 index 0000000..79847c9 --- /dev/null +++ b/packages/sushiswap-watcher/subgraph-build/schema.graphql @@ -0,0 +1,421 @@ +enum PairType { + CONSTANT_PRODUCT_POOL +} + +type Factory @entity { + " Contract address " + id: ID! + " Factory type " + type: PairType! + " Volume USD " + volumeUSD: BigDecimal! + " Volume Native " + volumeNative: BigDecimal! + " Liquidity USD " + liquidityUSD: BigDecimal! + " Liquidity NATIVE " + liquidityNative: BigDecimal! + " Fees USD " + feesUSD: BigDecimal! + " Fees NATIVE " + feesNative: BigDecimal! + " Pair count " + pairCount: BigInt! + " Transaction count " + transactionCount: BigInt! + " Token count " + tokenCount: BigInt! + " User count " + userCount: BigInt! +} + +" Bundle - should only ever be one created" +type Bundle @entity { + " hardcoded to '1'" + id: ID! + " Price of native " + nativePrice: BigDecimal! +} + +type Token @entity { + " Token address " + id: ID! + " Token Price " + price: TokenPrice! + " Symbol of the token " + symbol: String! + " if symbol was successfully retrieved " + symbolSuccess: Boolean! + " Name of the token " + name: String! + " if name was successfully retrieved " + nameSuccess: Boolean! + " Decimals of the token " + decimals: BigInt! + " if decimals were successfully retrieved " + decimalsSuccess: Boolean! + + " Liquidity " + liquidity: BigInt! + " Liquidity in native " + liquidityNative: BigDecimal! + " Liquidity in USD " + liquidityUSD: BigDecimal! + " Volume " + volume: BigDecimal! + " Volume in native " + volumeNative: BigDecimal! + " Volume in USD " + volumeUSD: BigDecimal! + " Fee in USD " + feesNative: BigDecimal! + " Volume in USD " + feesUSD: BigDecimal! + " Count of all the transactions " + txCount: BigInt! + " Count of all the pairs " + pairCount: BigInt! + " Count of all the whitelisted pairs " + whitelistedPairCount: BigInt! + " All pairs where this token is involved in " + pairs: [_TokenPair!]! @derivedFrom(field: "token") + " All whitelisted pairs where this token is involved in " + whitelistedPairs: [_WhitelistedTokenPair!]! @derivedFrom(field: "token") +} + +type TokenPrice @entity { + " same as token entity id, address of token " + id: ID! + " Token " + token: Token! + " derived native, this is useful for calculating price. (derivedNative * bundle.nativePrice = USD price) " + derivedNative: BigDecimal! + " price in USD. NOTE: this will not always be up to date, it only updates when onSync event is emitted, bundle.nativePrice could have changed. " + lastUsdPrice: BigDecimal! + " Which token this price is based on " + pricedOffToken: Token + " Which pair this price is based on " + pricedOffPair: Pair +} + +type _TokenPair @entity(immutable: true) { + " id is created by combining token.id and count, e.g. 0x00x00:1 " + id: ID! + " Pair " + pair: Pair! + " Token " + token: Token! +} + +type _WhitelistedTokenPair @entity(immutable: true) { + " id is created by combining token.id and count, e.g. 0x00x00:1 " + id: ID! + " Pair " + pair: Pair! + " Token " + token: Token! +} + +type Pair @entity { + " Pair address (contract address) " + id: ID! + " Pair type " + type: PairType! + " Swap fee " + swapFee: BigInt! + " TWAP - time weighted average price " + twapEnabled: Boolean! + " name of the pair, this combines symbol of both tokens, e.g. WETH/SUSHI " + name: String! + " First Token " + token0: Token! + " Second Token " + token1: Token! + " Which source this pair comes from, in this case it will always be 'LEGACY' " + source: String! + " Which block this pair was created on " + createdAtBlock: BigInt! + " When this pair was created " + createdAtTimestamp: BigInt! + + " Liquidity of first token " + reserve0: BigInt! + " Liquidity of second token " + reserve1: BigInt! + " Liquidity, Total supply of all LP in this pool " + liquidity: BigInt! + " USD liquidity" + liquidityUSD: BigDecimal! + " Native Liquidity " + liquidityNative: BigDecimal! + " Tracked Liquidity native " + trackedLiquidityNative: BigDecimal! + " Price of the first token in this pair, not to be confused with TokenPrice entity " + token0Price: BigDecimal! + " Price of the second token in this pair, not to be confused with TokenPrice entity " + token1Price: BigDecimal! + # volume in Native + volumeNative: BigDecimal! + # volume in USD + volumeUSD: BigDecimal! + # volume token0 + volumeToken0: BigDecimal! + # volume token1 + volumeToken1: BigDecimal! + " Fee in Native " + feesNative: BigDecimal! + " Fee in USD " + feesUSD: BigDecimal! + " APR " + apr: BigDecimal! + " When APR was last updated " + aprUpdatedAtTimestamp: BigInt! + " Transaction count " + txCount: BigInt! + + " Liquidity Positions " + liquidityPositions: [LiquidityPosition!]! @derivedFrom(field: "pair") + " Liquidity position snapshots " + liquidityPositionSnapshots: [LiquidityPositionSnapshot!]! @derivedFrom(field: "pair") + " Pair Hour Snapshot " + hourSnapshots: [PairHourSnapshot!]! @derivedFrom(field: "pair") + " Pair Day Snapshot " + daySnapshots: [PairDaySnapshot!]! @derivedFrom(field: "pair") +} + + +type User @entity { + id: ID! + lpSnapshotsCount: BigInt! + liquidityPositions: [LiquidityPosition!] @derivedFrom(field: "user") +} + +type LiquidityPosition @entity { + "pair.id:user.id" + id: ID! + pair: Pair! + user: User! + balance: BigInt! + createdAtBlock: BigInt! + createdAtTimestamp: BigInt! +} + +type Mint @entity { + " transaction.id:transaction.mints.length " + id: ID! + transaction: Transaction! + timestamp: BigInt! # need this to pull recent txns for specific token or pair + pair: Pair! + + # populated from the primary Transfer event + to: String! + liquidity: BigDecimal! + + # populated from the Mint event + sender: Bytes + amount0: BigDecimal + amount1: BigDecimal + logIndex: BigInt + # derived amount based on available prices of tokens + amountUSD: BigDecimal + + # optional fee fields, if a Transfer event is fired in _mintFee + feeTo: Bytes + feeLiquidity: BigDecimal +} + +type Burn @entity { + " transaction.id:transaction.burns.length " + id: ID! + transaction: Transaction! + timestamp: BigInt! # need this to pull recent txns for specific token or pair + pair: Pair! + + # populated from the primary Transfer event + liquidity: BigDecimal! + + # populated from the Burn event + sender: String + amount0: BigDecimal + amount1: BigDecimal + to: String + logIndex: BigInt + # derived amount based on available prices of tokens + amountUSD: BigDecimal + + # mark uncomplete in ETH case + complete: Boolean! + + # optional fee fields, if a Transfer event is fired in _mintFee + feeTo: String + feeLiquidity: BigDecimal +} + +type Swap @entity { + # transaction hash - index of swap in transaction swaps array + id: ID! + transaction: Transaction! + timestamp: BigInt! # need this to pull recent txns for specific token or pair + pair: Pair! + + # populated from the Swap event + sender: String! + tokenIn: Token! + tokenOut: Token! + amountIn: BigDecimal! + amountOut: BigDecimal! + to: String! + logIndex: BigInt + + # derived info + amountUSD: BigDecimal! +} + + +type Transaction @entity { + " Tx hash " + id: ID! + gasLimit: BigInt! + gasPrice: BigInt! + # This is not the reverse of Mint.transaction; it is only used to + # track incomplete mints (similar for burns and swaps) + mints: [Mint!]! + burns: [Burn!]! + swaps: [Swap!]! + createdAtBlock: BigInt! + createdAtTimestamp: BigInt! +} + +# saved over time for return calculations, gets created and never updated +type LiquidityPositionSnapshot @entity(immutable: true) { + " {lp.id}-{timestamp} " + id: ID! + liquidityPosition: LiquidityPosition! + " saved for fast historical lookups " + timestamp: Int! + " saved for fast historical lookups " + block: Int! + " reference to user " + user: User! + " reference to pair " + pair: Pair! + " snapshot of token0 price " + token0PriceUSD: BigDecimal! + " snapshot of token1 price " + token1PriceUSD: BigDecimal! + " snapshot of pair token0 reserves " + reserve0: BigInt! + " snapshot of pair token1 reserves " + reserve1: BigInt! + " snapshot of pair reserves in USD " + reserveUSD: BigDecimal! + " snapshot of pool token supply " + liquidityTokenTotalSupply: BigInt! + " snapshot of users pool token balance " + liquidityTokenBalance: BigInt! +} + +type PairHourSnapshot @entity { + " {pairId}-hour-{timestamp} " + id: ID! + pair: Pair! + date: Int! + " Used to calculate apr " + cumulativeVolumeUSD: BigDecimal! + volumeUSD: BigDecimal! + volumeNative: BigDecimal! + volumeToken0: BigDecimal! + volumeToken1: BigDecimal! + liquidity: BigDecimal! + liquidityNative: BigDecimal! + liquidityUSD: BigDecimal! + feesNative: BigDecimal! + feesUSD: BigDecimal! + apr: BigDecimal! + transactionCount: BigInt! +} + +type PairDaySnapshot @entity { + " {pairId}-day-{timestamp} " + id: ID! + pair: Pair! + date: Int! + " Used to calculate apr " + cumulativeVolumeUSD: BigDecimal! + volumeUSD: BigDecimal! + volumeNative: BigDecimal! + volumeToken0: BigDecimal! + volumeToken1: BigDecimal! + liquidity: BigDecimal! + liquidityNative: BigDecimal! + liquidityUSD: BigDecimal! + feesNative: BigDecimal! + feesUSD: BigDecimal! + apr: BigDecimal! + transactionCount: BigInt! +} + +type TokenHourSnapshot @entity { + " {tokenId}-hour-{timestamp} " + id: ID! + date: Int! + token: Token! + liquidity: BigDecimal! + liquidityNative: BigDecimal! + liquidityUSD: BigDecimal! + volume: BigDecimal! + volumeNative: BigDecimal! + volumeUSD: BigDecimal! + priceNative: BigDecimal! + priceUSD: BigDecimal! + feesNative: BigDecimal! + feesUSD: BigDecimal! + transactionCount: BigInt! +} + +type TokenDaySnapshot @entity { + " {tokenId}-day-{timestamp} " + id: ID! + date: Int! + token: Token! + liquidity: BigDecimal! + liquidityNative: BigDecimal! + liquidityUSD: BigDecimal! + volume: BigDecimal! + volumeNative: BigDecimal! + volumeUSD: BigDecimal! + priceNative: BigDecimal! + priceUSD: BigDecimal! + feesNative: BigDecimal! + feesUSD: BigDecimal! + transactionCount: BigInt! +} + +type FactoryHourSnapshot @entity { + " {factoryId}-hour-{timestamp} " + id: ID! + factory: Factory! + date: Int! + volumeUSD: BigDecimal! + volumeNative: BigDecimal! + liquidityNative: BigDecimal! + liquidityUSD: BigDecimal! + feesNative: BigDecimal! + feesUSD: BigDecimal! + transactionCount: BigInt! +} + +type FactoryDaySnapshot @entity { + " {factoryId}-day-{timestamp} " + id: ID! + factory: Factory! + date: Int! + volumeUSD: BigDecimal! + volumeNative: BigDecimal! + liquidityNative: BigDecimal! + liquidityUSD: BigDecimal! + feesNative: BigDecimal! + feesUSD: BigDecimal! + transactionCount: BigInt! +} + diff --git a/packages/sushiswap-watcher/subgraph-build/subgraph.yaml b/packages/sushiswap-watcher/subgraph-build/subgraph.yaml new file mode 100644 index 0000000..9df365a --- /dev/null +++ b/packages/sushiswap-watcher/subgraph-build/subgraph.yaml @@ -0,0 +1,69 @@ +specVersion: 0.0.6 +description: Sushiswap +repository: https://github.com/sushiswap/sushiswap-subgraph +schema: + file: schema.graphql +dataSources: + - kind: ethereum/contract + name: Factory + network: mainnet + source: + address: "0x9b3336186a38e1b6c21955d112dbb0343ee061ee" + abi: Factory + startBlock: 3328632 + mapping: + kind: ethereum/events + apiVersion: 0.0.7 + language: wasm/assemblyscript + file: Factory/Factory.wasm + entities: [] + abis: + - name: Factory + file: Factory/node_modules/abi/Uniswap/UniswapV2Factory.json + - name: Pair + file: Factory/node_modules/abi/Uniswap/UniswapV2Pair.json + - name: SushiToken + file: Factory/node_modules/abi/SUSHI/SushiToken.json + - name: ERC20 + file: Factory/node_modules/abi/ERC20/ERC20.json + - name: SymbolBytes32 + file: Factory/node_modules/abi/ERC20/SymbolBytes32.json + - name: NameBytes32 + file: Factory/node_modules/abi/ERC20/NameBytes32.json + eventHandlers: + - event: PairCreated(indexed address,indexed address,address,uint256) + handler: onPairCreated +templates: + - kind: ethereum/contract + name: Pair + network: mainnet + source: + abi: Pair + mapping: + kind: ethereum/events + apiVersion: 0.0.7 + language: wasm/assemblyscript + file: templates/Pair/Pair.wasm + entities: [] + abis: + - name: Factory + file: Pair/node_modules/abi/Uniswap/UniswapV2Factory.json + - name: Pair + file: Pair/node_modules/abi/Uniswap/UniswapV2Pair.json + - name: ERC20 + file: Pair/node_modules/abi/ERC20/ERC20.json + - name: SymbolBytes32 + file: Pair/node_modules/abi/ERC20/SymbolBytes32.json + - name: NameBytes32 + file: Pair/node_modules/abi/ERC20/NameBytes32.json + eventHandlers: + - event: Sync(uint112,uint112) + handler: onSync + - event: Transfer(indexed address,indexed address,uint256) + handler: onTransfer + - event: Mint(indexed address,uint256,uint256) + handler: onMint + - event: Burn(indexed address,uint256,uint256,indexed address) + handler: onBurn + - event: Swap(indexed address,uint256,uint256,uint256,uint256,indexed address) + handler: onSwap diff --git a/packages/sushiswap-watcher/subgraph-build/templates/Pair/Pair.wasm b/packages/sushiswap-watcher/subgraph-build/templates/Pair/Pair.wasm new file mode 100644 index 0000000..b12d873 Binary files /dev/null and b/packages/sushiswap-watcher/subgraph-build/templates/Pair/Pair.wasm differ diff --git a/packages/sushiswap-watcher/tsconfig.json b/packages/sushiswap-watcher/tsconfig.json new file mode 100644 index 0000000..f4b8852 --- /dev/null +++ b/packages/sushiswap-watcher/tsconfig.json @@ -0,0 +1,74 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig.json to read more about this file */ + + /* Basic Options */ + // "incremental": true, /* Enable incremental compilation */ + "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */ + "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ + "lib": ["es2019"], /* Specify library files to be included in the compilation. */ + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */ + // "declaration": true, /* Generates corresponding '.d.ts' file. */ + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + "outDir": "dist", /* Redirect output structure to the directory. */ + // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "composite": true, /* Enable project compilation */ + // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + + /* Strict Type-Checking Options */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an 'override' modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */ + + /* Module Resolution Options */ + // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + + /* Source Map Options */ + // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + + /* Experimental Options */ + "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + + /* Advanced Options */ + "skipLibCheck": true, /* Skip type checking of declaration files. */ + "forceConsistentCasingInFileNames": true, /* Disallow inconsistently-cased references to the same file. */ + "resolveJsonModule": true /* Enabling the option allows importing JSON, and validating the types in that JSON file. */ + }, + "include": ["src/**/*"] +}