diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 5537680..0000000 --- a/.gitignore +++ /dev/null @@ -1,42 +0,0 @@ -# http://www.gnu.org/software/automake -config.h.in -Makefile.in -Makefile -# http://www.gnu.org/software/autoconf -*.la -/autom4te.cache -/aclocal.m4 -/compile -/configure -/depcomp -/install-sh -/missing -test -*~ -.*~ -.cproject -.project -.settings -*.o -*.lo -.*.swp -.libs -.deps - -*.html -/autom4te.cache -/stamp-h1 -Makefile -/config.status -/config.log -/config.h -/aclocal.m4 -Makefile.in -/config/ -/configure -*~ -m4/*.m4 -/build*/ -ltmain.sh -libtool -libwebsock.la diff --git a/AUTHORS b/AUTHORS deleted file mode 100644 index e69de29..0000000 diff --git a/COPYING b/COPYING deleted file mode 100644 index 94a9ed0..0000000 --- a/COPYING +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 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 General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is 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. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - 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. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - 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 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. Use with the GNU Affero General Public License. - - 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 Affero 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 special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU 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 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 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 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 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - 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 GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..27fbc6d --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,5283 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "aead" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" +dependencies = [ + "generic-array", +] + +[[package]] +name = "aes" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", + "opaque-debug", +] + +[[package]] +name = "aes-gcm-siv" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589c637f0e68c877bbd59a4599bbe849cac8e5f3e4b5a3ebae8f528cd218dcdc" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "polyval", + "subtle", + "zeroize", +] + +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom 0.2.15", + "once_cell", + "version_check", +] + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "getrandom 0.2.15", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + +[[package]] +name = "anyhow" +version = "1.0.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c042108f3ed77fd83760a5fd79b53be043192bb3b9dba91d8c574c0ada7850c8" + +[[package]] +name = "ark-bn254" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a22f4561524cd949590d78d7d4c5df8f592430d221f7f3c9497bbafd8972120f" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-std", +] + +[[package]] +name = "ark-ec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +dependencies = [ + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", + "itertools", + "num-traits", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm", + "ark-ff-macros", + "ark-serialize", + "ark-std", + "derivative", + "digest 0.10.7", + "itertools", + "num-bigint 0.4.6", + "num-traits", + "paste", + "rustc_version", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint 0.4.6", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-poly" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +dependencies = [ + "ark-ff", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-serialize-derive", + "ark-std", + "digest 0.10.7", + "num-bigint 0.4.6", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "ascii" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" + +[[package]] +name = "asn1-rs" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6fd5ddaf0351dff5b8da21b2fb4ff8e08ddd02857f0bf69c47639106c0fff0" +dependencies = [ + "asn1-rs-derive", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror", + "time", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "synstructure", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "assert_matches" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" + +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener", + "futures-core", +] + +[[package]] +name = "async-compression" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cb8f1d480b0ea3783ab015936d2a55c87e219676f0c0b7dec61494043f21857" +dependencies = [ + "brotli", + "flate2", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "async-mutex" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e" +dependencies = [ + "event-listener", +] + +[[package]] +name = "async-trait" +version = "0.1.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.83", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "backtrace" +version = "0.3.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets 0.52.6", +] + +[[package]] +name = "base64" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +dependencies = [ + "serde", +] + +[[package]] +name = "bitmaps" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2" +dependencies = [ + "typenum", +] + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "blake3" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30cca6d3674597c30ddf2c587bf8d9d65c9a84d2326d941cc79c9842dfe0ef52" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "digest 0.10.7", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "block-padding", + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-padding" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" + +[[package]] +name = "borsh" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15bf3650200d8bffa99015595e10f1fbd17de07abbc25bb067da79e769939bfa" +dependencies = [ + "borsh-derive 0.9.3", + "hashbrown 0.11.2", +] + +[[package]] +name = "borsh" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115e54d64eb62cdebad391c19efc9dce4981c690c85a33a12199d99bb9546fee" +dependencies = [ + "borsh-derive 0.10.4", + "hashbrown 0.13.2", +] + +[[package]] +name = "borsh" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6362ed55def622cddc70a4746a68554d7b687713770de539e59a739b249f8ed" +dependencies = [ + "borsh-derive 1.5.1", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6441c552f230375d18e3cc377677914d2ca2b0d36e52129fe15450a2dce46775" +dependencies = [ + "borsh-derive-internal 0.9.3", + "borsh-schema-derive-internal 0.9.3", + "proc-macro-crate 0.1.5", + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "borsh-derive" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831213f80d9423998dd696e2c5345aba6be7a0bd8cd19e31c5243e13df1cef89" +dependencies = [ + "borsh-derive-internal 0.10.4", + "borsh-schema-derive-internal 0.10.4", + "proc-macro-crate 0.1.5", + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "borsh-derive" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ef8005764f53cd4dca619f5bf64cafd4664dada50ece25e4d81de54c80cc0b" +dependencies = [ + "once_cell", + "proc-macro-crate 3.2.0", + "proc-macro2", + "quote", + "syn 2.0.83", + "syn_derive", +] + +[[package]] +name = "borsh-derive-internal" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5449c28a7b352f2d1e592a8a28bf139bc71afb0764a14f3c02500935d8c44065" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "borsh-derive-internal" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65d6ba50644c98714aa2a70d13d7df3cd75cd2b523a2b452bf010443800976b3" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "borsh-schema-derive-internal" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdbd5696d8bfa21d53d9fe39a714a18538bad11492a42d066dbbc395fb1951c0" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "borsh-schema-derive-internal" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "276691d96f063427be83e6692b86148e488ebba9f48f77788724ca027ba3b6d4" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "brotli" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bs58" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "bv" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8834bb1d8ee5dc048ee3124f2c7c1afcc6bc9aed03f11e9dfd8c69470a5db340" +dependencies = [ + "feature-probe", + "serde", +] + +[[package]] +name = "bytecheck" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "bytemuck" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcfcc3cd946cb52f0bbfdbbcfa2f4e24f75ebb6c0e1002f7c25904fada18b9ec" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.83", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" + +[[package]] +name = "caps" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190baaad529bcfbde9e1a19022c42781bdb6ff9de25721abdb8fd98c0807730b" +dependencies = [ + "libc", + "thiserror", +] + +[[package]] +name = "cc" +version = "1.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2e7962b54006dcfcc61cb72735f4d89bb97061dd6a7ed882ec6b8ee53714c6f" +dependencies = [ + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-targets 0.52.6", +] + +[[package]] +name = "cipher" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +dependencies = [ + "generic-array", +] + +[[package]] +name = "clap" +version = "2.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +dependencies = [ + "ansi_term", + "atty", + "bitflags 1.3.2", + "strsim 0.8.0", + "textwrap 0.11.0", + "unicode-width", + "vec_map", +] + +[[package]] +name = "clap" +version = "3.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" +dependencies = [ + "atty", + "bitflags 1.3.2", + "clap_lex", + "indexmap 1.9.3", + "once_cell", + "strsim 0.10.0", + "termcolor", + "textwrap 0.16.1", +] + +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "combine" +version = "3.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680" +dependencies = [ + "ascii", + "byteorder", + "either", + "memchr", + "unreachable", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "console" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "unicode-width", + "windows-sys 0.52.0", +] + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "console_log" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89f72f65e8501878b8a004d5a1afb780987e2ce2b4532c562e367a72c57499f" +dependencies = [ + "log", + "web-sys", +] + +[[package]] +name = "const-oid" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" + +[[package]] +name = "constant_time_eq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "crypto-mac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "ctr" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" +dependencies = [ + "cipher", +] + +[[package]] +name = "curve25519-dalek" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "serde", + "subtle", + "zeroize", +] + +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.11.1", + "syn 2.0.83", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.83", +] + +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "data-encoding" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + +[[package]] +name = "der" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" +dependencies = [ + "const-oid", +] + +[[package]] +name = "der-parser" +version = "8.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbd676fbbab537128ef0278adb5576cf363cff6aa22a7b24effe97347cfab61e" +dependencies = [ + "asn1-rs", + "displaydoc", + "nom", + "num-bigint 0.4.6", + "num-traits", + "rusticata-macros", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "derivation-path" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e5c37193a1db1d8ed868c03ec7b152175f26160a5b740e5e484143877e0adf0" + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "dialoguer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59c6f2989294b9a498d3ad5491a79c6deb604617378e1cdc4bfc1c1361fe2f87" +dependencies = [ + "console", + "shell-words", + "tempfile", + "zeroize", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "crypto-common", + "subtle", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.83", +] + +[[package]] +name = "dlopen2" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b4f5f101177ff01b8ec4ecc81eead416a8aa42819a2869311b3420fa114ffa" +dependencies = [ + "dlopen2_derive", + "libc", + "once_cell", + "winapi", +] + +[[package]] +name = "dlopen2_derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cbae11b3de8fce2a456e8ea3dada226b35fe791f0dc1d360c0941f0bb681f3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.83", +] + +[[package]] +name = "eager" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abe71d579d1812060163dff96056261deb5bf6729b100fa2e36a68b9649ba3d3" + +[[package]] +name = "ed25519" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" +dependencies = [ + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" +dependencies = [ + "curve25519-dalek", + "ed25519", + "rand 0.7.3", + "serde", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "ed25519-dalek-bip32" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d2be62a4061b872c8c0873ee4fc6f101ce7b889d039f019c5fa2af471a59908" +dependencies = [ + "derivation-path", + "ed25519-dalek", + "hmac 0.12.1", + "sha2 0.10.8", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + +[[package]] +name = "encoding_rs" +version = "0.8.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "enum-iterator" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fd242f399be1da0a5354aa462d57b4ab2b4ee0683cc552f7c007d2d12d36e94" +dependencies = [ + "enum-iterator-derive", +] + +[[package]] +name = "enum-iterator-derive" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ab991c1362ac86c61ab6f556cff143daa22e5a15e4e189df818b2fd19fe65b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.83", +] + +[[package]] +name = "env_logger" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "fastrand" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" + +[[package]] +name = "feature-probe" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835a3dc7d1ec9e75e2b5fb4ba75396837112d2060b03f7d43bc1897c7f7211da" + +[[package]] +name = "flate2" +version = "1.0.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.83", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "serde", + "typenum", + "version_check", +] + +[[package]] +name = "gethostname" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1ebd34e35c46e00bb73e81363248d627782724609fe1b6396f553f68fe3862e" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "goblin" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7666983ed0dd8d21a6f6576ee00053ca0926fb281a5522577a4dbd0f1b54143" +dependencies = [ + "log", + "plain", + "scroll", +] + +[[package]] +name = "h2" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap 2.6.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hash32" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" +dependencies = [ + "byteorder", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +dependencies = [ + "ahash 0.7.8", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.8", +] + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash 0.8.11", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hashbrown" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "histogram" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12cb882ccb290b8646e554b157ab0b71e64e8d5bef775cd66b6531e52d302669" + +[[package]] +name = "hmac" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" +dependencies = [ + "crypto-mac", + "digest 0.9.0", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "hmac-drbg" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" +dependencies = [ + "digest 0.9.0", + "generic-array", + "hmac 0.8.1", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "hyper" +version = "0.14.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c08302e8fa335b151b788c775ff56e7a03ae64ff85c548ee820fecb70356e85" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http", + "hyper", + "rustls", + "tokio", + "tokio-rustls", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "im" +version = "15.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0acd33ff0285af998aaf9b57342af478078f53492322fafc47450e09397e0e9" +dependencies = [ + "bitmaps", + "rand_core 0.6.4", + "rand_xoshiro", + "rayon", + "serde", + "sized-chunks", + "typenum", + "version_check", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +dependencies = [ + "equivalent", + "hashbrown 0.15.0", +] + +[[package]] +name = "indicatif" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" +dependencies = [ + "console", + "instant", + "number_prefix", + "portable-atomic", + "unicode-width", +] + +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "ipnet" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "jsonrpc-core" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14f7f76aef2d054868398427f6c54943cf3d1caa9a7ec7d0c38d69df97a965eb" +dependencies = [ + "futures", + "futures-executor", + "futures-util", + "log", + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.161" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" + +[[package]] +name = "libsecp256k1" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9d220bc1feda2ac231cb78c3d26f27676b8cf82c96971f7aeef3d0cf2797c73" +dependencies = [ + "arrayref", + "base64 0.12.3", + "digest 0.9.0", + "hmac-drbg", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", + "rand 0.7.3", + "serde", + "sha2 0.9.9", + "typenum", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0f6ab710cec28cef759c5f18671a27dae2a5f952cdaaee1d8e2908cb2478a80" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccab96b584d38fac86a83f07e659f0deafd0253dc096dab5a36d53efe653c5c3" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67abfe149395e3aa1c48a2beb32b068e2334402df8181f818d3aee2b304c4f5d" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "light-poseidon" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c9a85a9752c549ceb7578064b4ed891179d20acd85f27318573b64d2d7ee7ee" +dependencies = [ + "ark-bn254", + "ark-ff", + "num-bigint 0.4.6", + "thiserror", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "memmap2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "merlin" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" +dependencies = [ + "byteorder", + "keccak", + "rand_core 0.6.4", + "zeroize", +] + +[[package]] +name = "mev-bot-solana" +version = "0.1.0" +dependencies = [ + "anyhow", + "env_logger", + "log", + "reqwest", + "rust_decimal", + "rust_decimal_macros", + "serde", + "serde_json", + "solana-client", + "solana-sdk", + "thiserror", + "tokio", + "toml", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +dependencies = [ + "hermit-abi 0.3.9", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.52.0", +] + +[[package]] +name = "native-tls" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "nix" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", + "memoffset 0.7.1", + "pin-utils", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8536030f9fea7127f841b45bb6243b27255787fb4eb83958aa1ef9d2fdc0c36" +dependencies = [ + "num-bigint 0.2.6", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.83", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" +dependencies = [ + "autocfg", + "num-bigint 0.2.6", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi 0.3.9", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1" +dependencies = [ + "num_enum_derive 0.6.1", +] + +[[package]] +name = "num_enum" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +dependencies = [ + "num_enum_derive 0.7.3", +] + +[[package]] +name = "num_enum_derive" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn 2.0.83", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +dependencies = [ + "proc-macro-crate 3.2.0", + "proc-macro2", + "quote", + "syn 2.0.83", +] + +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + +[[package]] +name = "object" +version = "0.36.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" +dependencies = [ + "memchr", +] + +[[package]] +name = "oid-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff" +dependencies = [ + "asn1-rs", +] + +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "openssl" +version = "0.10.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" +dependencies = [ + "bitflags 2.6.0", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.83", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "os_str_bytes" +version = "6.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pbkdf2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "216eaa586a190f0a738f2f918511eecfa90f13295abec0e457cdebcceda80cbd" +dependencies = [ + "crypto-mac", +] + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "pem" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" +dependencies = [ + "base64 0.13.1", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "percentage" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd23b938276f14057220b707937bcb42fa76dda7560e57a2da30cb52d557937" +dependencies = [ + "num", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs8" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cabda3fb821068a9a4fab19a683eac3af12edf0f34b94a8be53c4972b8149d0" +dependencies = [ + "der", + "spki", + "zeroize", +] + +[[package]] +name = "pkg-config" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" + +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + +[[package]] +name = "polyval" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "portable-atomic" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro-crate" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +dependencies = [ + "toml", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-crate" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +dependencies = [ + "toml_edit 0.22.22", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "ptr_meta" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "qstring" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "qualifier_attr" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e2e25ee72f5b24d773cae88422baddefff7714f97aab68d96fe2b6fc4a28fb2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.83", +] + +[[package]] +name = "quinn" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cc2c5017e4b43d5995dcea317bc46c1e09404c0a9664d2908f7f02dfe943d75" +dependencies = [ + "bytes", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "quinn-proto" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "141bf7dfde2fbc246bfd3fe12f2455aa24b0fbd9af535d8c86c7bd1381ff2b1a" +dependencies = [ + "bytes", + "rand 0.8.5", + "ring 0.16.20", + "rustc-hash", + "rustls", + "rustls-native-certs", + "slab", + "thiserror", + "tinyvec", + "tracing", +] + +[[package]] +name = "quinn-udp" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "055b4e778e8feb9f93c4e439f71dc2156ef13360b432b799e179a8c4cdf0b1d7" +dependencies = [ + "bytes", + "libc", + "socket2", + "tracing", + "windows-sys 0.48.0", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.15", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rand_xoshiro" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" +dependencies = [ + "rand_core 0.6.4", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "rcgen" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbe84efe2f38dea12e9bfc1f65377fdf03e53a18cb3b995faedf7934c7e785b" +dependencies = [ + "pem", + "ring 0.16.20", + "time", + "yasna", +] + +[[package]] +name = "redox_syscall" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +dependencies = [ + "bitflags 2.6.0", +] + +[[package]] +name = "regex" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "rend" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" +dependencies = [ + "bytecheck", +] + +[[package]] +name = "reqwest" +version = "0.11.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +dependencies = [ + "async-compression", + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-rustls", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "system-configuration", + "tokio", + "tokio-native-tls", + "tokio-rustls", + "tokio-util", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots 0.25.4", + "winreg", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin 0.5.2", + "untrusted 0.7.1", + "web-sys", + "winapi", +] + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.15", + "libc", + "spin 0.9.8", + "untrusted 0.9.0", + "windows-sys 0.52.0", +] + +[[package]] +name = "rkyv" +version = "0.7.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" +dependencies = [ + "bitvec", + "bytecheck", + "bytes", + "hashbrown 0.12.3", + "ptr_meta", + "rend", + "rkyv_derive", + "seahash", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "rpassword" +version = "7.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80472be3c897911d0137b2d2b9055faf6eeac5b14e324073d83bc17b191d7e3f" +dependencies = [ + "libc", + "rtoolbox", + "windows-sys 0.48.0", +] + +[[package]] +name = "rtoolbox" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c247d24e63230cdb56463ae328478bd5eac8b8faa8c69461a77e8e323afac90e" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "rust_decimal" +version = "1.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b082d80e3e3cc52b2ed634388d436fe1f4de6af5786cc2de9ba9737527bdf555" +dependencies = [ + "arrayvec", + "borsh 1.5.1", + "bytes", + "num-traits", + "rand 0.8.5", + "rkyv", + "serde", + "serde_json", +] + +[[package]] +name = "rust_decimal_macros" +version = "1.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da991f231869f34268415a49724c6578e740ad697ba0999199d6f22b3949332c" +dependencies = [ + "quote", + "rust_decimal", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom", +] + +[[package]] +name = "rustix" +version = "0.38.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" +dependencies = [ + "bitflags 2.6.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.21.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +dependencies = [ + "log", + "ring 0.17.8", + "rustls-webpki", + "sct", +] + +[[package]] +name = "rustls-native-certs" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" +dependencies = [ + "openssl-probe", + "rustls-pemfile", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring 0.17.8", + "untrusted 0.9.0", +] + +[[package]] +name = "rustversion" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "schannel" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "scroll" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" +dependencies = [ + "scroll_derive", +] + +[[package]] +name = "scroll_derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.83", +] + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring 0.17.8", + "untrusted 0.9.0", +] + +[[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.6.0", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + +[[package]] +name = "serde" +version = "1.0.213" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ea7893ff5e2466df8d720bb615088341b295f849602c6956047f8f80f0e9bc1" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.213" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e85ad2009c50b58e87caa8cd6dac16bdf511bbfb7af6c33df902396aa480fa5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.83", +] + +[[package]] +name = "serde_json" +version = "1.0.132" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07ff71d2c147a7b57362cead5e22f772cd52f6ab31cfcd9edcd7f6aeb2a0afbe" +dependencies = [ + "serde", + "serde_with_macros", +] + +[[package]] +name = "serde_with_macros" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.83", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha3" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" +dependencies = [ + "block-buffer 0.9.0", + "digest 0.9.0", + "keccak", + "opaque-debug", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest 0.10.7", + "keccak", +] + +[[package]] +name = "shell-words" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "sized-chunks" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e" +dependencies = [ + "bitmaps", + "typenum", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "solana-account-decoder" +version = "1.18.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b109fd3a106e079005167e5b0e6f6d2c88bbedec32530837b584791a8b5abf36" +dependencies = [ + "Inflector", + "base64 0.21.7", + "bincode", + "bs58", + "bv", + "lazy_static", + "serde", + "serde_derive", + "serde_json", + "solana-config-program", + "solana-sdk", + "spl-token", + "spl-token-2022", + "spl-token-group-interface", + "spl-token-metadata-interface", + "thiserror", + "zstd", +] + +[[package]] +name = "solana-clap-utils" +version = "1.18.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "074ef478856a45d5627270fbc6b331f91de9aae7128242d9e423931013fb8a2a" +dependencies = [ + "chrono", + "clap 2.34.0", + "rpassword", + "solana-remote-wallet", + "solana-sdk", + "thiserror", + "tiny-bip39", + "uriparse", + "url", +] + +[[package]] +name = "solana-client" +version = "1.18.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24a9f32c42402c4b9484d5868ac74b7e0a746e3905d8bfd756e1203e50cbb87e" +dependencies = [ + "async-trait", + "bincode", + "dashmap", + "futures", + "futures-util", + "indexmap 2.6.0", + "indicatif", + "log", + "quinn", + "rayon", + "solana-connection-cache", + "solana-measure", + "solana-metrics", + "solana-pubsub-client", + "solana-quic-client", + "solana-rpc-client", + "solana-rpc-client-api", + "solana-rpc-client-nonce-utils", + "solana-sdk", + "solana-streamer", + "solana-thin-client", + "solana-tpu-client", + "solana-udp-client", + "thiserror", + "tokio", +] + +[[package]] +name = "solana-config-program" +version = "1.18.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d75b803860c0098e021a26f0624129007c15badd5b0bc2fbd9f0e1a73060d3b" +dependencies = [ + "bincode", + "chrono", + "serde", + "serde_derive", + "solana-program-runtime", + "solana-sdk", +] + +[[package]] +name = "solana-connection-cache" +version = "1.18.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9306ede13e8ceeab8a096bcf5fa7126731e44c201ca1721ea3c38d89bcd4111" +dependencies = [ + "async-trait", + "bincode", + "crossbeam-channel", + "futures-util", + "indexmap 2.6.0", + "log", + "rand 0.8.5", + "rayon", + "rcgen", + "solana-measure", + "solana-metrics", + "solana-sdk", + "thiserror", + "tokio", +] + +[[package]] +name = "solana-frozen-abi" +version = "1.18.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03ab2c30c15311b511c0d1151e4ab6bc9a3e080a37e7c6e7c2d96f5784cf9434" +dependencies = [ + "block-buffer 0.10.4", + "bs58", + "bv", + "either", + "generic-array", + "im", + "lazy_static", + "log", + "memmap2", + "rustc_version", + "serde", + "serde_bytes", + "serde_derive", + "sha2 0.10.8", + "solana-frozen-abi-macro", + "subtle", + "thiserror", +] + +[[package]] +name = "solana-frozen-abi-macro" +version = "1.18.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c142f779c3633ac83c84d04ff06c70e1f558c876f13358bed77ba629c7417932" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.83", +] + +[[package]] +name = "solana-logger" +version = "1.18.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121d36ffb3c6b958763312cbc697fbccba46ee837d3a0aa4fc0e90fcb3b884f3" +dependencies = [ + "env_logger", + "lazy_static", + "log", +] + +[[package]] +name = "solana-measure" +version = "1.18.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c01a7f9cdc9d9d37a3d5651b2fe7ec9d433c2a3470b9f35897e373b421f0737" +dependencies = [ + "log", + "solana-sdk", +] + +[[package]] +name = "solana-metrics" +version = "1.18.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e36052aff6be1536bdf6f737c6e69aca9dbb6a2f3f582e14ecb0ddc0cd66ce" +dependencies = [ + "crossbeam-channel", + "gethostname", + "lazy_static", + "log", + "reqwest", + "solana-sdk", + "thiserror", +] + +[[package]] +name = "solana-net-utils" +version = "1.18.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a1f5c6be9c5b272866673741e1ebc64b2ea2118e5c6301babbce526fdfb15f4" +dependencies = [ + "bincode", + "clap 3.2.25", + "crossbeam-channel", + "log", + "nix", + "rand 0.8.5", + "serde", + "serde_derive", + "socket2", + "solana-logger", + "solana-sdk", + "solana-version", + "tokio", + "url", +] + +[[package]] +name = "solana-perf" +version = "1.18.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28acaf22477566a0fbddd67249ea5d859b39bacdb624aff3fadd3c5745e2643c" +dependencies = [ + "ahash 0.8.11", + "bincode", + "bv", + "caps", + "curve25519-dalek", + "dlopen2", + "fnv", + "lazy_static", + "libc", + "log", + "nix", + "rand 0.8.5", + "rayon", + "rustc_version", + "serde", + "solana-frozen-abi", + "solana-frozen-abi-macro", + "solana-metrics", + "solana-rayon-threadlimit", + "solana-sdk", + "solana-vote-program", +] + +[[package]] +name = "solana-program" +version = "1.18.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c10f4588cefd716b24a1a40dd32c278e43a560ab8ce4de6b5805c9d113afdfa1" +dependencies = [ + "ark-bn254", + "ark-ec", + "ark-ff", + "ark-serialize", + "base64 0.21.7", + "bincode", + "bitflags 2.6.0", + "blake3", + "borsh 0.10.4", + "borsh 0.9.3", + "borsh 1.5.1", + "bs58", + "bv", + "bytemuck", + "cc", + "console_error_panic_hook", + "console_log", + "curve25519-dalek", + "getrandom 0.2.15", + "itertools", + "js-sys", + "lazy_static", + "libc", + "libsecp256k1", + "light-poseidon", + "log", + "memoffset 0.9.1", + "num-bigint 0.4.6", + "num-derive 0.4.2", + "num-traits", + "parking_lot", + "rand 0.8.5", + "rustc_version", + "rustversion", + "serde", + "serde_bytes", + "serde_derive", + "serde_json", + "sha2 0.10.8", + "sha3 0.10.8", + "solana-frozen-abi", + "solana-frozen-abi-macro", + "solana-sdk-macro", + "thiserror", + "tiny-bip39", + "wasm-bindgen", + "zeroize", +] + +[[package]] +name = "solana-program-runtime" +version = "1.18.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf0c3eab2a80f514289af1f422c121defb030937643c43b117959d6f1932fb5" +dependencies = [ + "base64 0.21.7", + "bincode", + "eager", + "enum-iterator", + "itertools", + "libc", + "log", + "num-derive 0.4.2", + "num-traits", + "percentage", + "rand 0.8.5", + "rustc_version", + "serde", + "solana-frozen-abi", + "solana-frozen-abi-macro", + "solana-measure", + "solana-metrics", + "solana-sdk", + "solana_rbpf", + "thiserror", +] + +[[package]] +name = "solana-pubsub-client" +version = "1.18.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b064e76909d33821b80fdd826e6757251934a52958220c92639f634bea90366d" +dependencies = [ + "crossbeam-channel", + "futures-util", + "log", + "reqwest", + "semver", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder", + "solana-rpc-client-api", + "solana-sdk", + "thiserror", + "tokio", + "tokio-stream", + "tokio-tungstenite", + "tungstenite", + "url", +] + +[[package]] +name = "solana-quic-client" +version = "1.18.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a90e40ee593f6e9ddd722d296df56743514ae804975a76d47e7afed4e3da244" +dependencies = [ + "async-mutex", + "async-trait", + "futures", + "itertools", + "lazy_static", + "log", + "quinn", + "quinn-proto", + "rcgen", + "rustls", + "solana-connection-cache", + "solana-measure", + "solana-metrics", + "solana-net-utils", + "solana-rpc-client-api", + "solana-sdk", + "solana-streamer", + "thiserror", + "tokio", +] + +[[package]] +name = "solana-rayon-threadlimit" +version = "1.18.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66468f9c014992167de10cc68aad6ac8919a8c8ff428dc88c0d2b4da8c02b8b7" +dependencies = [ + "lazy_static", + "num_cpus", +] + +[[package]] +name = "solana-remote-wallet" +version = "1.18.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c191019f4d4f84281a6d0dd9a43181146b33019627fc394e42e08ade8976b431" +dependencies = [ + "console", + "dialoguer", + "log", + "num-derive 0.4.2", + "num-traits", + "parking_lot", + "qstring", + "semver", + "solana-sdk", + "thiserror", + "uriparse", +] + +[[package]] +name = "solana-rpc-client" +version = "1.18.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36ed4628e338077c195ddbf790693d410123d17dec0a319b5accb4aaee3fb15c" +dependencies = [ + "async-trait", + "base64 0.21.7", + "bincode", + "bs58", + "indicatif", + "log", + "reqwest", + "semver", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder", + "solana-rpc-client-api", + "solana-sdk", + "solana-transaction-status", + "solana-version", + "solana-vote-program", + "tokio", +] + +[[package]] +name = "solana-rpc-client-api" +version = "1.18.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83c913551faa4a1ae4bbfef6af19f3a5cf847285c05b4409e37c8993b3444229" +dependencies = [ + "base64 0.21.7", + "bs58", + "jsonrpc-core", + "reqwest", + "semver", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder", + "solana-sdk", + "solana-transaction-status", + "solana-version", + "spl-token-2022", + "thiserror", +] + +[[package]] +name = "solana-rpc-client-nonce-utils" +version = "1.18.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a47b6bb1834e6141a799db62bbdcf80d17a7d58d7bc1684c614e01a7293d7cf" +dependencies = [ + "clap 2.34.0", + "solana-clap-utils", + "solana-rpc-client", + "solana-sdk", + "thiserror", +] + +[[package]] +name = "solana-sdk" +version = "1.18.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "580ad66c2f7a4c3cb3244fe21440546bd500f5ecb955ad9826e92a78dded8009" +dependencies = [ + "assert_matches", + "base64 0.21.7", + "bincode", + "bitflags 2.6.0", + "borsh 1.5.1", + "bs58", + "bytemuck", + "byteorder", + "chrono", + "derivation-path", + "digest 0.10.7", + "ed25519-dalek", + "ed25519-dalek-bip32", + "generic-array", + "hmac 0.12.1", + "itertools", + "js-sys", + "lazy_static", + "libsecp256k1", + "log", + "memmap2", + "num-derive 0.4.2", + "num-traits", + "num_enum 0.7.3", + "pbkdf2 0.11.0", + "qstring", + "qualifier_attr", + "rand 0.7.3", + "rand 0.8.5", + "rustc_version", + "rustversion", + "serde", + "serde_bytes", + "serde_derive", + "serde_json", + "serde_with", + "sha2 0.10.8", + "sha3 0.10.8", + "siphasher", + "solana-frozen-abi", + "solana-frozen-abi-macro", + "solana-logger", + "solana-program", + "solana-sdk-macro", + "thiserror", + "uriparse", + "wasm-bindgen", +] + +[[package]] +name = "solana-sdk-macro" +version = "1.18.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b75d0f193a27719257af19144fdaebec0415d1c9e9226ae4bd29b791be5e9bd" +dependencies = [ + "bs58", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.83", +] + +[[package]] +name = "solana-security-txt" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "468aa43b7edb1f9b7b7b686d5c3aeb6630dc1708e86e31343499dd5c4d775183" + +[[package]] +name = "solana-streamer" +version = "1.18.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8476e41ad94fe492e8c06697ee35912cf3080aae0c9e9ac6430835256ccf056" +dependencies = [ + "async-channel", + "bytes", + "crossbeam-channel", + "futures-util", + "histogram", + "indexmap 2.6.0", + "itertools", + "libc", + "log", + "nix", + "pem", + "percentage", + "pkcs8", + "quinn", + "quinn-proto", + "rand 0.8.5", + "rcgen", + "rustls", + "smallvec", + "solana-metrics", + "solana-perf", + "solana-sdk", + "thiserror", + "tokio", + "x509-parser", +] + +[[package]] +name = "solana-thin-client" +version = "1.18.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8c02245d0d232430e79dc0d624aa42d50006097c3aec99ac82ac299eaa3a73f" +dependencies = [ + "bincode", + "log", + "rayon", + "solana-connection-cache", + "solana-rpc-client", + "solana-rpc-client-api", + "solana-sdk", +] + +[[package]] +name = "solana-tpu-client" +version = "1.18.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67251506ed03de15f1347b46636b45c47da6be75015b4a13f0620b21beb00566" +dependencies = [ + "async-trait", + "bincode", + "futures-util", + "indexmap 2.6.0", + "indicatif", + "log", + "rayon", + "solana-connection-cache", + "solana-measure", + "solana-metrics", + "solana-pubsub-client", + "solana-rpc-client", + "solana-rpc-client-api", + "solana-sdk", + "thiserror", + "tokio", +] + +[[package]] +name = "solana-transaction-status" +version = "1.18.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d3d36db1b2ab2801afd5482aad9fb15ed7959f774c81a77299fdd0ddcf839d4" +dependencies = [ + "Inflector", + "base64 0.21.7", + "bincode", + "borsh 0.10.4", + "bs58", + "lazy_static", + "log", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder", + "solana-sdk", + "spl-associated-token-account", + "spl-memo", + "spl-token", + "spl-token-2022", + "thiserror", +] + +[[package]] +name = "solana-udp-client" +version = "1.18.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a754a3c2265eb02e0c35aeaca96643951f03cee6b376afe12e0cf8860ffccd1" +dependencies = [ + "async-trait", + "solana-connection-cache", + "solana-net-utils", + "solana-sdk", + "solana-streamer", + "thiserror", + "tokio", +] + +[[package]] +name = "solana-version" +version = "1.18.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f44776bd685cc02e67ba264384acc12ef2931d01d1a9f851cb8cdbd3ce455b9e" +dependencies = [ + "log", + "rustc_version", + "semver", + "serde", + "serde_derive", + "solana-frozen-abi", + "solana-frozen-abi-macro", + "solana-sdk", +] + +[[package]] +name = "solana-vote-program" +version = "1.18.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25810970c91feb579bd3f67dca215fce971522e42bfd59696af89c5dfebd997c" +dependencies = [ + "bincode", + "log", + "num-derive 0.4.2", + "num-traits", + "rustc_version", + "serde", + "serde_derive", + "solana-frozen-abi", + "solana-frozen-abi-macro", + "solana-metrics", + "solana-program", + "solana-program-runtime", + "solana-sdk", + "thiserror", +] + +[[package]] +name = "solana-zk-token-sdk" +version = "1.18.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cbdf4249b6dfcbba7d84e2b53313698043f60f8e22ce48286e6fbe8a17c8d16" +dependencies = [ + "aes-gcm-siv", + "base64 0.21.7", + "bincode", + "bytemuck", + "byteorder", + "curve25519-dalek", + "getrandom 0.1.16", + "itertools", + "lazy_static", + "merlin", + "num-derive 0.4.2", + "num-traits", + "rand 0.7.3", + "serde", + "serde_json", + "sha3 0.9.1", + "solana-program", + "solana-sdk", + "subtle", + "thiserror", + "zeroize", +] + +[[package]] +name = "solana_rbpf" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da5d083187e3b3f453e140f292c09186881da8a02a7b5e27f645ee26de3d9cc5" +dependencies = [ + "byteorder", + "combine", + "goblin", + "hash32", + "libc", + "log", + "rand 0.8.5", + "rustc-demangle", + "scroll", + "thiserror", + "winapi", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "spki" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d01ac02a6ccf3e07db148d2be087da624fea0221a16152ed01f0496a6b0a27" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "spl-associated-token-account" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "992d9c64c2564cc8f63a4b508bf3ebcdf2254b0429b13cd1d31adb6162432a5f" +dependencies = [ + "assert_matches", + "borsh 0.10.4", + "num-derive 0.4.2", + "num-traits", + "solana-program", + "spl-token", + "spl-token-2022", + "thiserror", +] + +[[package]] +name = "spl-discriminator" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cce5d563b58ef1bb2cdbbfe0dfb9ffdc24903b10ae6a4df2d8f425ece375033f" +dependencies = [ + "bytemuck", + "solana-program", + "spl-discriminator-derive", +] + +[[package]] +name = "spl-discriminator-derive" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07fd7858fc4ff8fb0e34090e41d7eb06a823e1057945c26d480bfc21d2338a93" +dependencies = [ + "quote", + "spl-discriminator-syn", + "syn 2.0.83", +] + +[[package]] +name = "spl-discriminator-syn" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18fea7be851bd98d10721782ea958097c03a0c2a07d8d4997041d0ece6319a63" +dependencies = [ + "proc-macro2", + "quote", + "sha2 0.10.8", + "syn 2.0.83", + "thiserror", +] + +[[package]] +name = "spl-memo" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f180b03318c3dbab3ef4e1e4d46d5211ae3c780940dd0a28695aba4b59a75a" +dependencies = [ + "solana-program", +] + +[[package]] +name = "spl-pod" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2881dddfca792737c0706fa0175345ab282b1b0879c7d877bad129645737c079" +dependencies = [ + "borsh 0.10.4", + "bytemuck", + "solana-program", + "solana-zk-token-sdk", + "spl-program-error", +] + +[[package]] +name = "spl-program-error" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "249e0318493b6bcf27ae9902600566c689b7dfba9f1bdff5893e92253374e78c" +dependencies = [ + "num-derive 0.4.2", + "num-traits", + "solana-program", + "spl-program-error-derive", + "thiserror", +] + +[[package]] +name = "spl-program-error-derive" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1845dfe71fd68f70382232742e758557afe973ae19e6c06807b2c30f5d5cb474" +dependencies = [ + "proc-macro2", + "quote", + "sha2 0.10.8", + "syn 2.0.83", +] + +[[package]] +name = "spl-tlv-account-resolution" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "615d381f48ddd2bb3c57c7f7fb207591a2a05054639b18a62e785117dd7a8683" +dependencies = [ + "bytemuck", + "solana-program", + "spl-discriminator", + "spl-pod", + "spl-program-error", + "spl-type-length-value", +] + +[[package]] +name = "spl-token" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08459ba1b8f7c1020b4582c4edf0f5c7511a5e099a7a97570c9698d4f2337060" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive 0.3.3", + "num-traits", + "num_enum 0.6.1", + "solana-program", + "thiserror", +] + +[[package]] +name = "spl-token-2022" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d697fac19fd74ff472dfcc13f0b442dd71403178ce1de7b5d16f83a33561c059" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive 0.4.2", + "num-traits", + "num_enum 0.7.3", + "solana-program", + "solana-security-txt", + "solana-zk-token-sdk", + "spl-memo", + "spl-pod", + "spl-token", + "spl-token-group-interface", + "spl-token-metadata-interface", + "spl-transfer-hook-interface", + "spl-type-length-value", + "thiserror", +] + +[[package]] +name = "spl-token-group-interface" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b889509d49fa74a4a033ca5dae6c2307e9e918122d97e58562f5c4ffa795c75d" +dependencies = [ + "bytemuck", + "solana-program", + "spl-discriminator", + "spl-pod", + "spl-program-error", +] + +[[package]] +name = "spl-token-metadata-interface" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c16ce3ba6979645fb7627aa1e435576172dd63088dc7848cb09aa331fa1fe4f" +dependencies = [ + "borsh 0.10.4", + "solana-program", + "spl-discriminator", + "spl-pod", + "spl-program-error", + "spl-type-length-value", +] + +[[package]] +name = "spl-transfer-hook-interface" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aabdb7c471566f6ddcee724beb8618449ea24b399e58d464d6b5bc7db550259" +dependencies = [ + "arrayref", + "bytemuck", + "solana-program", + "spl-discriminator", + "spl-pod", + "spl-program-error", + "spl-tlv-account-resolution", + "spl-type-length-value", +] + +[[package]] +name = "spl-type-length-value" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a468e6f6371f9c69aae760186ea9f1a01c2908351b06a5e0026d21cfc4d7ecac" +dependencies = [ + "bytemuck", + "solana-program", + "spl-discriminator", + "spl-pod", + "spl-program-error", +] + +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01680f5d178a369f817f43f3d399650272873a8e7588a7872f7e90edc71d60a3" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn_derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.83", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "unicode-xid", +] + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" +dependencies = [ + "cfg-if", + "fastrand", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "textwrap" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" + +[[package]] +name = "thiserror" +version = "1.0.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.83", +] + +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tiny-bip39" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffc59cb9dfc85bb312c3a78fd6aa8a8582e310b0fa885d5bb877f6dcc601839d" +dependencies = [ + "anyhow", + "hmac 0.8.1", + "once_cell", + "pbkdf2 0.4.0", + "rand 0.7.3", + "rustc-hash", + "sha2 0.9.9", + "thiserror", + "unicode-normalization", + "wasm-bindgen", + "zeroize", +] + +[[package]] +name = "tinyvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "145f3413504347a2be84393cc8a7d2fb4d863b375909ea59f2158261aa258bbb" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-macros" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.83", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" +dependencies = [ + "futures-util", + "log", + "rustls", + "tokio", + "tokio-rustls", + "tungstenite", + "webpki-roots 0.25.4", +] + +[[package]] +name = "tokio-util" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.6.0", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.22.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +dependencies = [ + "indexmap 2.6.0", + "toml_datetime", + "winnow 0.6.20", +] + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.83", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand 0.8.5", + "rustls", + "sha1", + "thiserror", + "url", + "utf-8", + "webpki-roots 0.24.0", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-bidi" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "unicode-normalization" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "universal-hash" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "unreachable" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" +dependencies = [ + "void", +] + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "uriparse" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0200d0fc04d809396c2ad43f3c95da3582a2556eba8d453c1087f4120ee352ff" +dependencies = [ + "fnv", + "lazy_static", +] + +[[package]] +name = "url" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "uuid" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.83", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.83", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" + +[[package]] +name = "web-sys" +version = "0.3.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b291546d5d9d1eab74f069c77749f2cb8504a12caa20f0f2de93ddbf6f411888" +dependencies = [ + "rustls-webpki", +] + +[[package]] +name = "webpki-roots" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "x509-parser" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0ecbeb7b67ce215e40e3cc7f2ff902f94a223acf44995934763467e7b1febc8" +dependencies = [ + "asn1-rs", + "base64 0.13.1", + "data-encoding", + "der-parser", + "lazy_static", + "nom", + "oid-registry", + "rusticata-macros", + "thiserror", + "time", +] + +[[package]] +name = "yasna" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +dependencies = [ + "time", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.83", +] + +[[package]] +name = "zeroize" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.83", +] + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.13+zstd.1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..84471d4 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "mev-bot-solana" +version = "0.1.0" +edition = "2021" + +[dependencies] +solana-client = "1.7.11" +solana-sdk = "1.7.11" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +tokio = { version = "1.14", features = ["full"] } +reqwest = { version = "0.11", features = ["json"] } +anyhow = "1.0" +thiserror = "1.0" +log = "0.4" +env_logger = "0.9" +toml = "0.5" +rust_decimal = "1.14" +rust_decimal_macros = "1.14" \ No newline at end of file diff --git a/ChangeLog b/ChangeLog deleted file mode 100644 index e69de29..0000000 diff --git a/INSTALL b/INSTALL deleted file mode 100644 index e69de29..0000000 diff --git a/Makefile.am b/Makefile.am deleted file mode 100644 index 976a54a..0000000 --- a/Makefile.am +++ /dev/null @@ -1,6 +0,0 @@ -lib_LTLIBRARIES=libwsclient.la -libwsclient_la_SOURCES = wsclient.c base64.c sha1.c -library_includedir=$(includedir)/wsclient -library_include_HEADERS = wsclient.h config.h -AM_LDFLAGS = -lpthread -ACLOCAL_AMFLAGS = -I m4 diff --git a/NEWS b/NEWS deleted file mode 100644 index e69de29..0000000 diff --git a/README b/README deleted file mode 100644 index e69de29..0000000 diff --git a/README.md b/README.md index 9557f74..af84695 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,15 @@ -libwsclient -=========== +# Solana MEV Bot +A sophisticated MEV (Maximal Extractable Value) bot built for the Solana blockchain, designed to capture value through various arbitrage strategies and market inefficiencies. -WebSocket client library for C - -This library abstracts away WebSocket protocol framing for -client connections. It aims to provide a *somewhat* similar -API to the implementation in your browser. You create a new -client context and create callbacks to be triggered when -certain events occur (onopen, onmessage, onclose, onerror). - -Your best bet for getting started is to look at test.c which shows -how to connect to an echo server using libwsclient calls. - -Also, to install: - -./autogen.sh - -./configure && make && sudo make install - -Then link your C program against wsclient: 'gcc -g -O2 -o test test.c -lwsclient' +## Overview +This MEV bot implements multiple strategies to extract value from the Solana blockchain, including: +- Cross-DEX arbitrage +- Sandwich trading +- Just-In-Time (JIT) liquidity +- MEV-Share bundle submissions +- Copy trading +- Token sniping +## Architecture diff --git a/api/flipside.rs b/api/flipside.rs new file mode 100644 index 0000000..bfe24d3 --- /dev/null +++ b/api/flipside.rs @@ -0,0 +1,26 @@ +pub struct FlipsideApi { + pub api_key: String, + pub api_url: String, +} + +impl FlipsideApi { + pub fn new(api_key: String, api_url: String) -> Self { + FlipsideApi { + api_key, + api_url, + } + } + + pub async fn get_token_volume(&self, token_mint: &str) -> Result { + let url = format!("{}/volume?token_mint={}", self.api_url, token_mint); + let client = reqwest::Client::new(); + let response = client + .get(&url) + .header("Authorization", &self.api_key) + .send() + .await?; + + let volume: f64 = response.json().await?; + Ok(volume) + } +} \ No newline at end of file diff --git a/api/mod.rs b/api/mod.rs new file mode 100644 index 0000000..f9d33ee --- /dev/null +++ b/api/mod.rs @@ -0,0 +1,3 @@ +pub mod parsec; +pub mod flipside; +pub mod thegraph; \ No newline at end of file diff --git a/api/parsec.rs b/api/parsec.rs new file mode 100644 index 0000000..d7abf9f --- /dev/null +++ b/api/parsec.rs @@ -0,0 +1,26 @@ +pub struct ParsecApi { + pub api_key: String, + pub api_url: String, +} + +impl ParsecApi { + pub fn new(api_key: String, api_url: String) -> Self { + ParsecApi { + api_key, + api_url, + } + } + + pub async fn get_token_prices(&self) -> Result, reqwest::Error> { + let url = format!("{}/prices", self.api_url); + let client = reqwest::Client::new(); + let response = client + .get(&url) + .header("Authorization", &self.api_key) + .send() + .await?; + + let prices: HashMap = response.json().await?; + Ok(prices) + } +} \ No newline at end of file diff --git a/api/telegraph.rs b/api/telegraph.rs new file mode 100644 index 0000000..978a295 --- /dev/null +++ b/api/telegraph.rs @@ -0,0 +1,35 @@ +pub struct TheGraphApi { + pub api_url: String, +} + +impl TheGraphApi { + pub fn new(api_url: String) -> Self { + TheGraphApi { + api_url, + } + } + + pub async fn get_trader_transactions(&self, trader_account: &str) -> Result, reqwest::Error> { + let query = format!("{{ traderTransactions(trader: \"{}\") {{ id tokenAmount tokenMint }} }}", trader_account); + let client = reqwest::Client::new(); + let response = client + .post(&self.api_url) + .json(&serde_json::json!({ "query": query })) + .send() + .await?; + + let result: serde_json::Value = response.json().await?; + let transactions = result["data"]["traderTransactions"] + .as_array() + .unwrap() + .iter() + .map(|trade| crate::models::trade::Trade { + id: trade["id"].as_str().unwrap().to_string(), + token_amount: trade["tokenAmount"].as_f64().unwrap(), + token_mint: trade["tokenMint"].as_str().unwrap().to_string(), + }) + .collect(); + + Ok(transactions) + } +} \ No newline at end of file diff --git a/autogen.sh b/autogen.sh deleted file mode 100755 index deae53b..0000000 --- a/autogen.sh +++ /dev/null @@ -1,5 +0,0 @@ -#! /bin/sh -libtoolize -aclocal \ -&& automake --add-missing \ -&& autoconf diff --git a/base64.c b/base64.c deleted file mode 100644 index d2f5c10..0000000 --- a/base64.c +++ /dev/null @@ -1,215 +0,0 @@ -#include -#include -#include - - - -/** - * characters used for Base64 encoding - */ -const char *BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -/** - * encode three bytes using base64 (RFC 3548) - * - * @param triple three bytes that should be encoded - * @param result buffer of four characters where the result is stored - */ -void _base64_encode_triple(unsigned char triple[3], char result[4]) - { - int tripleValue, i; - - tripleValue = triple[0]; - tripleValue *= 256; - tripleValue += triple[1]; - tripleValue *= 256; - tripleValue += triple[2]; - - for (i=0; i<4; i++) - { - result[3-i] = BASE64_CHARS[tripleValue%64]; - tripleValue /= 64; - } -} - -/** - * encode an array of bytes using Base64 (RFC 3548) - * - * @param source the source buffer - * @param sourcelen the length of the source buffer - * @param target the target buffer - * @param targetlen the length of the target buffer - * @return 1 on success, 0 otherwise - */ -int base64_encode(unsigned char *source, size_t sourcelen, char *target, size_t targetlen) - { - /* check if the result will fit in the target buffer */ - if ((sourcelen+2)/3*4 > targetlen-1) - return 0; - - /* encode all full triples */ - while (sourcelen >= 3) - { - _base64_encode_triple(source, target); - sourcelen -= 3; - source += 3; - target += 4; - } - - /* encode the last one or two characters */ - if (sourcelen > 0) - { - unsigned char temp[3]; - memset(temp, 0, sizeof(temp)); - memcpy(temp, source, sourcelen); - _base64_encode_triple(temp, target); - target[3] = '='; - if (sourcelen == 1) - target[2] = '='; - - target += 4; - } - - /* terminate the string */ - target[0] = 0; - - return 1; -} - -/** - * determine the value of a base64 encoding character - * - * @param base64char the character of which the value is searched - * @return the value in case of success (0-63), -1 on failure - */ -int _base64_char_value(char base64char) - { - if (base64char >= 'A' && base64char <= 'Z') - return base64char-'A'; - if (base64char >= 'a' && base64char <= 'z') - return base64char-'a'+26; - if (base64char >= '0' && base64char <= '9') - return base64char-'0'+2*26; - if (base64char == '+') - return 2*26+10; - if (base64char == '/') - return 2*26+11; - return -1; -} - -/** - * decode a 4 char base64 encoded byte triple - * - * @param quadruple the 4 characters that should be decoded - * @param result the decoded data - * @return lenth of the result (1, 2 or 3), 0 on failure - */ -int _base64_decode_triple(char quadruple[4], unsigned char *result) - { - int i, triple_value, bytes_to_decode = 3, only_equals_yet = 1; - int char_value[4]; - - for (i=0; i<4; i++) - char_value[i] = _base64_char_value(quadruple[i]); - - /* check if the characters are valid */ - for (i=3; i>=0; i--) - { - if (char_value[i]<0) - { - if (only_equals_yet && quadruple[i]=='=') - { - /* we will ignore this character anyway, make it something - * that does not break our calculations */ - char_value[i]=0; - bytes_to_decode--; - continue; - } - return 0; - } - /* after we got a real character, no other '=' are allowed anymore */ - only_equals_yet = 0; - } - - /* if we got "====" as input, bytes_to_decode is -1 */ - if (bytes_to_decode < 0) - bytes_to_decode = 0; - - /* make one big value out of the partial values */ - triple_value = char_value[0]; - triple_value *= 64; - triple_value += char_value[1]; - triple_value *= 64; - triple_value += char_value[2]; - triple_value *= 64; - triple_value += char_value[3]; - - /* break the big value into bytes */ - for (i=bytes_to_decode; i<3; i++) - triple_value /= 256; - for (i=bytes_to_decode-1; i>=0; i--) - { - result[i] = triple_value%256; - triple_value /= 256; - } - - return bytes_to_decode; -} - -/** - * decode base64 encoded data - * - * @param source the encoded data (zero terminated) - * @param target pointer to the target buffer - * @param targetlen length of the target buffer - * @return length of converted data on success, -1 otherwise - */ -size_t base64_decode(char *source, unsigned char *target, size_t targetlen) - { - char *src, *tmpptr; - char quadruple[4], tmpresult[3]; - int i, tmplen = 3; - size_t converted = 0; - - /* concatinate '===' to the source to handle unpadded base64 data */ - src = (char *)malloc(strlen(source)+5); - if (src == NULL) - return -1; - strcpy(src, source); - strcat(src, "===="); - tmpptr = src; - - /* convert as long as we get a full result */ - while (tmplen == 3) - { - /* get 4 characters to convert */ - for (i=0; i<4; i++) - { - /* skip invalid characters - we won't reach the end */ - while (*tmpptr != '=' && _base64_char_value(*tmpptr)<0) - tmpptr++; - - quadruple[i] = *(tmpptr++); - } - - /* convert the characters */ - tmplen = _base64_decode_triple(quadruple, tmpresult); - - /* check if the fit in the result buffer */ - if (targetlen < tmplen) - { - free(src); - return -1; - } - - /* put the partial result in the result buffer */ - memcpy(target, tmpresult, tmplen); - target += tmplen; - targetlen -= tmplen; - converted += tmplen; - } - - free(src); - return converted; -} - diff --git a/bot/copy_trade_manager.rs b/bot/copy_trade_manager.rs new file mode 100644 index 0000000..b2e19dd --- /dev/null +++ b/bot/copy_trade_manager.rs @@ -0,0 +1,71 @@ +use crate::models::market_conditions::MarketConditions; +use crate::models::mev_opportunity::MevOpportunity; +use solana_client::rpc_client::RpcClient; +use solana_sdk::pubkey::Pubkey; +use std::collections::HashMap; + +pub struct CopyTradeManager { + rpc_client: RpcClient, + target_accounts: HashMap, +} + +impl CopyTradeManager { + pub fn new(rpc_client: RpcClient) -> Self { + Self { + rpc_client, + target_accounts: HashMap::new(), + } + } + + pub fn update(&mut self, market_conditions: &MarketConditions) { + self.update_target_accounts(market_conditions); + } + + pub async fn find_opportunities(&self) -> Vec { + let mut opportunities = Vec::new(); + for (account, balance) in &self.target_accounts { + if *balance >= 1000.0 { + let opportunity = self.find_copy_trade_opportunity(account).await; + if let Some(opp) = opportunity { + opportunities.push(opp); + } + } + } + opportunities + } + + fn update_target_accounts(&mut self, market_conditions: &MarketConditions) { + for (account, balance) in &market_conditions.account_balances { + self.target_accounts.insert(*account, *balance); + } + } + + async fn find_copy_trade_opportunity(&self, account: &Pubkey) -> Option { + let recent_trades = self.get_recent_trades(account).await; + if let Some(profitable_trade) = self.find_profitable_trade(recent_trades) { + let copy_trade_transactions = self.create_copy_trade_transactions(&profitable_trade); + let mev_opportunity = MevOpportunity { + transactions: copy_trade_transactions, + min_profit: 0.01, + }; + Some(mev_opportunity) + } else { + None + } + } + + async fn get_recent_trades(&self, account: &Pubkey) -> Vec { + let trades = Vec::new(); + trades + } + + fn find_profitable_trade(&self, trades: Vec) -> Option { + let profitable_trade = None; + profitable_trade + } + + fn create_copy_trade_transactions(&self, trade: &solana_transaction::Transaction) -> Vec<(solana_sdk::transaction::Transaction, f64)> { + let copy_trade_txs = Vec::new(); + copy_trade_txs + } +} \ No newline at end of file diff --git a/bot/cross_chain_manager.rs b/bot/cross_chain_manager.rs new file mode 100644 index 0000000..b977921 --- /dev/null +++ b/bot/cross_chain_manager.rs @@ -0,0 +1,17 @@ +use crate::models::market_conditions::MarketConditions; +use crate::models::mev_opportunity::MevOpportunity; + +pub struct CrossChainManager {} + +impl CrossChainManager { + pub fn new(_rpc_client: solana_client::rpc_client::RpcClient) -> Self { + Self {} + } + + pub fn update(&mut self, _market_conditions: &MarketConditions) {} + + pub async fn find_opportunities(&self) -> Vec { + let opportunities = Vec::new(); + opportunities + } +} \ No newline at end of file diff --git a/bot/flashbot_client.rs b/bot/flashbot_client.rs new file mode 100644 index 0000000..d92e5d6 --- /dev/null +++ b/bot/flashbot_client.rs @@ -0,0 +1,20 @@ +use crate::utils::solana::send_transaction; +use solana_client::rpc_client::RpcClient; +use solana_sdk::transaction::Transaction; + +pub struct FlashbotsClient { + rpc_client: RpcClient, +} + +impl FlashbotsClient { + pub fn new(rpc_client: RpcClient) -> Self { + Self { rpc_client } + } + + pub async fn send_bundle(&self, txs: &[Transaction]) -> Result<(), Box> { + for tx in txs { + send_transaction(&self.rpc_client, tx).await?; + } + Ok(()) + } +} \ No newline at end of file diff --git a/bot/gas_optimizer.rs b/bot/gas_optimizer.rs new file mode 100644 index 0000000..878b163 --- /dev/null +++ b/bot/gas_optimizer.rs @@ -0,0 +1,16 @@ +use solana_sdk::transaction::Transaction; + +pub struct GasOptimizer {} + +impl GasOptimizer { + pub fn new(_rpc_client: solana_client::rpc_client::RpcClient) -> Self { + Self {} + } + + pub fn update(&mut self, _market_conditions: &crate::models::market_conditions::MarketConditions) {} + + pub async fn optimize(&self, txs: &[Transaction]) -> Vec { + let optimized_txs = txs.to_vec(); + optimized_txs + } +} \ No newline at end of file diff --git a/bot/market_analyzer.rs b/bot/market_analyzer.rs new file mode 100644 index 0000000..354cc4c --- /dev/null +++ b/bot/market_analyzer.rs @@ -0,0 +1,35 @@ +use crate::models::market_conditions::MarketConditions; +use solana_client::rpc_client::RpcClient; + +pub struct MarketAnalyzer { + rpc_client: RpcClient, +} + +impl MarketAnalyzer { + pub fn new(rpc_client: RpcClient) -> Self { + Self { rpc_client } + } + + pub async fn analyze(&self) -> MarketConditions { + MarketConditions { + liquidity: self.calculate_liquidity().await, + volume: self.calculate_volume().await, + volatility: self.calculate_volatility().await, + } + } + + async fn calculate_liquidity(&self) -> f64 { + let liquidity = 1000000.0; + liquidity + } + + async fn calculate_volume(&self) -> f64 { + let volume = 500000.0; + volume + } + + async fn calculate_volatility(&self) -> f64 { + let volatility = 0.02; + volatility + } +} \ No newline at end of file diff --git a/bot/mod.rs b/bot/mod.rs new file mode 100644 index 0000000..e2bb4af --- /dev/null +++ b/bot/mod.rs @@ -0,0 +1,15 @@ +pub mod solana_mev_bot; +pub mod flashbots_client; +pub mod simulation_engine; +pub mod optimizer; +pub mod risk_manager; +pub mod market_analyzer; +pub mod strategy_manager; +pub mod monitoring_manager; +pub mod copy_trade_manager; +pub mod sniping_manager; +pub mod gas_optimizer; +pub mod path_finder; +pub mod trade_executor; +pub mod cross_chain_manager; +pub mod order_manager; \ No newline at end of file diff --git a/bot/monitoring_manager.rs b/bot/monitoring_manager.rs new file mode 100644 index 0000000..6765a22 --- /dev/null +++ b/bot/monitoring_manager.rs @@ -0,0 +1,50 @@ +use crate::models::market_conditions::MarketConditions; +use crate::models::transaction_log::TransactionLog; +use solana_client::rpc_client::RpcClient; +use solana_sdk::transaction::Transaction; + +pub struct MonitoringManager { + rpc_client: RpcClient, + transaction_logs: Vec, +} + +impl MonitoringManager { + pub fn new(rpc_client: RpcClient) -> Self { + Self { + rpc_client, + transaction_logs: Vec::new(), + } + } + + pub fn log_and_monitor(&mut self, txs: &[Transaction], market_conditions: &MarketConditions) { + for tx in txs { + let log = TransactionLog { + signature: tx.signatures[0].to_string(), + market_conditions: market_conditions.clone(), + }; + self.transaction_logs.push(log); + } + self.monitor_performance(); + } + + fn monitor_performance(&self) { + let num_transactions = self.transaction_logs.len(); + let total_profit = self.calculate_total_profit(); + println!("Number of transactions: {}", num_transactions); + println!("Total profit: {}", total_profit); + } + + fn calculate_total_profit(&self) -> f64 { + let mut total_profit = 0.0; + for log in &self.transaction_logs { + let profit = self.calculate_transaction_profit(&log.signature); + total_profit += profit; + } + total_profit + } + + fn calculate_transaction_profit(&self, signature: &str) -> f64 { + let profit = 100.0; + profit + } +} \ No newline at end of file diff --git a/bot/optimizer.rs b/bot/optimizer.rs new file mode 100644 index 0000000..d38e9a1 --- /dev/null +++ b/bot/optimizer.rs @@ -0,0 +1,23 @@ +use crate::models::mev_opportunity::MevOpportunity; +use solana_client::rpc_client::RpcClient; +use solana_sdk::transaction::Transaction; + +pub struct Optimizer { + rpc_client: RpcClient, +} + +impl Optimizer { + pub fn new(rpc_client: RpcClient) -> Self { + Self { rpc_client } + } + + pub async fn optimize(&self, opportunity: &MevOpportunity) -> Vec { + let mut optimized_txs = Vec::new(); + for (tx, profit) in &opportunity.transactions { + if *profit >= opportunity.min_profit { + optimized_txs.push(tx.clone()); + } + } + optimized_txs + } +} \ No newline at end of file diff --git a/bot/order_manager.rs b/bot/order_manager.rs new file mode 100644 index 0000000..3f9fd4d --- /dev/null +++ b/bot/order_manager.rs @@ -0,0 +1,13 @@ +use solana_sdk::transaction::Transaction; + +pub struct OrderManager {} + +impl OrderManager { + pub fn new(_rpc_client: solana_client::rpc_client::RpcClient) -> Self { + Self {} + } + + pub fn update(&mut self, _market_conditions: &crate::models::market_conditions::MarketConditions) {} + + pub async fn manage_orders(&self, _executed_txs: &[Transaction]) {} +} \ No newline at end of file diff --git a/bot/path_finder.rs b/bot/path_finder.rs new file mode 100644 index 0000000..730a002 --- /dev/null +++ b/bot/path_finder.rs @@ -0,0 +1,18 @@ +use crate::models::mev_opportunity::MevOpportunity; +use solana_sdk::pubkey::Pubkey; +use std::collections::HashMap; + +pub struct PathFinder {} + +impl PathFinder { + pub fn new(_rpc_client: solana_client::rpc_client::RpcClient) -> Self { + Self {} + } + + pub fn update(&mut self, _market_conditions: &crate::models::market_conditions::MarketConditions) {} + + pub async fn find_opportunities(&self, _target_accounts: &HashMap) -> Vec { + let opportunities = Vec::new(); + opportunities + } +} \ No newline at end of file diff --git a/bot/risk_manager.rs b/bot/risk_manager.rs new file mode 100644 index 0000000..aff1d93 --- /dev/null +++ b/bot/risk_manager.rs @@ -0,0 +1,52 @@ +use solana_client::rpc_client::RpcClient; +use solana_sdk::transaction::Transaction; + +pub struct RiskManager { + rpc_client: RpcClient, + max_capital_per_trade: f64, + max_slippage: f64, +} + +impl RiskManager { + pub fn new(rpc_client: RpcClient) -> Self { + Self { + rpc_client, + max_capital_per_trade: 1000.0, + max_slippage: 0.05, + } + } + + pub fn update(&mut self, max_capital_per_trade: f64, max_slippage: f64) { + self.max_capital_per_trade = max_capital_per_trade; + self.max_slippage = max_slippage; + } + + pub async fn is_safe(&self, tx: &Transaction) -> bool { + let tx_cost = self.calculate_tx_cost(tx).await; + tx_cost <= self.max_capital_per_trade && self.calculate_slippage(tx).await <= self.max_slippage + } + + async fn calculate_tx_cost(&self, tx: &Transaction) -> f64 { + let (result, _) = self.rpc_client.simulate_transaction(tx).await.unwrap(); + let accounts_data = result.accounts.unwrap(); + let mut cost = 0.0; + for account in &accounts_data { + let lamports = account.lamports.unwrap(); + cost += lamports as f64 / 1e9; + } + cost + } + + async fn calculate_slippage(&self, tx: &Transaction) -> f64 { + let (result, _) = self.rpc_client.simulate_transaction(tx).await.unwrap(); + let accounts_data = result.accounts.unwrap(); + let mut balance_changes = Vec::new(); + for account in &accounts_data { + let lamports = account.lamports.unwrap(); + balance_changes.push(lamports as f64 / 1e9); + } + let max_balance_change = balance_changes.iter().cloned().fold(0.0 / 0.0, f64::max); + let min_balance_change = balance_changes.iter().cloned().fold(0.0 / 0.0, f64::min); + (max_balance_change - min_balance_change) / min_balance_change + } +} \ No newline at end of file diff --git a/bot/simulation_engine b/bot/simulation_engine new file mode 100644 index 0000000..4c61f81 --- /dev/null +++ b/bot/simulation_engine @@ -0,0 +1,23 @@ +use solana_client::rpc_client::RpcClient; +use solana_sdk::transaction::Transaction; + +pub struct SimulationEngine { + rpc_client: RpcClient, +} + +impl SimulationEngine { + pub fn new(rpc_client: RpcClient) -> Self { + Self { rpc_client } + } + + pub async fn simulate(&self, tx: &Transaction) -> f64 { + let (result, _) = self.rpc_client.simulate_transaction(tx).await.unwrap(); + let accounts_data = result.accounts.unwrap(); + let mut profit = 0.0; + for account in &accounts_data { + let lamports = account.lamports.unwrap(); + profit += lamports as f64 / 1e9; + } + profit + } +} \ No newline at end of file diff --git a/bot/sniping_manager.rs b/bot/sniping_manager.rs new file mode 100644 index 0000000..4b77234 --- /dev/null +++ b/bot/sniping_manager.rs @@ -0,0 +1,71 @@ +use crate::models::market_conditions::MarketConditions; +use crate::models::mev_opportunity::MevOpportunity; +use solana_client::rpc_client::RpcClient; +use solana_sdk::pubkey::Pubkey; +use std::collections::HashMap; + +pub struct SnipingManager { + rpc_client: RpcClient, + target_accounts: HashMap, +} + +impl SnipingManager { + pub fn new(rpc_client: RpcClient) -> Self { + Self { + rpc_client, + target_accounts: HashMap::new(), + } + } + + pub fn update(&mut self, market_conditions: &MarketConditions) { + self.update_target_accounts(market_conditions); + } + + pub async fn find_opportunities(&self) -> Vec { + let mut opportunities = Vec::new(); + for (account, balance) in &self.target_accounts { + if *balance >= 1000.0 { + let opportunity = self.find_sniping_opportunity(account).await; + if let Some(opp) = opportunity { + opportunities.push(opp); + } + } + } + opportunities + } + + fn update_target_accounts(&mut self, market_conditions: &MarketConditions) { + for (account, balance) in &market_conditions.account_balances { + self.target_accounts.insert(*account, *balance); + } + } + + async fn find_sniping_opportunity(&self, account: &Pubkey) -> Option { + let mempool_transactions = self.get_mempool_transactions().await; + if let Some(profitable_tx) = self.find_profitable_transaction(mempool_transactions) { + let sniping_transactions = self.create_sniping_transactions(&profitable_tx); + let mev_opportunity = MevOpportunity { + transactions: sniping_transactions, + min_profit: 0.01, + }; + Some(mev_opportunity) + } else { + None + } + } + + async fn get_mempool_transactions(&self) -> Vec { + let transactions = Vec::new(); + transactions + } + + fn find_profitable_transaction(&self, transactions: Vec) -> Option { + let profitable_tx = None; + profitable_tx + } + + fn create_sniping_transactions(&self, transaction: &solana_transaction::Transaction) -> Vec<(solana_sdk::transaction::Transaction, f64)> { + let sniping_txs = Vec::new(); + sniping_txs + } +} \ No newline at end of file diff --git a/bot/solana_mev_bot.rs b/bot/solana_mev_bot.rs new file mode 100644 index 0000000..f2b8617 --- /dev/null +++ b/bot/solana_mev_bot.rs @@ -0,0 +1,157 @@ +use crate::dex::dex_integration::DexIntegration; +use crate::models::market_conditions::MarketConditions; +use crate::models::mev_opportunity::MevOpportunity; +use crate::models::transaction_log::TransactionLog; +use crate::strategies::strategy::Strategy; +use solana_client::rpc_client::RpcClient; +use solana_sdk::pubkey::Pubkey; +use solana_sdk::signature::Keypair; +use solana_sdk::transaction::Transaction; +use std::collections::HashMap; +use std::sync::Arc; +use tokio::sync::Mutex; + +pub struct SolanaMevBot { + rpc_client: RpcClient, + payer_keypair: Keypair, + target_accounts: HashMap, + profit_threshold: f64, + dex_integrations: Vec>, + flashbots_client: Arc>, + simulation_engine: Arc>, + optimizer: Arc>, + risk_manager: Arc>, + market_analyzer: Arc>, + strategy_manager: Arc>, + monitoring_manager: Arc>, + copy_trade_manager: Arc>, + sniping_manager: Arc>, + gas_optimizer: Arc>, + path_finder: Arc>, + trade_executor: Arc>, + cross_chain_manager: Arc>, + order_manager: Arc>, +} + +impl SolanaMevBot { + pub async fn new( + rpc_url: &str, + payer_keypair: Keypair, + target_accounts: HashMap, + profit_threshold: f64, + dex_integrations: Vec>, + ) -> Self { + let rpc_client = RpcClient::new(rpc_url.to_string()); + let flashbots_client = Arc::new(Mutex::new(FlashbotsClient::new(rpc_client.clone()))); + let simulation_engine = Arc::new(Mutex::new(SimulationEngine::new(rpc_client.clone()))); + let optimizer = Arc::new(Mutex::new(Optimizer::new(rpc_client.clone()))); + let risk_manager = Arc::new(Mutex::new(RiskManager::new(rpc_client.clone()))); + let market_analyzer = Arc::new(Mutex::new(MarketAnalyzer::new(rpc_client.clone()))); + let strategy_manager = Arc::new(Mutex::new(StrategyManager::new(rpc_client.clone(), dex_integrations.clone()))); + let monitoring_manager = Arc::new(Mutex::new(MonitoringManager::new(rpc_client.clone()))); + let copy_trade_manager = Arc::new(Mutex::new(CopyTradeManager::new(rpc_client.clone()))); + let sniping_manager = Arc::new(Mutex::new(SnipingManager::new(rpc_client.clone()))); + let gas_optimizer = Arc::new(Mutex::new(GasOptimizer::new(rpc_client.clone()))); + let path_finder = Arc::new(Mutex::new(PathFinder::new(rpc_client.clone()))); + let trade_executor = Arc::new(Mutex::new(TradeExecutor::new(rpc_client.clone()))); + let cross_chain_manager = Arc::new(Mutex::new(CrossChainManager::new(rpc_client.clone()))); + let order_manager = Arc::new(Mutex::new(OrderManager::new(rpc_client.clone()))); + + SolanaMevBot { + rpc_client, + payer_keypair, + target_accounts, + profit_threshold, + dex_integrations, + flashbots_client, + simulation_engine, + optimizer, + risk_manager, + market_analyzer, + strategy_manager, + monitoring_manager, + copy_trade_manager, + sniping_manager, + gas_optimizer, + path_finder, + trade_executor, + cross_chain_manager, + order_manager, + } + } + + pub async fn run(&mut self) { + loop { + let market_conditions = self.market_analyzer.lock().await.analyze().await; + self.strategy_manager.lock().await.update(&market_conditions); + self.risk_manager.lock().await.update(&market_conditions); + self.copy_trade_manager.lock().await.update(&market_conditions); + self.sniping_manager.lock().await.update(&market_conditions); + self.gas_optimizer.lock().await.update(&market_conditions); + self.path_finder.lock().await.update(&market_conditions); + self.cross_chain_manager.lock().await.update(&market_conditions); + self.order_manager.lock().await.update(&market_conditions); + + let opportunities = self.find_opportunities().await; + let mut all_opportunities = Vec::new(); + all_opportunities.extend(opportunities); + + let copy_trade_opportunities = self.copy_trade_manager.lock().await.find_opportunities().await; + all_opportunities.extend(copy_trade_opportunities); + + let sniping_opportunities = self.sniping_manager.lock().await.find_opportunities().await; + all_opportunities.extend(sniping_opportunities); + + let cross_chain_opportunities = self.cross_chain_manager.lock().await.find_opportunities().await; + all_opportunities.extend(cross_chain_opportunities); + + let profitable_txns = self.optimize_and_filter_txns(&all_opportunities).await; + let gas_optimized_txns = self.gas_optimizer.lock().await.optimize(&profitable_txns).await; + + let executed_txns = self.trade_executor.lock().await.execute_transactions(&gas_optimized_txns).await; + self.monitoring_manager.lock().await.log_and_monitor(&executed_txns, &market_conditions); + + self.order_manager.lock().await.manage_orders(&executed_txns).await; + + tokio::time::sleep(std::time::Duration::from_millis(500)).await; + } + } + + async fn find_opportunities(&self) -> Vec { + let mut opportunities = Vec::new(); + + for dex_integration in &self.dex_integrations { + let dex_opportunities = dex_integration.find_opportunities( + &self.target_accounts, + &self.market_analyzer, + &self.strategy_manager, + ).await; + opportunities.extend(dex_opportunities); + } + + let path_opportunities = self.path_finder.lock().await.find_opportunities(&self.target_accounts).await; + opportunities.extend(path_opportunities); + + opportunities + } + + async fn optimize_and_filter_txns(&self, opportunities: &[MevOpportunity]) -> Vec { + let mut profitable_txns = Vec::new(); + + for opportunity in opportunities { + let optimized_txns = self.optimizer.lock().await.optimize(opportunity).await; + for tx in &optimized_txns { + if self.risk_manager.lock().await.is_safe(tx).await && self.is_profitable(tx).await { + profitable_txns.push(tx.clone()); + } + } + } + + profitable_txns + } + + async fn is_profitable(&self, tx: &Transaction) -> bool { + let profit = self.simulation_engine.lock().await.simulate(tx).await; + profit >= self.profit_threshold + } +} \ No newline at end of file diff --git a/bot/strategy_manager.rs b/bot/strategy_manager.rs new file mode 100644 index 0000000..0d3ec72 --- /dev/null +++ b/bot/strategy_manager.rs @@ -0,0 +1,42 @@ +use crate::dex::dex_integration::DexIntegration; +use crate::models::market_conditions::MarketConditions; +use crate::models::mev_opportunity::MevOpportunity; +use crate::strategies::strategy::Strategy; +use solana_client::rpc_client::RpcClient; +use std::collections::HashMap; +use solana_sdk::pubkey::Pubkey; + +pub struct StrategyManager { + rpc_client: RpcClient, + strategies: Vec>, + dex_integrations: Vec>, +} + +impl StrategyManager { + pub fn new(rpc_client: RpcClient, dex_integrations: Vec>) -> Self { + Self { + rpc_client, + strategies: Vec::new(), + dex_integrations, + } + } + + pub fn update(&mut self, market_conditions: &MarketConditions) { + for strategy in &mut self.strategies { + strategy.update(market_conditions); + } + } + + pub fn add_strategy(&mut self, strategy: impl Strategy + 'static) { + self.strategies.push(Box::new(strategy)); + } + + pub async fn find_opportunities(&self, target_accounts: &HashMap) -> Vec { + let mut opportunities = Vec::new(); + for strategy in &self.strategies { + let strategy_opportunities = strategy.find_opportunities(target_accounts).await; + opportunities.extend(strategy_opportunities); + } + opportunities + } +} \ No newline at end of file diff --git a/bot/trade_executor.rs b/bot/trade_executor.rs new file mode 100644 index 0000000..aa868cb --- /dev/null +++ b/bot/trade_executor.rs @@ -0,0 +1,14 @@ +use solana_sdk::transaction::Transaction; + +pub struct TradeExecutor {} + +impl TradeExecutor { + pub fn new(_rpc_client: solana_client::rpc_client::RpcClient) -> Self { + Self {} + } + + pub async fn execute_transactions(&self, txs: &[Transaction]) -> Vec { + let executed_txs = txs.to_vec(); + executed_txs + } +} \ No newline at end of file diff --git a/config.guess b/config.guess deleted file mode 120000 index 405bc32..0000000 --- a/config.guess +++ /dev/null @@ -1 +0,0 @@ -/usr/share/automake-1.11/config.guess \ No newline at end of file diff --git a/config.h.in b/config.h.in deleted file mode 100644 index be7ba63..0000000 --- a/config.h.in +++ /dev/null @@ -1,124 +0,0 @@ -/* config.h.in. Generated from configure.ac by autoheader. */ - -/* Define to 1 if you have the header file. */ -#undef HAVE_DLFCN_H - -/* Define to 1 if you have the `gettimeofday' function. */ -#undef HAVE_GETTIMEOFDAY - -/* Define to 1 if you have the header file. */ -#undef HAVE_INTTYPES_H - -/* Define to 1 if you have the `pthread' library (-lpthread). */ -#undef HAVE_LIBPTHREAD - -/* Define to 1 if you have the `ssl' library (-lssl). */ -#undef HAVE_LIBSSL - -/* Define to 1 if your system has a GNU libc compatible `malloc' function, and - to 0 otherwise. */ -#undef HAVE_MALLOC - -/* Define to 1 if you have the header file. */ -#undef HAVE_MEMORY_H - -/* Define to 1 if you have the `memset' function. */ -#undef HAVE_MEMSET - -/* Define to 1 if you have the header file. */ -#undef HAVE_NETDB_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_NETINET_IN_H - -/* Define to 1 if your system has a GNU libc compatible `realloc' function, - and to 0 otherwise. */ -#undef HAVE_REALLOC - -/* Define to 1 if you have the `socket' function. */ -#undef HAVE_SOCKET - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDDEF_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDINT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDLIB_H - -/* Define to 1 if you have the `strchr' function. */ -#undef HAVE_STRCHR - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRINGS_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRING_H - -/* Define to 1 if you have the `strstr' function. */ -#undef HAVE_STRSTR - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_SOCKET_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_STAT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_TIME_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_TYPES_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_UNISTD_H - -/* Define to the sub-directory in which libtool stores uninstalled libraries. - */ -#undef LT_OBJDIR - -/* Name of package */ -#undef PACKAGE - -/* Define to the address where bug reports for this package should be sent. */ -#undef PACKAGE_BUGREPORT - -/* Define to the full name of this package. */ -#undef PACKAGE_NAME - -/* Define to the full name and version of this package. */ -#undef PACKAGE_STRING - -/* Define to the one symbol short name of this package. */ -#undef PACKAGE_TARNAME - -/* Define to the home page for this package. */ -#undef PACKAGE_URL - -/* Define to the version of this package. */ -#undef PACKAGE_VERSION - -/* Define to 1 if you have the ANSI C header files. */ -#undef STDC_HEADERS - -/* Version number of package */ -#undef VERSION - -/* Define to `__inline__' or `__inline' if that's what the C compiler - calls it, or to nothing if 'inline' is not supported under any name. */ -#ifndef __cplusplus -#undef inline -#endif - -/* Define to rpl_malloc if the replacement function should be used. */ -#undef malloc - -/* Define to rpl_realloc if the replacement function should be used. */ -#undef realloc - -/* Define to `unsigned int' if does not define. */ -#undef size_t - -/* Define to `int' if does not define. */ -#undef ssize_t diff --git a/config.rs b/config.rs new file mode 100644 index 0000000..8114d6f --- /dev/null +++ b/config.rs @@ -0,0 +1,43 @@ +use serde::Deserialize; +use solana_sdk::pubkey::Pubkey; + +#[derive(Debug, Deserialize, Clone)] +pub struct Config { + pub solana: SolanaConfig, + pub bot: BotConfig, + pub dexes: DexesConfig, + pub monitoring: MonitoringConfig, + pub logging: LoggingConfig, +} + +#[derive(Debug, Deserialize, Clone)] +pub struct SolanaConfig { + pub rpc_url: String, + pub ws_url: String, + pub commitment: String, +} + +#[derive(Debug, Deserialize, Clone)] +pub struct BotConfig { + pub keypair_path: String, + pub profit_threshold: f64, + pub max_position_size: f64, +} + +#[derive(Debug, Deserialize, Clone)] +pub struct DexesConfig { + pub raydium_program_id: Pubkey, + pub serum_program_id: Pubkey, + pub orca_program_id: Pubkey, +} + +#[derive(Debug, Deserialize, Clone)] +pub struct MonitoringConfig { + pub dashboard_port: u16, + pub update_interval: u64, +} + +#[derive(Debug, Deserialize, Clone)] +pub struct LoggingConfig { + pub level: String, +} \ No newline at end of file diff --git a/config.sub b/config.sub deleted file mode 120000 index 4d47fbc..0000000 --- a/config.sub +++ /dev/null @@ -1 +0,0 @@ -/usr/share/automake-1.11/config.sub \ No newline at end of file diff --git a/config.toml b/config.toml new file mode 100644 index 0000000..775cf93 --- /dev/null +++ b/config.toml @@ -0,0 +1,21 @@ +[solana] +rpc_url = "https://api.mainnet-beta.solana.com" +ws_url = "wss://api.mainnet-beta.solana.com" +commitment = "confirmed" + +[bot] +keypair_path = "/path/to/keypair.json" +profit_threshold = 0.01 +max_position_size = 10000.0 + +[dexes] +raydium_program_id = "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R" +serum_program_id = "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin" +orca_program_id = "DjVE6JNiYqPL2QXyCUUh8rNjHrbz9hXHNYt99MQ59qw1" + +[monitoring] +dashboard_port = 8080 +update_interval = 60 + +[logging] +level = "info" \ No newline at end of file diff --git a/configure.ac b/configure.ac deleted file mode 100644 index 14da466..0000000 --- a/configure.ac +++ /dev/null @@ -1,39 +0,0 @@ -# -*- Autoconf -*- -# Process this file with autoconf to produce a configure script. - -AC_PREREQ([2.60]) -AC_INIT([libwsclient], [1.0.1], [payden@paydensutherland.com]) -AM_INIT_AUTOMAKE -LT_INIT([disable-static]) -AC_CONFIG_SRCDIR([wsclient.c]) -AC_CONFIG_HEADERS([config.h]) -AC_CONFIG_MACRO_DIR([m4]) -# Checks for programs. -AC_PROG_CC -AC_PROG_CXX - - - -# Checks for libraries. - -# Checks for header files. -AC_CHECK_HEADERS([netdb.h stdlib.h string.h sys/socket.h unistd.h netinet/in.h stddef.h sys/time.h]) - -AC_C_INLINE -# Checks for typedefs, structures, and compiler characteristics. -AC_TYPE_SIZE_T -AC_TYPE_SSIZE_T - -# Checks for library functions. -AC_FUNC_MALLOC -AC_FUNC_REALLOC -AC_CHECK_FUNCS([memset socket strstr strchr gettimeofday]) -AC_CHECK_LIB(pthread, pthread_create, [], [ - echo "This library requires pthread" - exit -1 - ]) -AC_CHECK_LIB(ssl, SSL_CTX_new, [], [ - echo "OpenSSL not found, building without SSL support" - ]) -AC_CONFIG_FILES([Makefile]) -AC_OUTPUT diff --git a/dex/dex_integration.rs b/dex/dex_integration.rs new file mode 100644 index 0000000..4e45dba --- /dev/null +++ b/dex/dex_integration.rs @@ -0,0 +1,11 @@ +use async_trait::async_trait; +use solana_sdk::pubkey::Pubkey; +use std::collections::HashMap; + +#[async_trait] +pub trait DexIntegration { + async fn get_prices(&self) -> HashMap; + async fn get_account_balances(&self, account: &Pubkey) -> HashMap; + async fn place_order(&self, market: &str, side: &str, size: f64, price: f64) -> Option; + async fn cancel_order(&self, order_id: &str) -> bool; +} \ No newline at end of file diff --git a/dex/mod.rs b/dex/mod.rs new file mode 100644 index 0000000..adf13f8 --- /dev/null +++ b/dex/mod.rs @@ -0,0 +1,4 @@ +pub mod dex_integration; +pub mod raydium; +pub mod serum; +pub mod orca; \ No newline at end of file diff --git a/dex/orca.rs b/dex/orca.rs new file mode 100644 index 0000000..fbba540 --- /dev/null +++ b/dex/orca.rs @@ -0,0 +1,147 @@ +use crate::dex::dex_trait::DexTrait; +use crate::error::Result; +use crate::models::market::Market; +use crate::models::order::{Order, OrderSide, OrderStatus, OrderType}; +use sdk::pubkey::Pubkey; +use sdk::signature::Keypair; +use sdk::signer::Signer; +use sdk::transaction::Transaction; +use solana_client::rpc_client::RpcClient; +use std::collections::HashMap; + +pub struct Orca { + pub rpc_client: RpcClient, + pub program_id: Pubkey, + pub authority: Keypair, +} + +impl Orca { + pub fn new(rpc_client: RpcClient, program_id: Pubkey, authority: Keypair) -> Self { + Orca { + rpc_client, + program_id, + authority, + } + } +} + +#[async_trait] +impl DexTrait for Orca { + async fn get_markets(&self) -> Result> { + let mut markets = Vec::new(); + + let pools = self.rpc_client.get_program_accounts(&self.program_id)?; + + for pool in pools { + let pool_data: PoolData = bincode::deserialize(&pool.account.data)?; + + let market = Market { + address: pool.pubkey, + name: format!("{}/{}", pool_data.token_a.to_string(), pool_data.token_b.to_string()), + base_asset: pool_data.token_a, + quote_asset: pool_data.token_b, + base_decimals: pool_data.token_a_decimals, + quote_decimals: pool_data.token_b_decimals, + }; + markets.push(market); + } + + Ok(markets) + } + + async fn get_orderbook(&self, market: &Market) -> Result<(Vec, Vec)> { + Ok((Vec::new(), Vec::new())) + } + + async fn place_order( + &self, + market: &Market, + order_type: OrderType, + side: OrderSide, + price: f64, + quantity: f64, + ) -> Result { + let pool_data = self.get_pool_data(&market.address).await?; + + let (token_a_amount, token_b_amount) = match side { + OrderSide::Bid => (quantity, quantity * price), + OrderSide::Ask => (quantity / price, quantity), + }; + + let minimum_amount_out = match side { + OrderSide::Bid => token_b_amount * 0.99, + OrderSide::Ask => token_a_amount * 0.99, + }; + + let instruction = orca_swap::instruction::swap( + &self.program_id, + &market.address, + &self.authority.pubkey(), + &pool_data.token_a_account, + &pool_data.token_b_account, + &self.get_token_account(&market.base_asset).await?, + &self.get_token_account(&market.quote_asset).await?, + token_a_amount, + minimum_amount_out, + )?; + + let recent_blockhash = self.rpc_client.get_latest_blockhash()?; + let transaction = Transaction::new_signed_with_payer( + &[instruction], + Some(&self.authority.pubkey()), + &[&self.authority], + recent_blockhash, + ); + + self.rpc_client.send_and_confirm_transaction(&transaction)?; + + Ok(Order { + id: self.create_order_id(), + market: market.clone(), + order_type, + side, + price, + quantity, + status: OrderStatus::Filled, + }) + } + + async fn cancel_order(&self, _order: &Order) -> Result<()> { + Ok(()) + } + + async fn get_balances(&self, market: &Market) -> Result> { + let pool_data = self.get_pool_data(&market.address).await?; + + let token_a_balance = self.rpc_client.get_token_account_balance(&pool_data.token_a_account)?; + let token_b_balance = self.rpc_client.get_token_account_balance(&pool_data.token_b_account)?; + + let mut balances = HashMap::new(); + balances.insert(market.base_asset, token_a_balance.amount as f64); + balances.insert(market.quote_asset, token_b_balance.amount as f64); + + Ok(balances) + } +} + +impl Orca { + fn create_order_id(&self) -> u64 { + rand::random() + } + + async fn get_pool_data(&self, pool_address: &Pubkey) -> Result { + let pool_account_info = self.rpc_client.get_account(pool_address)?; + let pool_data: PoolData = bincode::deserialize(&pool_account_info.data)?; + + Ok(pool_data) + } + + async fn get_token_account(&self, token_mint: &Pubkey) -> Result { + let token_account = spl_associated_token_account::get_associated_token_address( + &self.authority.pubkey(), + token_mint, + ); + + Ok(token_account) + } +} \ No newline at end of file diff --git a/dex/raydium.rs b/dex/raydium.rs new file mode 100644 index 0000000..e2a0d7c --- /dev/null +++ b/dex/raydium.rs @@ -0,0 +1,259 @@ +use crate::dex::dex_trait::DexTrait; +use crate::error::Result; +use crate::models::market::Market; +use crate::models::order::{Order, OrderSide, OrderStatus, OrderType}; +use sdk::pubkey::Pubkey; +use sdk::signature::Keypair; +use sdk::signer::Signer; +use sdk::transaction::Transaction; +use solana_client::rpc_client::RpcClient; +use std::collections::HashMap; + +pub struct Raydium { + pub rpc_client: RpcClient, + pub program_id: Pubkey, + pub amm_id: Pubkey, + pub serum_program_id: Pubkey, + pub authority: Keypair, +} + +impl Raydium { + pub fn new( + rpc_client: RpcClient, + program_id: Pubkey, + amm_id: Pubkey, + serum_program_id: Pubkey, + authority: Keypair, + ) -> Self { + Raydium { + rpc_client, + program_id, + amm_id, + serum_program_id, + authority, + } + } +} + +#[async_trait] +impl DexTrait for Raydium { + async fn get_markets(&self) -> Result> { + let mut markets = Vec::new(); + + let market_infos = self.rpc_client.get_account_info(&self.amm_id)?; + let market_data: AmmInfo = bincode::deserialize(&market_infos.data)?; + + for (mint_a, mint_b) in market_data.mints.iter() { + let market = Market { + address: Pubkey::default(), + name: format!("{}/{}", mint_a, mint_b), + base_asset: *mint_a, + quote_asset: *mint_b, + base_decimals: 0, + quote_decimals: 0, + }; + markets.push(market); + } + + Ok(markets) + } + + async fn get_orderbook(&self, market: &Market) -> Result<(Vec, Vec)> { + let market_account_info = self.rpc_client.get_account_info(&market.address)?; + let market_data: MarketState = bincode::deserialize(&market_account_info.data)?; + + let bids = market_data.bids.iter().map(|order| Order { + price: order.price, + quantity: order.quantity, + side: OrderSide::Bid, + }).collect(); + + let asks = market_data.asks.iter().map(|order| Order { + price: order.price, + quantity: order.quantity, + side: OrderSide::Ask, + }).collect(); + + Ok((bids, asks)) + } + + async fn place_order( + &self, + market: &Market, + order_type: OrderType, + side: OrderSide, + price: f64, + quantity: f64, + ) -> Result { + let order_id = self.create_order_id(); + let order_account = Keypair::new(); + + let (vault_a, vault_b) = self.get_vaults(market).await?; + + let (token_a_account, token_b_account) = self.get_token_accounts(market).await?; + + let order_data = match side { + OrderSide::Bid => MarketInstruction::NewOrder { + order_type: order_type.into(), + side: Side::Bid, + limit_price: price, + max_quantity: quantity, + order_id, + }, + OrderSide::Ask => MarketInstruction::NewOrder { + order_type: order_type.into(), + side: Side::Ask, + limit_price: price, + max_quantity: quantity, + order_id, + }, + }; + + let accounts = match side { + OrderSide::Bid => vec![ + AccountMeta::new(market.address, false), + AccountMeta::new(order_account.pubkey(), true), + AccountMeta::new(self.authority.pubkey(), true), + AccountMeta::new_readonly(spl_token::ID, false), + AccountMeta::new(token_b_account, false), + AccountMeta::new(vault_b, false), + AccountMeta::new(vault_a, false), + AccountMeta::new(token_a_account, false), + AccountMeta::new_readonly(solana_sdk::sysvar::rent::ID, false), + ], + OrderSide::Ask => vec![ + AccountMeta::new(market.address, false), + AccountMeta::new(order_account.pubkey(), true), + AccountMeta::new(self.authority.pubkey(), true), + AccountMeta::new_readonly(spl_token::ID, false), + AccountMeta::new(token_a_account, false), + AccountMeta::new(vault_a, false), + AccountMeta::new(vault_b, false), + AccountMeta::new(token_b_account, false), + AccountMeta::new_readonly(solana_sdk::sysvar::rent::ID, false), + ], + }; + + let instruction = Instruction { + program_id: self.program_id, + accounts, + data: order_data.pack(), + }; + + let recent_blockhash = self.rpc_client.get_latest_blockhash()?; + let transaction = Transaction::new_signed_with_payer( + &[instruction], + Some(&self.authority.pubkey()), + &[&self.authority, &order_account], + recent_blockhash, + ); + + self.rpc_client.send_and_confirm_transaction(&transaction)?; + + Ok(Order { + id: order_id, + market: market.clone(), + order_type, + side, + price, + quantity, + status: OrderStatus::Open, + }) + } + + async fn cancel_order(&self, order: &Order) -> Result<()> { + let cancel_data = MarketInstruction::CancelOrder { order_id: order.id }; + + let accounts = vec![ + AccountMeta::new(order.market.address, false), + AccountMeta::new_readonly(self.authority.pubkey(), true), + AccountMeta::new(self.get_bids_address(&order.market)?, false), + AccountMeta::new(self.get_asks_address(&order.market)?, false), + ]; + + let instruction = Instruction { + program_id: self.program_id, + accounts, + data: cancel_data.pack(), + }; + + let recent_blockhash = self.rpc_client.get_latest_blockhash()?; + let transaction = Transaction::new_signed_with_payer( + &[instruction], + Some(&self.authority.pubkey()), + &[&self.authority], + recent_blockhash, + ); + + self.rpc_client.send_and_confirm_transaction(&transaction)?; + + Ok(()) + } + + async fn get_balances(&self, market: &Market) -> Result> { + let (vault_a, vault_b) = self.get_vaults(market).await?; + + let vault_a_balance = self.rpc_client.get_token_account_balance(&vault_a)?; + let vault_b_balance = self.rpc_client.get_token_account_balance(&vault_b)?; + + let mut balances = HashMap::new(); + balances.insert(market.base_asset, vault_a_balance.amount as f64); + balances.insert(market.quote_asset, vault_b_balance.amount as f64); + + Ok(balances) + } +} + +impl Raydium { + fn create_order_id(&self) -> u64 { + rand::random() + } + + async fn get_vaults(&self, market: &Market) -> Result<(Pubkey, Pubkey)> { + let market_account_info = self.rpc_client.get_account_info(&market.address)?; + let market_data: MarketState = bincode::deserialize(&market_account_info.data)?; + + Ok((market_data.base_vault, market_data.quote_vault)) + } + + async fn get_token_accounts(&self, market: &Market) -> Result<(Pubkey, Pubkey)> { + let token_a_account = spl_associated_token_account::get_associated_token_address( + &self.authority.pubkey(), + &market.base_asset, + ); + let token_b_account = spl_associated_token_account::get_associated_token_address( + &self.authority.pubkey(), + &market.quote_asset, + ); + + Ok((token_a_account, token_b_account)) + } + + fn get_bids_address(&self, market: &Market) -> Result { + let (bids_address, _) = Pubkey::find_program_address( + &[ + &market.address.to_bytes(), + &spl_token::ID.to_bytes(), + &self.program_id.to_bytes(), + b"bids", + ], + &self.program_id, + ); + + Ok(bids_address) + } + + fn get_asks_address(&self, market: &Market) -> Result { + let (asks_address, _) = Pubkey::find_program_address( + &[ + &market.address.to_bytes(), + &spl_token::ID.to_bytes(), + &self.program_id.to_bytes(), + b"asks", + ], + &self.program_id, + ); + + Ok(asks_address) + } +} \ No newline at end of file diff --git a/dex/serum.rs b/dex/serum.rs new file mode 100644 index 0000000..42caf6f --- /dev/null +++ b/dex/serum.rs @@ -0,0 +1,273 @@ +use crate::dex::dex_trait::DexTrait; +use crate::error::Result; +use crate::models::market::Market; +use crate::models::order::{Order, OrderSide, OrderStatus, OrderType}; +use sdk::pubkey::Pubkey; +use sdk::signature::Keypair; +use sdk::signer::Signer; +use sdk::transaction::Transaction; +use solana_client::rpc_client::RpcClient; +use std::collections::HashMap; + +pub struct Serum { + pub rpc_client: RpcClient, + pub program_id: Pubkey, + pub authority: Keypair, +} + +impl Serum { + pub fn new(rpc_client: RpcClient, program_id: Pubkey, authority: Keypair) -> Self { + Serum { + rpc_client, + program_id, + authority, + } + } +} + +#[async_trait] +impl DexTrait for Serum { + async fn get_markets(&self) -> Result> { + let mut markets = Vec::new(); + + let market_infos = self.rpc_client.get_program_accounts(&self.program_id)?; + + for market_info in market_infos { + let market_data: MarketState = bincode::deserialize(&market_info.account.data)?; + + let market = Market { + address: market_info.pubkey, + name: String::from_utf8_lossy(&market_data.name).to_string(), + base_asset: market_data.coin_lot_size, + quote_asset: market_data.pc_lot_size, + base_decimals: market_data.coin_decimals, + quote_decimals: market_data.pc_decimals, + }; + markets.push(market); + } + + Ok(markets) + } + + async fn get_orderbook(&self, market: &Market) -> Result<(Vec, Vec)> { + let market_account_info = self.rpc_client.get_account_info(&market.address)?; + let market_data: MarketState = bincode::deserialize(&market_account_info.data)?; + + let bids = market_data.load_bids_mut(&self.program_id)?; + let asks = market_data.load_asks_mut(&self.program_id)?; + + let bid_orders = bids.orders(&market_data, &self.program_id)?; + let ask_orders = asks.orders(&market_data, &self.program_id)?; + + Ok((bid_orders, ask_orders)) + } + + async fn place_order( + &self, + market: &Market, + order_type: OrderType, + side: OrderSide, + price: f64, + quantity: f64, + ) -> Result { + let order_id = self.create_order_id(); + let order_account = Keypair::new(); + + let (token_a_account, token_b_account) = self.get_token_accounts(market).await?; + + let order_data = NewOrderInstructionV3 { + side: side.into(), + limit_price: price, + max_qty: quantity, + order_type: order_type.into(), + client_order_id: 0, + self_trade_behavior: SelfTradeBehavior::DecrementTake, + limit: 65535, + max_coin_qty: quantity, + max_native_pc_qty_including_fees: price * quantity, + self_trade_behavior_v2: SelfTradeBehaviorV2::CancelProvide, + padding: [0; 5], + }; + + let accounts = match side { + OrderSide::Bid => vec![ + AccountMeta::new(market.address, false), + AccountMeta::new(order_account.pubkey(), true), + AccountMeta::new(self.authority.pubkey(), true), + AccountMeta::new_readonly(spl_token::ID, false), + AccountMeta::new(token_b_account, false), + AccountMeta::new(self.get_bids_address(&market)?, false), + AccountMeta::new(self.get_asks_address(&market)?, false), + AccountMeta::new(self.get_event_queue_address(&market)?, false), + AccountMeta::new(token_a_account, false), + AccountMeta::new_readonly(solana_sdk::sysvar::rent::ID, false), + ], + OrderSide::Ask => vec![ + AccountMeta::new(market.address, false), + AccountMeta::new(order_account.pubkey(), true), + AccountMeta::new(self.authority.pubkey(), true), + AccountMeta::new_readonly(spl_token::ID, false), + AccountMeta::new(token_a_account, false), + AccountMeta::new(self.get_asks_address(&market)?, false), + AccountMeta::new(self.get_bids_address(&market)?, false), + AccountMeta::new(self.get_event_queue_address(&market)?, false), + AccountMeta::new(token_b_account, false), + AccountMeta::new_readonly(solana_sdk::sysvar::rent::ID, false), + ], + }; + + let instruction = Instruction { + program_id: self.program_id, + accounts, + data: order_data.pack(), + }; + + let recent_blockhash = self.rpc_client.get_latest_blockhash()?; + let transaction = Transaction::new_signed_with_payer( + &[instruction], + Some(&self.authority.pubkey()), + &[&self.authority, &order_account], + recent_blockhash, + ); + + self.rpc_client.send_and_confirm_transaction(&transaction)?; + + Ok(Order { + id: order_id, + market: market.clone(), + order_type, + side, + price, + quantity, + status: OrderStatus::Open, + }) + } + + async fn cancel_order(&self, order: &Order) -> Result<()> { + let cancel_data = MarketInstruction::CancelOrderV2 { + side: order.side.into(), + order_id: order.id, + }; + + let accounts = vec![ + AccountMeta::new(order.market.address, false), + AccountMeta::new_readonly(self.authority.pubkey(), true), + AccountMeta::new(self.get_bids_address(&order.market)?, false), + AccountMeta::new(self.get_asks_address(&order.market)?, false), + AccountMeta::new(self.get_event_queue_address(&order.market)?, false), + ]; + + let instruction = Instruction { + program_id: self.program_id, + accounts, + data: cancel_data.pack(), + }; + + let recent_blockhash = self.rpc_client.get_latest_blockhash()?; + let transaction = Transaction::new_signed_with_payer( + &[instruction], + Some(&self.authority.pubkey()), + &[&self.authority], + recent_blockhash, + ); + + self.rpc_client.send_and_confirm_transaction(&transaction)?; + + Ok(()) + } + + async fn get_balances(&self, market: &Market) -> Result> { + let vault_signer = self.get_vault_signer_address(&market)?; + let base_vault = self.get_vault_address(&market, &market.base_asset)?; + let quote_vault = self.get_vault_address(&market, &market.quote_asset)?; + + let base_vault_balance = self.rpc_client.get_token_account_balance(&base_vault)?; + let quote_vault_balance = self.rpc_client.get_token_account_balance("e_vault)?; + + let mut balances = HashMap::new(); + balances.insert(market.base_asset, base_vault_balance.amount as f64); + balances.insert(market.quote_asset, quote_vault_balance.amount as f64); + + Ok(balances) + } +} + +impl Serum { + fn create_order_id(&self) -> u64 { + rand::random() + } + + async fn get_token_accounts(&self, market: &Market) -> Result<(Pubkey, Pubkey)> { + let token_a_account = spl_associated_token_account::get_associated_token_address( + &self.authority.pubkey(), + &market.base_asset, + ); + let token_b_account = spl_associated_token_account::get_associated_token_address( + &self.authority.pubkey(), + &market.quote_asset, + ); + + Ok((token_a_account, token_b_account)) + } + + fn get_bids_address(&self, market: &Market) -> Result { + let (bids_address, _) = Pubkey::find_program_address( + &[ + &market.address.to_bytes(), + b"bids", + ], + &self.program_id, + ); + + Ok(bids_address) + } + + fn get_asks_address(&self, market: &Market) -> Result { + let (asks_address, _) = Pubkey::find_program_address( + &[ + &market.address.to_bytes(), + b"asks", + ], + &self.program_id, + ); + + Ok(asks_address) + } + + fn get_event_queue_address(&self, market: &Market) -> Result { + let (event_queue_address, _) = Pubkey::find_program_address( + &[ + &market.address.to_bytes(), + b"event_queue", + ], + &self.program_id, + ); + + Ok(event_queue_address) + } + + fn get_vault_signer_address(&self, market: &Market) -> Result { + let (vault_signer_address, _) = Pubkey::find_program_address( + &[ + &market.address.to_bytes(), + b"vault_signer", + ], + &self.program_id, + ); + + Ok(vault_signer_address) + } + + fn get_vault_address(&self, market: &Market, token_mint: &Pubkey) -> Result { + let (vault_address, _) = Pubkey::find_program_address( + &[ + &market.address.to_bytes(), + &token_mint.to_bytes(), + b"vault", + ], + &spl_token::ID, + ); + + Ok(vault_address) + } +} \ No newline at end of file diff --git a/error.rs b/error.rs new file mode 100644 index 0000000..73aed00 --- /dev/null +++ b/error.rs @@ -0,0 +1,21 @@ +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum MevBotError { + #[error("Solana client error: {0}")] + SolanaClientError(#[from] solana_client::client_error::ClientError), + + #[error("Reqwest error: {0}")] + ReqwestError(#[from] reqwest::Error), + + #[error("JSON error: {0}")] + JsonError(#[from] serde_json::Error), + + #[error("Decimal error: {0}")] + DecimalError(#[from] rust_decimal::Error), + + #[error("Custom error: {0}")] + Custom(String), +} + +pub type Result = std::result::Result; \ No newline at end of file diff --git a/libs.rs b/libs.rs new file mode 100644 index 0000000..80b350f --- /dev/null +++ b/libs.rs @@ -0,0 +1,42 @@ +//! # Solana MEV Bot +//! +//! Este bot está diseñado para aprovechar las oportunidades de MEV (Maximal Extractable Value) +//! en la red de Solana. El bot utiliza diversas estrategias, como sniping y copy trading, +//! para identificar y ejecutar transacciones rentables. +//! +//! ## Características principales +//! +//! - Integración con múltiples DEX (Raydium, Serum, Orca) para obtener precios y ejecutar transacciones +//! - Estrategias especializadas de sniping y copy trading para maximizar las ganancias +//! - Optimización avanzada del rendimiento y escalabilidad +//! - Monitoreo en tiempo real y dashboard para rastrear el rendimiento y las métricas clave +//! - Cobertura exhaustiva de pruebas y documentación detallada +//! +//! ## Uso +//! +//! Para utilizar el bot de Solana MEV, siga estos pasos: +//! +//! 1. Configure las credenciales y los parámetros en el archivo `config.toml` +//! 2. Ejecute el bot con `cargo run --release` +//! 3. Monitoree el rendimiento y las métricas a través del dashboard en tiempo real +//! 4. Ajuste las estrategias y los parámetros según sea necesario para optimizar las ganancias +//! +//! ## Contribución +//! +//! Si desea contribuir a este proyecto, siga estas pautas: +//! +//! 1. Abra un issue para discutir los cambios propuestos +//! 2. Haga fork del repositorio y cree una nueva rama para sus cambios +//! 3. Envíe un pull request con una descripción detallada de sus cambios y su propósito +//! 4. Asegúrese de que todos los tests pasen y de seguir las pautas de codificación establecidas +//! +//! ## Licencia +//! +//! Este proyecto está licenciado bajo los términos de la Licencia MIT. Consulte el archivo `LICENSE` para obtener más detalles. +//! + +pub mod bot; +pub mod dex; +pub mod strategies; +pub mod models; +pub mod utils; \ No newline at end of file diff --git a/main.rs b/main.rs new file mode 100644 index 0000000..85ecf03 --- /dev/null +++ b/main.rs @@ -0,0 +1,62 @@ +use std::sync::Arc; + +use mev_bot_solana::bot::solana_mev_bot::SolanaMevBot; +use mev_bot_solana::config::Config; +use mev_bot_solana::dex::dex_manager::DexManager; +use mev_bot_solana::monitoring::dashboard::Dashboard; +use mev_bot_solana::monitoring::metrics::Metrics; +use mev_bot_solana::strategies::copy_trade_strategy::CopyTradeStrategy; +use mev_bot_solana::strategies::sniping_strategy::SnipingStrategy; +use mev_bot_solana::utils::config_parser::parse_config; +use solana_client::rpc_client::RpcClient; +use solana_sdk::signature::read_keypair_file; + +#[tokio::main] +async fn main() { + let config = parse_config("config.toml").expect("Failed to parse config"); + + let rpc_client = Arc::new(RpcClient::new_with_commitment( + config.solana.rpc_url.clone(), + config.solana.commitment.clone(), + )); + + let metrics = Arc::new(Metrics::new()); + let dashboard = Dashboard::new(metrics.clone(), config.monitoring.update_interval); + + let dex_manager = Arc::new(tokio::sync::Mutex::new(DexManager::new( + rpc_client.clone(), + config.dexes.clone(), + ))); + + let sniping_strategy = Arc::new(tokio::sync::Mutex::new(SnipingStrategy::new( + rpc_client.clone(), + dex_manager.clone(), + config.bot.max_position_size, + ))); + + let copy_trade_strategy = Arc::new(tokio::sync::Mutex::new(CopyTradeStrategy::new( + rpc_client.clone(), + dex_manager.clone(), + config.bot.max_position_size, + ))); + + let authority_keypair = read_keypair_file(config.bot.keypair_path.clone()) + .expect("Failed to read keypair file"); + + let mut mev_bot = SolanaMevBot::new( + rpc_client, + authority_keypair, + vec![ + sniping_strategy.clone(), + copy_trade_strategy.clone(), + ], + config.bot.profit_threshold, + metrics, + ); + + tokio::spawn(async move { + dashboard.run().await; + }); + + mev_bot.run().await; +} \ No newline at end of file diff --git a/models/copy_trade_opportunity.rs b/models/copy_trade_opportunity.rs new file mode 100644 index 0000000..d103159 --- /dev/null +++ b/models/copy_trade_opportunity.rs @@ -0,0 +1,9 @@ +use crate::models::market::Market; +use crate::models::order::Order; +use solana_sdk::pubkey::Pubkey; + +pub struct CopyTradeOpportunity { + pub trader: Pubkey, + pub market: Market, + pub trade: Order, +} \ No newline at end of file diff --git a/models/copy_trade_target.rs b/models/copy_trade_target.rs new file mode 100644 index 0000000..f3e47cc --- /dev/null +++ b/models/copy_trade_target.rs @@ -0,0 +1,7 @@ +use solana_sdk::pubkey::Pubkey; + +pub struct CopyTradeTarget { + pub trader_account: Pubkey, + pub target_token: Pubkey, + pub trade_amount: f64, +} \ No newline at end of file diff --git a/models/market_conditions.rs b/models/market_conditions.rs new file mode 100644 index 0000000..f35982d --- /dev/null +++ b/models/market_conditions.rs @@ -0,0 +1,9 @@ +use solana_sdk::pubkey::Pubkey; +use std::collections::HashMap; + +pub struct MarketConditions { + pub liquidity: f64, + pub volume: f64, + pub volatility: f64, + pub account_balances: HashMap, +} \ No newline at end of file diff --git a/models/mev_opportunity.rs b/models/mev_opportunity.rs new file mode 100644 index 0000000..0148418 --- /dev/null +++ b/models/mev_opportunity.rs @@ -0,0 +1,6 @@ +use solana_sdk::transaction::Transaction; + +pub struct MevOpportunity { + pub transactions: Vec<(Transaction, f64)>, + pub min_profit: f64, +} \ No newline at end of file diff --git a/models/mod.rs b/models/mod.rs new file mode 100644 index 0000000..195e8b9 --- /dev/null +++ b/models/mod.rs @@ -0,0 +1,3 @@ +pub mod market_conditions; +pub mod mev_opportunity; +pub mod transaction_log; \ No newline at end of file diff --git a/models/sniping_opportunity.rs b/models/sniping_opportunity.rs new file mode 100644 index 0000000..d53000d --- /dev/null +++ b/models/sniping_opportunity.rs @@ -0,0 +1,7 @@ +use crate::models::market::Market; + +pub struct SnipingOpportunity { + pub market: Market, + pub price: f64, + pub liquidity: f64, +} \ No newline at end of file diff --git a/models/transaction_log.rs b/models/transaction_log.rs new file mode 100644 index 0000000..49609f5 --- /dev/null +++ b/models/transaction_log.rs @@ -0,0 +1,6 @@ +use crate::models::market_conditions::MarketConditions; + +pub struct TransactionLog { + pub signature: String, + pub market_conditions: MarketConditions, +} \ No newline at end of file diff --git a/monitoring/dashboard.rs b/monitoring/dashboard.rs new file mode 100644 index 0000000..b2a63bf --- /dev/null +++ b/monitoring/dashboard.rs @@ -0,0 +1,37 @@ +use crate::monitoring::metrics::Metrics; +use std::sync::Arc; +use tokio::sync::Mutex; +use tokio::time; + +pub struct Dashboard { + pub metrics: Arc, + pub update_interval: u64, +} + +impl Dashboard { + pub fn new(metrics: Arc, update_interval: u64) -> Self { + Dashboard { + metrics, + update_interval, + } + } + + pub async fn run(&self) { + loop { + self.render().await; + time::sleep(time::Duration::from_secs(self.update_interval)).await; + } + } + + async fn render(&self) { + let orders = self.metrics.get_orders().await; + let profits = self.metrics.get_profits().await; + let volumes = self.metrics.get_volumes().await; + + println!("=== MEV Bot Dashboard ==="); + println!("Total Orders: {}", orders.len()); + println!("Total Profit: {:.2} SOL", profits.values().sum::()); + println!("Total Volume: {:.2} SOL", volumes.values().sum::()); + println!("=========================="); + } +} \ No newline at end of file diff --git a/monitoring/metrics.rs b/monitoring/metrics.rs new file mode 100644 index 0000000..a3f2495 --- /dev/null +++ b/monitoring/metrics.rs @@ -0,0 +1,48 @@ +use crate::models::market::Market; +use crate::models::order::Order; +use solana_sdk::pubkey::Pubkey; +use std::collections::HashMap; +use std::sync::Arc; +use tokio::sync::Mutex; + +pub struct Metrics { + pub orders: Arc>>, + pub profits: Arc>>, + pub volumes: Arc>>, +} + +impl Metrics { + pub fn new() -> Self { + Metrics { + orders: Arc::new(Mutex::new(Vec::new())), + profits: Arc::new(Mutex::new(HashMap::new())), + volumes: Arc::new(Mutex::new(HashMap::new())), + } + } + + pub async fn add_order(&self, order: Order) { + self.orders.lock().await.push(order); + } + + pub async fn update_profit(&self, market: &Market, profit: f64) { + let mut profits = self.profits.lock().await; + *profits.entry(market.address).or_insert(0.0) += profit; + } + + pub async fn update_volume(&self, market: &Market, volume: f64) { + let mut volumes = self.volumes.lock().await; + *volumes.entry(market.clone()).or_insert(0.0) += volume; + } + + pub async fn get_orders(&self) -> Vec { + self.orders.lock().await.clone() + } + + pub async fn get_profits(&self) -> HashMap { + self.profits.lock().await.clone() + } + + pub async fn get_volumes(&self) -> HashMap { + self.volumes.lock().await.clone() + } +} \ No newline at end of file diff --git a/sha1.c b/sha1.c deleted file mode 100644 index d87c7f4..0000000 --- a/sha1.c +++ /dev/null @@ -1,371 +0,0 @@ -/* - * sha1.c - * - * Copyright (C) 1998, 2009 - * Paul E. Jones - * All Rights Reserved - * - ***************************************************************************** - * $Id: sha1.c 12 2009-06-22 19:34:25Z paulej $ - ***************************************************************************** - * - * Description: - * This file implements the Secure Hashing Standard as defined - * in FIPS PUB 180-1 published April 17, 1995. - * - * The Secure Hashing Standard, which uses the Secure Hashing - * Algorithm (SHA), produces a 160-bit message digest for a - * given data stream. In theory, it is highly improbable that - * two messages will produce the same message digest. Therefore, - * this algorithm can serve as a means of providing a "fingerprint" - * for a message. - * - * Portability Issues: - * SHA-1 is defined in terms of 32-bit "words". This code was - * written with the expectation that the processor has at least - * a 32-bit machine word size. If the machine word size is larger, - * the code should still function properly. One caveat to that - * is that the input functions taking characters and character - * arrays assume that only 8 bits of information are stored in each - * character. - * - * Caveats: - * SHA-1 is designed to work with messages less than 2^64 bits - * long. Although SHA-1 allows a message digest to be generated for - * messages of any number of bits less than 2^64, this - * implementation only works with messages with a length that is a - * multiple of the size of an 8-bit character. - * - */ - -#include "sha1.h" - -/* - * Define the circular shift macro - */ -#define SHA1CircularShift(bits,word) \ - ((((word) << (bits)) & 0xFFFFFFFF) | \ - ((word) >> (32-(bits)))) - -/* Function prototypes */ -void SHA1ProcessMessageBlock(SHA1Context *); -void SHA1PadMessage(SHA1Context *); - -/* - * SHA1Reset - * - * Description: - * This function will initialize the SHA1Context in preparation - * for computing a new message digest. - * - * Parameters: - * context: [in/out] - * The context to reset. - * - * Returns: - * Nothing. - * - * Comments: - * - */ -void SHA1Reset(SHA1Context *context) -{ - context->Length_Low = 0; - context->Length_High = 0; - context->Message_Block_Index = 0; - - context->Message_Digest[0] = 0x67452301; - context->Message_Digest[1] = 0xEFCDAB89; - context->Message_Digest[2] = 0x98BADCFE; - context->Message_Digest[3] = 0x10325476; - context->Message_Digest[4] = 0xC3D2E1F0; - - context->Computed = 0; - context->Corrupted = 0; -} - -/* - * SHA1Result - * - * Description: - * This function will return the 160-bit message digest into the - * Message_Digest array within the SHA1Context provided - * - * Parameters: - * context: [in/out] - * The context to use to calculate the SHA-1 hash. - * - * Returns: - * 1 if successful, 0 if it failed. - * - * Comments: - * - */ -int SHA1Result(SHA1Context *context) -{ - - if (context->Corrupted) - { - return 0; - } - - if (!context->Computed) - { - SHA1PadMessage(context); - context->Computed = 1; - } - - return 1; -} - -/* - * SHA1Input - * - * Description: - * This function accepts an array of octets as the next portion of - * the message. - * - * Parameters: - * context: [in/out] - * The SHA-1 context to update - * message_array: [in] - * An array of characters representing the next portion of the - * message. - * length: [in] - * The length of the message in message_array - * - * Returns: - * Nothing. - * - * Comments: - * - */ -void SHA1Input( SHA1Context *context, - const unsigned char *message_array, - unsigned length) -{ - if (!length) - { - return; - } - - if (context->Computed || context->Corrupted) - { - context->Corrupted = 1; - return; - } - - while(length-- && !context->Corrupted) - { - context->Message_Block[context->Message_Block_Index++] = - (*message_array & 0xFF); - - context->Length_Low += 8; - /* Force it to 32 bits */ - context->Length_Low &= 0xFFFFFFFF; - if (context->Length_Low == 0) - { - context->Length_High++; - /* Force it to 32 bits */ - context->Length_High &= 0xFFFFFFFF; - if (context->Length_High == 0) - { - /* Message is too long */ - context->Corrupted = 1; - } - } - - if (context->Message_Block_Index == 64) - { - SHA1ProcessMessageBlock(context); - } - - message_array++; - } -} - -/* - * SHA1ProcessMessageBlock - * - * Description: - * This function will process the next 512 bits of the message - * stored in the Message_Block array. - * - * Parameters: - * None. - * - * Returns: - * Nothing. - * - * Comments: - * Many of the variable names in the SHAContext, especially the - * single character names, were used because those were the names - * used in the publication. - * - * - */ -void SHA1ProcessMessageBlock(SHA1Context *context) -{ - const unsigned K[] = /* Constants defined in SHA-1 */ - { - 0x5A827999, - 0x6ED9EBA1, - 0x8F1BBCDC, - 0xCA62C1D6 - }; - int t; /* Loop counter */ - unsigned temp; /* Temporary word value */ - unsigned W[80]; /* Word sequence */ - unsigned A, B, C, D, E; /* Word buffers */ - - /* - * Initialize the first 16 words in the array W - */ - for(t = 0; t < 16; t++) - { - W[t] = ((unsigned) context->Message_Block[t * 4]) << 24; - W[t] |= ((unsigned) context->Message_Block[t * 4 + 1]) << 16; - W[t] |= ((unsigned) context->Message_Block[t * 4 + 2]) << 8; - W[t] |= ((unsigned) context->Message_Block[t * 4 + 3]); - } - - for(t = 16; t < 80; t++) - { - W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); - } - - A = context->Message_Digest[0]; - B = context->Message_Digest[1]; - C = context->Message_Digest[2]; - D = context->Message_Digest[3]; - E = context->Message_Digest[4]; - - for(t = 0; t < 20; t++) - { - temp = SHA1CircularShift(5,A) + - ((B & C) | ((~B) & D)) + E + W[t] + K[0]; - temp &= 0xFFFFFFFF; - E = D; - D = C; - C = SHA1CircularShift(30,B); - B = A; - A = temp; - } - - for(t = 20; t < 40; t++) - { - temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1]; - temp &= 0xFFFFFFFF; - E = D; - D = C; - C = SHA1CircularShift(30,B); - B = A; - A = temp; - } - - for(t = 40; t < 60; t++) - { - temp = SHA1CircularShift(5,A) + - ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; - temp &= 0xFFFFFFFF; - E = D; - D = C; - C = SHA1CircularShift(30,B); - B = A; - A = temp; - } - - for(t = 60; t < 80; t++) - { - temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3]; - temp &= 0xFFFFFFFF; - E = D; - D = C; - C = SHA1CircularShift(30,B); - B = A; - A = temp; - } - - context->Message_Digest[0] = - (context->Message_Digest[0] + A) & 0xFFFFFFFF; - context->Message_Digest[1] = - (context->Message_Digest[1] + B) & 0xFFFFFFFF; - context->Message_Digest[2] = - (context->Message_Digest[2] + C) & 0xFFFFFFFF; - context->Message_Digest[3] = - (context->Message_Digest[3] + D) & 0xFFFFFFFF; - context->Message_Digest[4] = - (context->Message_Digest[4] + E) & 0xFFFFFFFF; - - context->Message_Block_Index = 0; -} - -/* - * SHA1PadMessage - * - * Description: - * According to the standard, the message must be padded to an even - * 512 bits. The first padding bit must be a '1'. The last 64 - * bits represent the length of the original message. All bits in - * between should be 0. This function will pad the message - * according to those rules by filling the Message_Block array - * accordingly. It will also call SHA1ProcessMessageBlock() - * appropriately. When it returns, it can be assumed that the - * message digest has been computed. - * - * Parameters: - * context: [in/out] - * The context to pad - * - * Returns: - * Nothing. - * - * Comments: - * - */ -void SHA1PadMessage(SHA1Context *context) -{ - /* - * Check to see if the current message block is too small to hold - * the initial padding bits and length. If so, we will pad the - * block, process it, and then continue padding into a second - * block. - */ - if (context->Message_Block_Index > 55) - { - context->Message_Block[context->Message_Block_Index++] = 0x80; - while(context->Message_Block_Index < 64) - { - context->Message_Block[context->Message_Block_Index++] = 0; - } - - SHA1ProcessMessageBlock(context); - - while(context->Message_Block_Index < 56) - { - context->Message_Block[context->Message_Block_Index++] = 0; - } - } - else - { - context->Message_Block[context->Message_Block_Index++] = 0x80; - while(context->Message_Block_Index < 56) - { - context->Message_Block[context->Message_Block_Index++] = 0; - } - } - - /* - * Store the message length as the last 8 octets - */ - context->Message_Block[56] = (context->Length_High >> 24) & 0xFF; - context->Message_Block[57] = (context->Length_High >> 16) & 0xFF; - context->Message_Block[58] = (context->Length_High >> 8) & 0xFF; - context->Message_Block[59] = (context->Length_High) & 0xFF; - context->Message_Block[60] = (context->Length_Low >> 24) & 0xFF; - context->Message_Block[61] = (context->Length_Low >> 16) & 0xFF; - context->Message_Block[62] = (context->Length_Low >> 8) & 0xFF; - context->Message_Block[63] = (context->Length_Low) & 0xFF; - - SHA1ProcessMessageBlock(context); -} diff --git a/sha1.h b/sha1.h deleted file mode 100644 index 1ca4b10..0000000 --- a/sha1.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * sha1.h - * - * Copyright (C) 1998, 2009 - * Paul E. Jones - * All Rights Reserved - * - ***************************************************************************** - * $Id: sha1.h 12 2009-06-22 19:34:25Z paulej $ - ***************************************************************************** - * - * Description: - * This class implements the Secure Hashing Standard as defined - * in FIPS PUB 180-1 published April 17, 1995. - * - * Many of the variable names in the SHA1Context, especially the - * single character names, were used because those were the names - * used in the publication. - * - * Please read the file sha1.c for more information. - * - */ - -#ifndef _SHA1_H_ -#define _SHA1_H_ - -/* - * This structure will hold context information for the hashing - * operation - */ -typedef struct SHA1Context -{ - unsigned Message_Digest[5]; /* Message Digest (output) */ - - unsigned Length_Low; /* Message length in bits */ - unsigned Length_High; /* Message length in bits */ - - unsigned char Message_Block[64]; /* 512-bit message blocks */ - int Message_Block_Index; /* Index into message block array */ - - int Computed; /* Is the digest computed? */ - int Corrupted; /* Is the message digest corruped? */ -} SHA1Context; - -/* - * Function Prototypes - */ -void SHA1Reset(SHA1Context *); -int SHA1Result(SHA1Context *); -void SHA1Input( SHA1Context *, - const unsigned char *, - unsigned); - -#endif diff --git a/strategies/arbitrage.rs b/strategies/arbitrage.rs new file mode 100644 index 0000000..4520898 --- /dev/null +++ b/strategies/arbitrage.rs @@ -0,0 +1,17 @@ +use crate::models::market_conditions::MarketConditions; +use crate::models::mev_opportunity::MevOpportunity; +use crate::strategies::strategy::Strategy; +use async_trait::async_trait; +use solana_sdk::pubkey::Pubkey; +use std::collections::HashMap; + +pub struct ArbitrageStrategy {} + +#[async_trait] +impl Strategy for ArbitrageStrategy { + fn update(&mut self, _market_conditions: &MarketConditions) {} + + async fn find_opportunities(&self, _target_accounts: &HashMap) -> Vec { + Vec::new() + } +} \ No newline at end of file diff --git a/strategies/arbitrage_strategy.rs b/strategies/arbitrage_strategy.rs new file mode 100644 index 0000000..c71c1b6 --- /dev/null +++ b/strategies/arbitrage_strategy.rs @@ -0,0 +1,117 @@ +use crate::dex::dex_manager::DexManager; +use crate::models::market_conditions::MarketConditions; +use crate::models::arbitrage_opportunity::ArbitrageOpportunity; +use crate::strategies::strategy::Strategy; +use crate::utils::math; +use async_trait::async_trait; +use solana_client::rpc_client::RpcClient; +use solana_sdk::pubkey::Pubkey; +use std::collections::HashMap; + +pub struct ArbitrageStrategy { + pub rpc_client: RpcClient, + pub dex_manager: DexManager, + pub min_profit_threshold: f64, +} + +impl ArbitrageStrategy { + pub fn new(rpc_client: RpcClient, dex_manager: DexManager, min_profit_threshold: f64) -> Self { + ArbitrageStrategy { + rpc_client, + dex_manager, + min_profit_threshold, + } + } + + pub async fn find_arbitrage_opportunities(&self, market_conditions: &MarketConditions) -> Vec { + let mut opportunities = Vec::new(); + + let token_prices = market_conditions.token_prices.clone(); + let token_pairs = self.generate_token_pairs(&token_prices); + + for (token_a, token_b) in token_pairs { + if let Some(opportunity) = self.find_arbitrage_opportunity(token_a, token_b, &token_prices).await { + if opportunity.expected_profit >= self.min_profit_threshold { + opportunities.push(opportunity); + } + } + } + + opportunities + } + + async fn find_arbitrage_opportunity(&self, token_a: &str, token_b: &str, token_prices: &HashMap) -> Option { + let mut best_opportunity: Option = None; + + if let Some(price_a_b) = token_prices.get(&format!("{}/{}", token_a, token_b)) { + if let Some(price_b_a) = token_prices.get(&format!("{}/{}", token_b, token_a)) { + let forward_amount = 1.0; + let forward_price = price_a_b; + let backward_amount = forward_amount * forward_price; + let backward_price = price_b_a; + + let forward_trade = self.dex_manager.get_best_trade_route(token_a, token_b, forward_amount).await; + let backward_trade = self.dex_manager.get_best_trade_route(token_b, token_a, backward_amount).await; + + if let (Some(forward_trade), Some(backward_trade)) = (forward_trade, backward_trade) { + let forward_amount_received = math::checked_div(forward_amount, forward_trade.price).unwrap_or(0.0); + let backward_amount_received = math::checked_mul(backward_trade.received_amount, backward_price).unwrap_or(0.0); + + let expected_profit = backward_amount_received - forward_amount; + + if expected_profit > 0.0 { + best_opportunity = Some(ArbitrageOpportunity { + token_a: token_a.to_string(), + token_b: token_b.to_string(), + forward_trade, + backward_trade, + expected_profit, + }); + } + } + } + } + + best_opportunity + } + + fn generate_token_pairs(&self, token_prices: &HashMap) -> Vec<(String, String)> { + let mut pairs = Vec::new(); + + for (token_a, _) in token_prices { + for (token_b, _) in token_prices { + if token_a != token_b { + pairs.push((token_a.clone(), token_b.clone())); + } + } + } + + pairs + } +} + +#[async_trait] +impl Strategy for ArbitrageStrategy { + async fn find_opportunities(&self, market_conditions: &MarketConditions) -> Vec { + self.find_arbitrage_opportunities(market_conditions).await + } + + async fn execute_opportunities(&self, opportunities: &[ArbitrageOpportunity]) { + for opportunity in opportunities { + let forward_trade = &opportunity.forward_trade; + let backward_trade = &opportunity.backward_trade; + + let forward_result = self.dex_manager.execute_trade(forward_trade).await; + if forward_result.is_ok() { + let backward_result = self.dex_manager.execute_trade(backward_trade).await; + if backward_result.is_ok() { + // Log successful arbitrage execution + } else { + // Log backward trade failure + } + } else { + // Log forward trade failure + } + } + } +} \ No newline at end of file diff --git a/strategies/copy_trade_strategy.rs b/strategies/copy_trade_strategy.rs new file mode 100644 index 0000000..dcecc74 --- /dev/null +++ b/strategies/copy_trade_strategy.rs @@ -0,0 +1,153 @@ +use crate::dex::dex_manager::DexManager; +use crate::error::Result; +use crate::models::copy_trade_opportunity::CopyTradeOpportunity; +use crate::models::market::Market; +use crate::models::order::Order; +use solana_client::rpc_client::RpcClient; +use solana_sdk::pubkey::Pubkey; +use solana_sdk::signature::Keypair; +use std::collections::HashMap; +use std::sync::Arc; +use tokio::sync::Mutex; + +pub struct CopyTradeStrategy { + pub rpc_client: Arc, + pub dex_manager: Arc>, + pub tracked_traders: Vec, + pub trade_threshold: f64, + pub max_trade_amount: f64, +} + +impl CopyTradeStrategy { + pub fn new( + rpc_client: Arc, + dex_manager: Arc>, + tracked_traders: Vec, + trade_threshold: f64, + max_trade_amount: f64, + ) -> Self { + CopyTradeStrategy { + rpc_client, + dex_manager, + tracked_traders, + trade_threshold, + max_trade_amount, + } + } + + pub async fn run(&self) -> Result<()> { + loop { + let opportunities = self.find_opportunities().await?; + + for opportunity in opportunities { + self.execute_copy_trade(&opportunity).await?; + } + + tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; + } + } + + async fn find_opportunities(&self) -> Result> { + let mut opportunities = Vec::new(); + + for trader in &self.tracked_traders { + let trades = self.get_recent_trades(trader).await?; + + for trade in trades { + if trade.quantity >= self.trade_threshold && trade.quantity <= self.max_trade_amount { + let market = self.dex_manager.lock().await.get_market(&trade.market).await?; + + let opportunity = CopyTradeOpportunity { + trader: *trader, + market, + trade, + }; + opportunities.push(opportunity); + } + } + } + + Ok(opportunities) + } + + async fn get_recent_trades(&self, trader: &Pubkey) -> Result> { + let signature_infos = self.rpc_client.get_signatures_for_address(trader)?; + + let mut trades = Vec::new(); + + for signature_info in signature_infos { + if let Some(signature) = signature_info.signature { + let transaction = self.rpc_client.get_transaction(&signature)?; + + if let Some(transaction) = transaction { + for instruction in transaction.transaction.message.instructions { + if let Some(dex_instruction) = DexInstruction::unpack(instruction) { + match dex_instruction { + DexInstruction::NewOrder { .. } => { + let order = self.parse_order(&transaction, &instruction)?; + trades.push(order); + } + _ => {} + } + } + } + } + } + } + + Ok(trades) + } + + fn parse_order(&self, transaction: &TransactionInfo, instruction: &CompiledInstruction) -> Result { + let market_address = instruction.accounts[0]; + let market = self.dex_manager.lock().await.get_market(&market_address).await?; + + let side = match instruction.data[0] { + 0 => OrderSide::Bid, + 1 => OrderSide::Ask, + _ => return Err(anyhow!("Invalid order side")), + }; + + let order_type = match instruction.data[1] { + 0 => OrderType::Limit, + 1 => OrderType::ImmediateOrCancel, + 2 => OrderType::PostOnly, + _ => return Err(anyhow!("Invalid order type")), + }; + + let price = f64::from_le_bytes(instruction.data[2..10].try_into()?); + let quantity = f64::from_le_bytes(instruction.data[10..18].try_into()?); + + Ok(Order { + id: transaction.transaction.signatures[0].to_string(), + market, + side, + order_type, + price, + quantity, + status: OrderStatus::Filled, + }) + } + async fn execute_copy_trade(&self, opportunity: &CopyTradeOpportunity) -> Result<()> { + let market = &opportunity.market; + let trade = &opportunity.trade; + let order = self + .dex_manager + .lock() + .await + .place_order(market, trade.order_type, trade.side, trade + async fn execute_copy_trade(&self, opportunity: &CopyTradeOpportunity) -> Result<()> { + let market = &opportunity.market; + let trade = &opportunity.trade; + + let order = self + .dex_manager + .lock() + .await + .place_order(market, trade.order_type, trade.side, trade.price, trade.quantity) + .await?; + + println!("Placed copy trade order: {:?}", order); + + Ok(()) +} \ No newline at end of file diff --git a/strategies/liquidation.rs b/strategies/liquidation.rs new file mode 100644 index 0000000..4cc3968 --- /dev/null +++ b/strategies/liquidation.rs @@ -0,0 +1,17 @@ +use crate::models::market_conditions::MarketConditions; +use crate::models::mev_opportunity::MevOpportunity; +use crate::strategies::strategy::Strategy; +use async_trait::async_trait; +use solana_sdk::pubkey::Pubkey; +use std::collections::HashMap; + +pub struct LiquidationStrategy {} + +#[async_trait] +impl Strategy for LiquidationStrategy { + fn update(&mut self, _market_conditions: &MarketConditions) {} + + async fn find_opportunities(&self, _target_accounts: &HashMap) -> Vec { + Vec::new() + } +} \ No newline at end of file diff --git a/strategies/mod.rs b/strategies/mod.rs new file mode 100644 index 0000000..b31d383 --- /dev/null +++ b/strategies/mod.rs @@ -0,0 +1,4 @@ +pub mod strategy; +pub mod arbitrage; +pub mod liquidation; +pub mod sandwich; \ No newline at end of file diff --git a/strategies/sandwich.rs b/strategies/sandwich.rs new file mode 100644 index 0000000..586d6a2 --- /dev/null +++ b/strategies/sandwich.rs @@ -0,0 +1,17 @@ +use crate::models::market_conditions::MarketConditions; +use crate::models::mev_opportunity::MevOpportunity; +use crate::strategies::strategy::Strategy; +use async_trait::async_trait; +use solana_sdk::pubkey::Pubkey; +use std::collections::HashMap; + +pub struct SandwichStrategy {} + +#[async_trait] +impl Strategy for SandwichStrategy { + fn update(&mut self, _market_conditions: &MarketConditions) {} + + async fn find_opportunities(&self, _target_accounts: &HashMap) -> Vec { + Vec::new() + } +} \ No newline at end of file diff --git a/strategies/sniping_strategy.rs b/strategies/sniping_strategy.rs new file mode 100644 index 0000000..08d7191 --- /dev/null +++ b/strategies/sniping_strategy.rs @@ -0,0 +1,119 @@ +use crate::dex::dex_manager::DexManager; +use crate::error::Result; +use crate::models::market::Market; +use crate::models::sniping_opportunity::SnipingOpportunity; +use solana_client::rpc_client::RpcClient; +use solana_sdk::pubkey::Pubkey; +use std::sync::Arc; +use tokio::sync::Mutex; + +pub struct SnipingStrategy { + pub rpc_client: Arc, + pub dex_manager: Arc>, + pub target_markets: Vec, + pub max_price: f64, + pub min_liquidity: f64, +} + +impl SnipingStrategy { + pub fn new( + rpc_client: Arc, + dex_manager: Arc>, + target_markets: Vec, + max_price: f64, + min_liquidity: f64, + ) -> Self { + SnipingStrategy { + rpc_client, + dex_manager, + target_markets, + max_price, + min_liquidity, + } + } + + pub async fn run(&self) -> Result<()> { + loop { + let markets = self.get_target_markets().await?; + + let opportunities = self.find_opportunities(&markets).await?; + + for opportunity in opportunities { + self.execute_sniping(&opportunity).await?; + } + + tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; + } + } + + async fn get_target_markets(&self) -> Result> { + let mut markets = Vec::new(); + + for market_address in &self.target_markets { + let market = self.dex_manager.lock().await.get_market(market_address).await?; + markets.push(market); + } + + Ok(markets) + } + + async fn find_opportunities(&self, markets: &[Market]) -> Result> { + let mut opportunities = Vec::new(); + + for market in markets { + let orderbook = self.dex_manager.lock().await.get_orderbook(market).await?; + + if let Some(best_bid) = orderbook.bids.first() { + if best_bid.price <= self.max_price { + let liquidity = self.calculate_liquidity(market, &orderbook).await?; + + if liquidity >= self.min_liquidity { + let opportunity = SnipingOpportunity { + market: market.clone(), + price: best_bid.price, + liquidity, + }; + opportunities.push(opportunity); + } + } + } + } + + Ok(opportunities) + } + + async fn calculate_liquidity(&self, market: &Market, orderbook: &Orderbook) -> Result { + let bids_volume = orderbook.bids.iter().map(|order| order.quantity).sum(); + let asks_volume = orderbook.asks.iter().map(|order| order.quantity).sum(); + + let mid_price = (orderbook.bids[0].price + orderbook.asks[0].price) / 2.0; + + let base_volume = bids_volume + asks_volume; + let quote_volume = base_volume * mid_price; + + let base_decimals = market.base_decimals; + let quote_decimals = market.quote_decimals; + + let liquidity = base_volume / 10_usize.pow(base_decimals as u32) as f64 + + quote_volume / 10_usize.pow(quote_decimals as u32) as f64; + + Ok(liquidity) + } + + async fn execute_sniping(&self, opportunity: &SnipingOpportunity) -> Result<()> { + let market = &opportunity.market; + let price = opportunity.price; + let quantity = opportunity.liquidity / price; + + let order = self + .dex_manager + .lock() + .await + .place_order(market, OrderType::Limit, OrderSide::Bid, price, quantity) + .await?; + + println!("Placed sniping order: {:?}", order); + + Ok(()) + } +} \ No newline at end of file diff --git a/strategies/strategy.rs b/strategies/strategy.rs new file mode 100644 index 0000000..3fbe2a7 --- /dev/null +++ b/strategies/strategy.rs @@ -0,0 +1,11 @@ +use crate::models::market_conditions::MarketConditions; +use crate::models::mev_opportunity::MevOpportunity; +use async_trait::async_trait; +use solana_sdk::pubkey::Pubkey; +use std::collections::HashMap; + +#[async_trait] +pub trait Strategy { + fn update(&mut self, market_conditions: &MarketConditions); + async fn find_opportunities(&self, target_accounts: &HashMap) -> Vec; +} \ No newline at end of file diff --git a/test.c b/test.c deleted file mode 100644 index a15026c..0000000 --- a/test.c +++ /dev/null @@ -1,55 +0,0 @@ -#include -#include -#include -#include - -#include - -int onclose(wsclient *c) { - fprintf(stderr, "onclose called: %d\n", c->sockfd); - return 0; -} - -int onerror(wsclient *c, wsclient_error *err) { - fprintf(stderr, "onerror: (%d): %s\n", err->code, err->str); - if(err->extra_code) { - errno = err->extra_code; - perror("recv"); - } - return 0; -} - -int onmessage(wsclient *c, wsclient_message *msg) { - fprintf(stderr, "onmessage: (%llu): %s\n", msg->payload_len, msg->payload); - return 0; -} - -int onopen(wsclient *c) { - fprintf(stderr, "onopen called: %d\n", c->sockfd); - libwsclient_send(c, "Hello onopen"); - return 0; -} - -int main(int argc, char **argv) { - //Initialize new wsclient * using specified URI - wsclient *client = libwsclient_new("ws://echo.websocket.org"); - if(!client) { - fprintf(stderr, "Unable to initialize new WS client.\n"); - exit(1); - } - //set callback functions for this client - libwsclient_onopen(client, &onopen); - libwsclient_onmessage(client, &onmessage); - libwsclient_onerror(client, &onerror); - libwsclient_onclose(client, &onclose); - //bind helper UNIX socket to "test.sock" - //One can then use netcat (nc) to send data to the websocket server end on behalf of the client, like so: - // $> echo -n "some data that will be echoed by echo.websocket.org" | nc -U test.sock - libwsclient_helper_socket(client, "test.sock"); - //starts run thread. - libwsclient_run(client); - //blocks until run thread for client is done. - libwsclient_finish(client); - return 0; -} - diff --git a/tests/copy_trade_strategy.rs b/tests/copy_trade_strategy.rs new file mode 100644 index 0000000..4b4565f --- /dev/null +++ b/tests/copy_trade_strategy.rs @@ -0,0 +1,26 @@ +use crate::bot::strategies::copy_trade_strategy::CopyTradeStrategy; +use solana_sdk::pubkey::Pubkey; +use std::collections::HashMap; + +#[tokio::test] +async fn test_copy_trade_strategy() { + let rpc_client = solana_client::rpc_client::RpcClient::new("https://api.mainnet-beta.solana.com".to_string()); + let mut strategy = CopyTradeStrategy::new(rpc_client); + + strategy.set_trade_threshold(1000.0); + strategy.set_max_trade_amount(10000.0); + + let trader_account = Pubkey::new_unique(); + let mut target_accounts = HashMap::new(); + target_accounts.insert(trader_account, crate::AccountInfo { + token_balance: 0.0, + token_price: 0.0, + }); + + let targets = strategy.find_opportunities(&target_accounts).await; + assert_eq!(targets.len(), 1); + + let target = &targets[0]; + assert_eq!(target.trader_account, trader_account); + assert_eq!(target.trade_amount, 5000.0); +} \ No newline at end of file diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs new file mode 100644 index 0000000..e7a1f08 --- /dev/null +++ b/tests/integration_tests.rs @@ -0,0 +1,68 @@ +use mev_bot_solana::bot::solana_mev_bot::SolanaMevBot; +use mev_bot_solana::config::Config; +use mev_bot_solana::dex::dex_manager::DexManager; +use mev_bot_solana::monitoring::metrics::Metrics; +use mev_bot_solana::strategies::copy_trade_strategy::CopyTradeStrategy; +use mev_bot_solana::strategies::sniping_strategy::SnipingStrategy; +use mev_bot_solana::utils::config_parser::parse_config; +use solana_client::rpc_client::RpcClient; +use solana_sdk::signature::read_keypair_file; +use std::sync::Arc; + +#[tokio::test] +async fn test_mev_bot_integration() { + let config = parse_config("config.toml").expect("Failed to parse config"); + + let rpc_client = Arc::new(RpcClient::new_with_commitment( + config.solana.rpc_url.clone(), + config.solana.commitment.clone(), + )); + + let metrics = Arc::new(Metrics::new()); + + let dex_manager = Arc::new(tokio::sync::Mutex::new(DexManager::new( + rpc_client.clone(), + config.dexes.clone(), + ))); + + let sniping_strategy = Arc::new(tokio::sync::Mutex::new(SnipingStrategy::new( + rpc_client.clone(), + dex_manager.clone(), + config.bot.max_position_size, + ))); + + let copy_trade_strategy = Arc::new(tokio::sync::Mutex::new(CopyTradeStrategy::new( + rpc_client.clone(), + dex_manager.clone(), + config.bot.max_position_size, + ))); + + let authority_keypair = read_keypair_file(config.bot.keypair_path.clone()) + .expect("Failed to read keypair file"); + + let mut mev_bot = SolanaMevBot::new( + rpc_client, + authority_keypair, + vec![ + sniping_strategy.clone(), + copy_trade_strategy.clone(), + ], + config.bot.profit_threshold, + metrics, + ); + + tokio::spawn(async move { + mev_bot.run().await; + }); + + tokio::time::sleep(tokio::time::Duration::from_secs(10)).await; + + let orders = mev_bot.metrics.get_orders().await; + assert!(!orders.is_empty()); + + let profits = mev_bot.metrics.get_profits().await; + assert!(!profits.is_empty()); + + let volumes = mev_bot.metrics.get_volumes().await; + assert!(!volumes.is_empty()); +} \ No newline at end of file diff --git a/tests/sniping_strategy.rs b/tests/sniping_strategy.rs new file mode 100644 index 0000000..5f724a5 --- /dev/null +++ b/tests/sniping_strategy.rs @@ -0,0 +1,29 @@ +use crate::bot::strategies::sniping_strategy::SnipingStrategy; +use solana_sdk::pubkey::Pubkey; +use std::collections::HashMap; + +#[tokio::test] +async fn test_sniping_strategy() { + let rpc_client = solana_client::rpc_client::RpcClient::new("https://api.mainnet-beta.solana.com".to_string()); + let mut strategy = SnipingStrategy::new(rpc_client); + + let token_mint = Pubkey::new_unique(); + strategy.add_target_token(token_mint); + strategy.set_max_price(10.0); + strategy.set_min_liquidity(1000.0); + + let mut target_accounts = HashMap::new(); + target_accounts.insert(token_mint, crate::AccountInfo { + token_balance: 5000.0, + token_price: 8.0, + }); + + let opportunities = strategy.find_opportunities(&target_accounts).await; + assert_eq!(opportunities.len(), 1); + + let opportunity = &opportunities[0]; + assert_eq!(opportunity.target_account, token_mint); + assert_eq!(opportunity.token_mint, token_mint); + assert_eq!(opportunity.expected_price, 8.0); + assert_eq!(opportunity.token_balance, 5000.0); +} \ No newline at end of file diff --git a/tests/solana_mev_bot.rs b/tests/solana_mev_bot.rs new file mode 100644 index 0000000..ded35ec --- /dev/null +++ b/tests/solana_mev_bot.rs @@ -0,0 +1,40 @@ +use std::collections::HashMap; +use std::sync::Arc; +use tokio::sync::Mutex; + +use solana_mev_bot::bot::solana_mev_bot::SolanaMevBot; +use solana_mev_bot::dex::{raydium, serum, orca}; +use solana_mev_bot::strategies::{sniping_strategy, copy_trade_strategy}; +use solana_mev_bot::utils::solana; + +#[tokio::test] +async fn test_solana_mev_bot() { + let rpc_url = "https://api.devnet.solana.com"; + let ws_url = "wss://api.devnet.solana.com"; + let payer_keypair = solana::load_keypair("path/to/keypair.json"); + let target_accounts = HashMap::new(); + let profit_threshold = 0.01; + + let rpc_client = Arc::new(solana_client::rpc_client::RpcClient::new_with_commitment( + rpc_url.to_string(), + solana_sdk::commitment_config::CommitmentConfig::confirmed(), + )); + + let mut solana_mev_bot = SolanaMevBot::new( + rpc_client.clone(), + ws_url.to_string(), + payer_keypair, + target_accounts, + profit_threshold, + vec![ + Arc::new(Mutex::new(raydium::Raydium::new(rpc_client.clone()))), + Arc::new(Mutex::new(serum::Serum::new(rpc_client.clone()))), + Arc::new(Mutex::new(orca::Orca::new(rpc_client.clone()))), + ], + Arc::new(Mutex::new(sniping_strategy::SnipingStrategy::new(rpc_client.clone()))), + Arc::new(Mutex::new(copy_trade_strategy::CopyTradeStrategy::new(rpc_client.clone()))), + ); + + let result = solana_mev_bot.run().await; + assert!(result.is_ok()); +} \ No newline at end of file diff --git a/utils/api.rs b/utils/api.rs new file mode 100644 index 0000000..902aad2 --- /dev/null +++ b/utils/api.rs @@ -0,0 +1,30 @@ +use crate::api::parsec::ParsecApi; +use crate::api::flipside::FlipsideApi; +use crate::api::thegraph::TheGraphApi; + +pub async fn get_sniping_data(parsec_api: &ParsecApi, flipside_api: &FlipsideApi) -> Result> { + let token_prices = parsec_api.get_token_prices().await?; + + let mut sniping_data = crate::models::sniping_data::SnipingData { + token_prices, + token_volumes: HashMap::new(), + }; + + for token_mint in token_prices.keys() { + let token_volume = flipside_api.get_token_volume(token_mint).await?; + sniping_data.token_volumes.insert(token_mint.to_string(), token_volume); + } + + Ok(sniping_data) +} + +pub async fn get_copy_trade_data(thegraph_api: &TheGraphApi, trader_accounts: &[String]) -> Result, Box> { + let mut all_trades = Vec::new(); + + for trader_account in trader_accounts { + let trades = thegraph_api.get_trader_transactions(trader_account).await?; + all_trades.extend(trades); + } + + Ok(all_trades) +} \ No newline at end of file diff --git a/utils/config_parser.rs b/utils/config_parser.rs new file mode 100644 index 0000000..b520139 --- /dev/null +++ b/utils/config_parser.rs @@ -0,0 +1,12 @@ +use crate::config::Config; +use anyhow::Result; +use std::fs::File; +use std::io::Read; + +pub fn parse_config(path: &str) -> Result { + let mut file = File::open(path)?; + let mut contents = String::new(); + file.read_to_string(&mut contents)?; + let config: Config = toml::from_str(&contents)?; + Ok(config) +} \ No newline at end of file diff --git a/utils/data_sources.rs b/utils/data_sources.rs new file mode 100644 index 0000000..69f3e33 --- /dev/null +++ b/utils/data_sources.rs @@ -0,0 +1,30 @@ +use crate::error::Result; +use reqwest::Client; +use serde::Deserialize; +use std::collections::HashMap; + +#[derive(Debug, Deserialize)] +pub struct PriceData { + pub symbol: String, + pub price: f64, +} + +pub async fn fetch_prices_from_coingecko(symbols: &[String]) -> Result> { + let url = format!( + "https://api.coingecko.com/api/v3/simple/price?ids={}&vs_currencies=usd", + symbols.join(",") + ); + + let client = Client::new(); + let response = client.get(&url).send().await?; + let prices: HashMap> = response.json().await?; + + let mut price_map = HashMap::new(); + for (symbol, price_data) in prices { + if let Some(price) = price_data.get("usd") { + price_map.insert(symbol, *price); + } + } + + Ok(price_map) +} \ No newline at end of file diff --git a/utils/keypair.rs b/utils/keypair.rs new file mode 100644 index 0000000..708b3bb --- /dev/null +++ b/utils/keypair.rs @@ -0,0 +1,11 @@ +use anyhow::Result; +use solana_sdk::signature::Keypair; +use std::fs::File; +use std::io::BufReader; + +pub fn read_keypair_file(path: &str) -> Result { + let file = File::open(path)?; + let reader = BufReader::new(file); + let keypair = Keypair::from_bytes(&serde_json::from_reader(reader)?)?; + Ok(keypair) +} \ No newline at end of file diff --git a/utils/mod.rs b/utils/mod.rs new file mode 100644 index 0000000..1aa1cf9 --- /dev/null +++ b/utils/mod.rs @@ -0,0 +1 @@ +pub mod solana; \ No newline at end of file diff --git a/utils/profit_calculator.rs b/utils/profit_calculator.rs new file mode 100644 index 0000000..51546b2 --- /dev/null +++ b/utils/profit_calculator.rs @@ -0,0 +1,20 @@ +use crate::error::Result; +use crate::models::market::Market; +use crate::models::order::{Order, OrderSide}; +use rust_decimal::Decimal; + +pub fn calculate_profit(market: &Market, buy_order: &Order, sell_order: &Order) -> Result { + if buy_order.side != OrderSide::Bid || sell_order.side != OrderSide::Ask { + return Err(anyhow!("Invalid order sides for profit calculation")); + } + + let buy_price = Decimal::from_f64(buy_order.price).ok_or_else(|| anyhow!("Invalid buy price"))?; + let sell_price = Decimal::from_f64(sell_order.price).ok_or_else(|| anyhow!("Invalid sell price"))?; + let quantity = Decimal::from_f64(buy_order.quantity).ok_or_else(|| anyhow!("Invalid quantity"))?; + + let buy_value = buy_price * quantity; + let sell_value = sell_price * quantity; + let profit = sell_value - buy_value; + + Ok(profit.to_f64().ok_or_else(|| anyhow!("Failed to convert profit to f64"))?) +} \ No newline at end of file diff --git a/utils/solana.rs b/utils/solana.rs new file mode 100644 index 0000000..1194a53 --- /dev/null +++ b/utils/solana.rs @@ -0,0 +1,46 @@ +use solana_sdk::transaction::Transaction; +use std::error::Error; + +pub fn analyze_transaction(transaction: &Transaction) -> Result> { + let mut analysis = crate::models::transaction_analysis::TransactionAnalysis::default(); + + analysis.signature = transaction.signatures[0].to_string(); + analysis.num_instructions = transaction.message.instructions.len() as u64; + + for (index, instruction) in transaction.message.instructions.iter().enumerate() { + let account_metas = &instruction.accounts; + let num_accounts = account_metas.len() as u64; + let program_id = &instruction.program_id; + + analysis.instructions.push(crate::models::transaction_analysis::InstructionAnalysis { + index: index as u64, + num_accounts, + program_id: program_id.to_string(), + }); + } + + Ok(analysis) +} + +pub fn calculate_profit(transaction: &Transaction) -> Result> { + let mut profit = 0.0; + + for (index, instruction) in transaction.message.instructions.iter().enumerate() { + let account_metas = &instruction.accounts; + + if let Some(transfer_instruction) = instruction.program_id(&spl_token::ID) { + if let Ok(transfer_amount) = spl_token::instruction::unpack_amount(transfer_instruction.data) { + let from_account = &account_metas[0]; + let to_account = &account_metas[1]; + + if from_account.is_signer { + profit -= transfer_amount as f64; + } else if to_account.is_signer { + profit += transfer_amount as f64; + } + } + } + } + + Ok(profit) +} \ No newline at end of file diff --git a/utils/transaction_utils.rs b/utils/transaction_utils.rs new file mode 100644 index 0000000..ae49ac2 --- /dev/null +++ b/utils/transaction_utils.rs @@ -0,0 +1,25 @@ +use crate::error::Result; +use solana_sdk::instruction::Instruction; +use solana_sdk::transaction::Transaction; + +pub fn get_instruction_data(transaction: &Transaction, program_id: &Pubkey) -> Result> { + let instruction = transaction + .message + .instructions + .iter() + .find(|ix| ix.program_id == *program_id) + .ok_or_else(|| anyhow!("Instruction not found for program ID: {}", program_id))?; + + Ok(instruction.data.clone()) +} + +pub fn get_instruction_accounts(transaction: &Transaction, program_id: &Pubkey) -> Result> { + let instruction = transaction + .message + .instructions + .iter() + .find(|ix| ix.program_id == *program_id) + .ok_or_else(|| anyhow!("Instruction not found for program ID: {}", program_id))?; + + Ok(instruction.accounts.iter().map(|account| account.pubkey).collect()) +} \ No newline at end of file diff --git a/wsclient.c b/wsclient.c deleted file mode 100644 index 4847a9f..0000000 --- a/wsclient.c +++ /dev/null @@ -1,1084 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - - -#include - -#include "wsclient.h" -#include "config.h" -#include "sha1.h" - - -void libwsclient_run(wsclient *c) { - if(c->flags & CLIENT_CONNECTING) { - pthread_join(c->handshake_thread, NULL); - pthread_mutex_lock(&c->lock); - c->flags &= ~CLIENT_CONNECTING; - free(c->URI); - c->URI = NULL; - pthread_mutex_unlock(&c->lock); - } - if(c->sockfd) { - pthread_create(&c->run_thread, NULL, libwsclient_run_thread, (void *)c); - } -} - -void *libwsclient_run_thread(void *ptr) { - wsclient *c = (wsclient *)ptr; - wsclient_error *err = NULL; - int sockfd; - char buf[1024]; - int n, i; - do { - memset(buf, 0, 1024); - n = _libwsclient_read(c, buf, 1023); - for(i = 0; i < n; i++) - libwsclient_in_data(c, buf[i]); - - } while(n > 0); - - if(n < 0) { - if(c->onerror) { - err = libwsclient_new_error(WS_RUN_THREAD_RECV_ERR); - err->extra_code = n; - c->onerror(c, err); - free(err); - err = NULL; - } - - } - - if(c->onclose) { - c->onclose(c); - } - close(c->sockfd); - free(c); - return NULL; -} - -void libwsclient_finish(wsclient *client) { - //TODO: handle UNIX socket helper thread shutdown better than killing it... :P - if(client->helper_thread) { - pthread_kill(client->helper_thread, SIGINT); - } - if(client->run_thread) { - pthread_join(client->run_thread, NULL); - } - -} - -void libwsclient_onclose(wsclient *client, int (*cb)(wsclient *c)) { - pthread_mutex_lock(&client->lock); - client->onclose = cb; - pthread_mutex_unlock(&client->lock); -} - -void libwsclient_onopen(wsclient *client, int (*cb)(wsclient *c)) { - pthread_mutex_lock(&client->lock); - client->onopen = cb; - pthread_mutex_unlock(&client->lock); -} - -void libwsclient_onmessage(wsclient *client, int (*cb)(wsclient *c, wsclient_message *msg)) { - pthread_mutex_lock(&client->lock); - client->onmessage = cb; - pthread_mutex_unlock(&client->lock); -} - -void libwsclient_onerror(wsclient *client, int (*cb)(wsclient *c, wsclient_error *err)) { - pthread_mutex_lock(&client->lock); - client->onerror = cb; - pthread_mutex_unlock(&client->lock); -} - -void libwsclient_close(wsclient *client) { - wsclient_error *err = NULL; - char data[6]; - int i = 0, n, mask_int; - struct timeval tv; - gettimeofday(&tv, NULL); - srand(tv.tv_sec * tv.tv_usec); - mask_int = rand(); - memcpy(data+2, &mask_int, 4); - data[0] = 0x88; - data[1] = 0x80; - pthread_mutex_lock(&client->send_lock); - do { - n = _libwsclient_write(client, data, 6); - i += n; - } while(i < 6 && n > 0); - pthread_mutex_unlock(&client->send_lock); - if(n < 0) { - if(client->onerror) { - err = libwsclient_new_error(WS_DO_CLOSE_SEND_ERR); - err->extra_code = n; - client->onerror(client, err); - free(err); - err = NULL; - } - return; - } - pthread_mutex_lock(&client->lock); - client->flags |= CLIENT_SENT_CLOSE_FRAME; - pthread_mutex_unlock(&client->lock); -} - -void libwsclient_handle_control_frame(wsclient *c, wsclient_frame *ctl_frame) { - wsclient_error *err = NULL; - wsclient_frame *ptr = NULL; - int i, n = 0; - char mask[4]; - int mask_int; - struct timeval tv; - gettimeofday(&tv, NULL); - srand(tv.tv_sec * tv.tv_usec); - mask_int = rand(); - memcpy(mask, &mask_int, 4); - pthread_mutex_lock(&c->lock); - switch(ctl_frame->opcode) { - case 0x8: - //close frame - if((c->flags & CLIENT_SENT_CLOSE_FRAME) == 0) { - //server request close. Send close frame as acknowledgement. - for(i=0;ipayload_len;i++) - *(ctl_frame->rawdata + ctl_frame->payload_offset + i) ^= (mask[i % 4] & 0xff); //mask payload - *(ctl_frame->rawdata + 1) |= 0x80; //turn mask bit on - i = 0; - pthread_mutex_lock(&c->send_lock); - while(i < ctl_frame->payload_offset + ctl_frame->payload_len && n >= 0) { - n = _libwsclient_write(c, ctl_frame->rawdata + i, ctl_frame->payload_offset + ctl_frame->payload_len - i); - i += n; - } - pthread_mutex_unlock(&c->send_lock); - if(n < 0) { - if(c->onerror) { - err = libwsclient_new_error(WS_HANDLE_CTL_FRAME_SEND_ERR); - err->extra_code = n; - c->onerror(c, err); - free(err); - err = NULL; - } - } - } - c->flags |= CLIENT_SHOULD_CLOSE; - break; - default: - fprintf(stderr, "Unhandled control frame received. Opcode: %d\n", ctl_frame->opcode); - break; - } - - ptr = ctl_frame->prev_frame; //This very well may be a NULL pointer, but just in case we preserve it. - free(ctl_frame->rawdata); - memset(ctl_frame, 0, sizeof(wsclient_frame)); - ctl_frame->prev_frame = ptr; - ctl_frame->rawdata = (char *)malloc(FRAME_CHUNK_LENGTH); - memset(ctl_frame->rawdata, 0, FRAME_CHUNK_LENGTH); - pthread_mutex_unlock(&c->lock); -} - -inline void libwsclient_in_data(wsclient *c, char in) { - wsclient_frame *current = NULL, *new = NULL; - unsigned char payload_len_short; - pthread_mutex_lock(&c->lock); - if(c->current_frame == NULL) { - c->current_frame = (wsclient_frame *)malloc(sizeof(wsclient_frame)); - memset(c->current_frame, 0, sizeof(wsclient_frame)); - c->current_frame->payload_len = -1; - c->current_frame->rawdata_sz = FRAME_CHUNK_LENGTH; - c->current_frame->rawdata = (char *)malloc(c->current_frame->rawdata_sz); - memset(c->current_frame->rawdata, 0, c->current_frame->rawdata_sz); - } - current = c->current_frame; - if(current->rawdata_idx >= current->rawdata_sz) { - current->rawdata_sz += FRAME_CHUNK_LENGTH; - current->rawdata = (char *)realloc(current->rawdata, current->rawdata_sz); - memset(current->rawdata + current->rawdata_idx, 0, current->rawdata_sz - current->rawdata_idx); - } - *(current->rawdata + current->rawdata_idx++) = in; - pthread_mutex_unlock(&c->lock); - if(libwsclient_complete_frame(c, current) == 1) { - if(current->fin == 1) { - //is control frame - if((current->opcode & 0x08) == 0x08) { - libwsclient_handle_control_frame(c, current); - } else { - libwsclient_dispatch_message(c, current); - c->current_frame = NULL; - } - } else { - new = (wsclient_frame *)malloc(sizeof(wsclient_frame)); - memset(new, 0, sizeof(wsclient_frame)); - new->payload_len = -1; - new->rawdata = (char *)malloc(FRAME_CHUNK_LENGTH); - memset(new->rawdata, 0, FRAME_CHUNK_LENGTH); - new->prev_frame = current; - current->next_frame = new; - c->current_frame = new; - } - } -} - -void libwsclient_dispatch_message(wsclient *c, wsclient_frame *current) { - unsigned long long message_payload_len, message_offset; - int message_opcode, i; - char *message_payload; - wsclient_frame *first = NULL; - wsclient_message *msg = NULL; - wsclient_error *err = NULL; - if(current == NULL) { - if(c->onerror) { - err = libwsclient_new_error(WS_DISPATCH_MESSAGE_NULL_PTR_ERR); - c->onerror(c, err); - free(err); - err = NULL; - } - return; - } - message_offset = 0; - message_payload_len = current->payload_len; - for(;current->prev_frame != NULL;current = current->prev_frame) { - message_payload_len += current->payload_len; - } - first = current; - message_opcode = current->opcode; - message_payload = (char *)malloc(message_payload_len + 1); - memset(message_payload, 0, message_payload_len + 1); - for(;current != NULL; current = current->next_frame) { - memcpy(message_payload + message_offset, current->rawdata + current->payload_offset, current->payload_len); - message_offset += current->payload_len; - } - - - libwsclient_cleanup_frames(first); - msg = (wsclient_message *)malloc(sizeof(wsclient_message)); - memset(msg, 0, sizeof(wsclient_message)); - msg->opcode = message_opcode; - msg->payload_len = message_offset; - msg->payload = message_payload; - if(c->onmessage != NULL) { - c->onmessage(c, msg); - } else { - fprintf(stderr, "No onmessage call back registered with libwsclient.\n"); - } - free(msg->payload); - free(msg); -} -void libwsclient_cleanup_frames(wsclient_frame *first) { - wsclient_frame *this = NULL; - wsclient_frame *next = first; - while(next != NULL) { - this = next; - next = this->next_frame; - if(this->rawdata != NULL) { - free(this->rawdata); - } - free(this); - } -} - -int libwsclient_complete_frame(wsclient *c, wsclient_frame *frame) { - wsclient_error *err = NULL; - int payload_len_short, i; - unsigned long long payload_len = 0; - if(frame->rawdata_idx < 2) { - return 0; - } - frame->fin = (*(frame->rawdata) & 0x80) == 0x80 ? 1 : 0; - frame->opcode = *(frame->rawdata) & 0x0f; - frame->payload_offset = 2; - if((*(frame->rawdata+1) & 0x80) != 0x0) { - if(c->onerror) { - err = libwsclient_new_error(WS_COMPLETE_FRAME_MASKED_ERR); - c->onerror(c, err); - free(err); - err = NULL; - } - pthread_mutex_lock(&c->lock); - c->flags |= CLIENT_SHOULD_CLOSE; - pthread_mutex_unlock(&c->lock); - return 0; - } - payload_len_short = *(frame->rawdata+1) & 0x7f; - switch(payload_len_short) { - case 126: - if(frame->rawdata_idx < 4) { - return 0; - } - for(i = 0; i < 2; i++) { - memcpy((void *)&payload_len+i, frame->rawdata+3-i, 1); - } - frame->payload_offset += 2; - frame->payload_len = payload_len; - break; - case 127: - if(frame->rawdata_idx < 10) { - return 0; - } - for(i = 0; i < 8; i++) { - memcpy((void *)&payload_len+i, frame->rawdata+9-i, 1); - } - frame->payload_offset += 8; - frame->payload_len = payload_len; - break; - default: - frame->payload_len = payload_len_short; - break; - - } - if(frame->rawdata_idx < frame->payload_offset + frame->payload_len) { - return 0; - } - return 1; -} - -int libwsclient_open_connection(const char *host, const char *port) { - struct addrinfo hints, *servinfo, *p; - int rv, sockfd; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - if((rv = getaddrinfo(host, port, &hints, &servinfo)) != 0) { - return WS_OPEN_CONNECTION_ADDRINFO_ERR; - } - - for(p = servinfo; p != NULL; p = p->ai_next) { - if((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { - continue; - } - if(connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) { - close(sockfd); - continue; - } - break; - } - freeaddrinfo(servinfo); - if(p == NULL) { - return WS_OPEN_CONNECTION_ADDRINFO_EXHAUSTED_ERR; - } - return sockfd; -} - -int libwsclient_helper_socket(wsclient *c, const char *path) { - socklen_t len; - int sockfd; - if(c->helper_sa.sun_family) { - fprintf(stderr, "Can only bind one UNIX socket for helper program communications.\n"); - return WS_HELPER_ALREADY_BOUND_ERR; - } - c->helper_sa.sun_family = AF_UNIX; - strncpy(c->helper_sa.sun_path, path, sizeof(c->helper_sa.sun_path) - 1); - unlink(c->helper_sa.sun_path); - len = strlen(c->helper_sa.sun_path) + sizeof(c->helper_sa.sun_family); - sockfd = socket(AF_UNIX, SOCK_STREAM, 0); - if(sockfd == -1) { - fprintf(stderr, "Error creating UNIX socket.\n"); - return WS_HELPER_CREATE_SOCK_ERR; - } - - - if(bind(sockfd, (struct sockaddr *)&c->helper_sa, len) == -1) { - fprintf(stderr, "Error binding UNIX socket.\n"); - perror("bind"); - close(sockfd); - memset(&c->helper_sa, 0, sizeof(struct sockaddr_un)); - return WS_HELPER_BIND_ERR; - } - - if(listen(sockfd, 5) == -1) { - fprintf(stderr, "Error listening on UNIX socket.\n"); - close(sockfd); - memset(&c->helper_sa, 0, sizeof(struct sockaddr_un)); - return WS_HELPER_LISTEN_ERR; - } - - c->helper_sock = sockfd; - pthread_create(&c->helper_thread, NULL, libwsclient_helper_socket_thread, (void *)c); -} - -void *libwsclient_helper_socket_thread(void *ptr) { - wsclient *c = ptr; - struct sockaddr_un remote; - socklen_t len; - int remote_sock, n, n2, flags; - char recv_buf[HELPER_RECV_BUF_SIZE]; - char secondary_buf[HELPER_RECV_BUF_SIZE]; - - - - for(;;) { //TODO: some way to cleanly break this loop - len = sizeof(remote); - - if((remote_sock = accept(c->helper_sock, (struct sockaddr *)&remote, &len)) == -1) { - continue; - } - - pthread_mutex_lock(&c->send_lock); - - n2 = 0; - n = 1; - flags = WS_FRAGMENT_START; - while(1) { - memset(recv_buf, 0, HELPER_RECV_BUF_SIZE); - n = recv(remote_sock, recv_buf, HELPER_RECV_BUF_SIZE - 1, 0); - if(n == 0 && n2 != 0) { - libwsclient_send_fragment(c, secondary_buf, n2, flags | WS_FRAGMENT_FIN); - break; - } - if(n == 0 && n2 == 0) { - fprintf(stderr, "Never received any data from UNIX socket, not sending anything.\n"); - break; - } - if(n != 0 && n2 != 0) { - libwsclient_send_fragment(c, secondary_buf, n2, flags); - flags &= ~WS_FRAGMENT_START; - } - if(n > 0) { - memset(secondary_buf, 0, HELPER_RECV_BUF_SIZE); - memcpy(secondary_buf, recv_buf, n); - n2 = n; - } - if(n < 0) { - fprintf(stderr, "Error occured\n"); - perror("recv"); - break; - } - - } - pthread_mutex_unlock(&c->send_lock); - close(remote_sock); - } - return NULL; -} - -wsclient *libwsclient_new(const char *URI) { - wsclient *client = NULL; - - client = (wsclient *)malloc(sizeof(wsclient)); - if(!client) { - fprintf(stderr, "Unable to allocate memory in libwsclient_new.\n"); - exit(WS_EXIT_MALLOC); - } - memset(client, 0, sizeof(wsclient)); - if(pthread_mutex_init(&client->lock, NULL) != 0) { - fprintf(stderr, "Unable to init mutex in libwsclient_new.\n"); - exit(WS_EXIT_PTHREAD_MUTEX_INIT); - } - if(pthread_mutex_init(&client->send_lock, NULL) != 0) { - fprintf(stderr, "Unable to init send lock in libwsclient_new.\n"); - exit(WS_EXIT_PTHREAD_MUTEX_INIT); - } - pthread_mutex_lock(&client->lock); - client->URI = (char *)malloc(strlen(URI)+1); - if(!client->URI) { - fprintf(stderr, "Unable to allocate memory in libwsclient_new.\n"); - exit(WS_EXIT_MALLOC); - } - memset(client->URI, 0, strlen(URI)+1); - strncpy(client->URI, URI, strlen(URI)); - client->flags |= CLIENT_CONNECTING; - pthread_mutex_unlock(&client->lock); - - if(pthread_create(&client->handshake_thread, NULL, libwsclient_handshake_thread, (void *)client)) { - fprintf(stderr, "Unable to create handshake thread.\n"); - exit(WS_EXIT_PTHREAD_CREATE); - } - return client; -} -void *libwsclient_handshake_thread(void *ptr) { - wsclient *client = (wsclient *)ptr; - wsclient_error *err = NULL; - const char *URI = client->URI; - SHA1Context shactx; - const char *UUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; - char pre_encode[256]; - char sha1bytes[20]; - char expected_base64[512]; - char request_headers[1024]; - char websocket_key[256]; - char key_nonce[16]; - char scheme[10]; - char host[255]; - char request_host[255]; - char port[10]; - char path[255]; - char recv_buf[1024]; - char *URI_copy = NULL, *p = NULL, *rcv = NULL, *tok = NULL; - int i, z, sockfd, n, flags = 0, headers_space = 1024; - URI_copy = (char *)malloc(strlen(URI)+1); - if(!URI_copy) { - fprintf(stderr, "Unable to allocate memory in libwsclient_new.\n"); - exit(WS_EXIT_MALLOC); - } - memset(URI_copy, 0, strlen(URI)+1); - strncpy(URI_copy, URI, strlen(URI)); - p = strstr(URI_copy, "://"); - if(p == NULL) { - fprintf(stderr, "Malformed or missing scheme for URI.\n"); - exit(WS_EXIT_BAD_SCHEME); - } - strncpy(scheme, URI_copy, p-URI_copy); - scheme[p-URI_copy] = '\0'; - if(strcmp(scheme, "ws") != 0 && strcmp(scheme, "wss") != 0) { - fprintf(stderr, "Invalid scheme for URI: %s\n", scheme); - exit(WS_EXIT_BAD_SCHEME); - } - if(strcmp(scheme, "ws") == 0) { - strncpy(port, "80", 9); - } else { - strncpy(port, "443", 9); - pthread_mutex_lock(&client->lock); - client->flags |= CLIENT_IS_SSL; - pthread_mutex_unlock(&client->lock); - } - for(i=p-URI_copy+3,z=0;*(URI_copy+i) != '/' && *(URI_copy+i) != ':' && *(URI_copy+i) != '\0';i++,z++) { - host[z] = *(URI_copy+i); - } - host[z] = '\0'; - if(*(URI_copy+i) == ':') { - i++; - p = strchr(URI_copy+i, '/'); - if(!p) - p = strchr(URI_copy+i, '\0'); - strncpy(port, URI_copy+i, (p - (URI_copy+i))); - port[p-(URI_copy+i)] = '\0'; - i += p-(URI_copy+i); - } - if(*(URI_copy+i) == '\0') { - //end of URI request path will be / - strncpy(path, "/", 1); - } else { - strncpy(path, URI_copy+i, 254); - } - free(URI_copy); - sockfd = libwsclient_open_connection(host, port); - - - if(sockfd < 0) { - if(client->onerror) { - err = libwsclient_new_error(sockfd); - client->onerror(client, err); - free(err); - err = NULL; - } - return NULL; - } - -#ifdef HAVE_LIBSSL - if(client->flags & CLIENT_IS_SSL) { - if((libwsclient_flags & WS_FLAGS_SSL_INIT) == 0) { - SSL_library_init(); - SSL_load_error_strings(); - libwsclient_flags |= WS_FLAGS_SSL_INIT; - } - client->ssl_ctx = SSL_CTX_new(SSLv23_method()); - client->ssl = SSL_new(client->ssl_ctx); - SSL_set_fd(client->ssl, sockfd); - SSL_connect(client->ssl); - } -#endif - - pthread_mutex_lock(&client->lock); - client->sockfd = sockfd; - pthread_mutex_unlock(&client->lock); - //perform handshake - //generate nonce - srand(time(NULL)); - for(z=0;z<16;z++) { - key_nonce[z] = rand() & 0xff; - } - base64_encode(key_nonce, 16, websocket_key, 256); - memset(request_headers, 0, 1024); - - if(strcmp(port, "80") != 0) { - snprintf(request_host, 255, "%s:%s", host, port); - } else { - snprintf(request_host, 255, "%s", host); - } - snprintf(request_headers, 1024, "GET %s HTTP/1.1\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nHost: %s\r\nSec-WebSocket-Key: %s\r\nSec-WebSocket-Version: 13\r\n\r\n", path, request_host, websocket_key); - n = _libwsclient_write(client, request_headers, strlen(request_headers)); - z = 0; - memset(recv_buf, 0, 1024); - //TODO: actually handle data after \r\n\r\n in case server - // sends post-handshake data that gets coalesced in this recv - do { - n = _libwsclient_read(client, recv_buf + z, 1023 - z); - z += n; - } while((z < 4 || strstr(recv_buf, "\r\n\r\n") == NULL) && n > 0); - - if(n == 0) { - if(client->onerror) { - err = libwsclient_new_error(WS_HANDSHAKE_REMOTE_CLOSED_ERR); - client->onerror(client, err); - free(err); - err = NULL; - } - return NULL; - } - if(n < 0) { - if(client->onerror) { - err = libwsclient_new_error(WS_HANDSHAKE_RECV_ERR); - err->extra_code = n; - client->onerror(client, err); - free(err); - err = NULL; - } - return NULL; - } - //parse recv_buf for response headers and assure Accept matches expected value - rcv = (char *)malloc(strlen(recv_buf)+1); - if(!rcv) { - fprintf(stderr, "Unable to allocate memory in libwsclient_new.\n"); - exit(WS_EXIT_MALLOC); - } - memset(rcv, 0, strlen(recv_buf)+1); - strncpy(rcv, recv_buf, strlen(recv_buf)); - memset(pre_encode, 0, 256); - snprintf(pre_encode, 256, "%s%s", websocket_key, UUID); - SHA1Reset(&shactx); - SHA1Input(&shactx, pre_encode, strlen(pre_encode)); - SHA1Result(&shactx); - memset(pre_encode, 0, 256); - snprintf(pre_encode, 256, "%08x%08x%08x%08x%08x", shactx.Message_Digest[0], shactx.Message_Digest[1], shactx.Message_Digest[2], shactx.Message_Digest[3], shactx.Message_Digest[4]); - for(z = 0; z < (strlen(pre_encode)/2);z++) - sscanf(pre_encode+(z*2), "%02hhx", sha1bytes+z); - memset(expected_base64, 0, 512); - base64_encode(sha1bytes, 20, expected_base64, 512); - for(tok = strtok(rcv, "\r\n"); tok != NULL; tok = strtok(NULL, "\r\n")) { - if(*tok == 'H' && *(tok+1) == 'T' && *(tok+2) == 'T' && *(tok+3) == 'P') { - p = strchr(tok, ' '); - p = strchr(p+1, ' '); - *p = '\0'; - if(strcmp(tok, "HTTP/1.1 101") != 0 && strcmp(tok, "HTTP/1.0 101") != 0) { - if(client->onerror) { - err = libwsclient_new_error(WS_HANDSHAKE_BAD_STATUS_ERR); - client->onerror(client, err); - free(err); - err = NULL; - } - return NULL; - } - flags |= REQUEST_VALID_STATUS; - } else { - p = strchr(tok, ' '); - *p = '\0'; - if(strcmp(tok, "Upgrade:") == 0) { - if(stricmp(p+1, "websocket") == 0) { - flags |= REQUEST_HAS_UPGRADE; - } - } - if(strcmp(tok, "Connection:") == 0) { - if(stricmp(p+1, "upgrade") == 0) { - flags |= REQUEST_HAS_CONNECTION; - } - } - if(strcmp(tok, "Sec-WebSocket-Accept:") == 0) { - if(strcmp(p+1, expected_base64) == 0) { - flags |= REQUEST_VALID_ACCEPT; - } - } - } - } - if(!flags & REQUEST_HAS_UPGRADE) { - if(client->onerror) { - err = libwsclient_new_error(WS_HANDSHAKE_NO_UPGRADE_ERR); - client->onerror(client, err); - free(err); - err = NULL; - } - return NULL; - } - if(!flags & REQUEST_HAS_CONNECTION) { - if(client->onerror) { - err = libwsclient_new_error(WS_HANDSHAKE_NO_CONNECTION_ERR); - client->onerror(client, err); - free(err); - err = NULL; - } - return NULL; - } - if(!flags & REQUEST_VALID_ACCEPT) { - if(client->onerror) { - err = libwsclient_new_error(WS_HANDSHAKE_BAD_ACCEPT_ERR); - client->onerror(client, err); - free(err); - err = NULL; - } - return NULL; - } - - - pthread_mutex_lock(&client->lock); - client->flags &= ~CLIENT_CONNECTING; - pthread_mutex_unlock(&client->lock); - if(client->onopen != NULL) { - client->onopen(client); - } - return NULL; -} - -//somewhat hackish stricmp -int stricmp(const char *s1, const char *s2) { - register unsigned char c1, c2; - register unsigned char flipbit = ~(1 << 5); - do { - c1 = (unsigned char)*s1++ & flipbit; - c2 = (unsigned char)*s2++ & flipbit; - if(c1 == '\0') - return c1 - c2; - } while(c1 == c2); - return c1 - c2; -} - -wsclient_error *libwsclient_new_error(int errcode) { - wsclient_error *err = NULL; - err = (wsclient_error *)malloc(sizeof(wsclient_error)); - if(!err) { - //one of the few places we will fail and exit - fprintf(stderr, "Unable to allocate memory in libwsclient_new_error.\n"); - exit(errcode); - } - memset(err, 0, sizeof(wsclient_error)); - err->code = errcode; - switch(err->code) { - case WS_OPEN_CONNECTION_ADDRINFO_ERR: - err->str = *(errors + 1); - break; - case WS_OPEN_CONNECTION_ADDRINFO_EXHAUSTED_ERR: - err->str = *(errors + 2); - break; - case WS_RUN_THREAD_RECV_ERR: - err->str = *(errors + 3); - break; - case WS_DO_CLOSE_SEND_ERR: - err->str = *(errors + 4); - break; - case WS_HANDLE_CTL_FRAME_SEND_ERR: - err->str = *(errors + 5); - break; - case WS_COMPLETE_FRAME_MASKED_ERR: - err->str = *(errors + 6); - break; - case WS_DISPATCH_MESSAGE_NULL_PTR_ERR: - err->str = *(errors + 7); - break; - case WS_SEND_AFTER_CLOSE_FRAME_ERR: - err->str = *(errors + 8); - break; - case WS_SEND_DURING_CONNECT_ERR: - err->str = *(errors + 9); - break; - case WS_SEND_NULL_DATA_ERR: - err->str = *(errors + 10); - break; - case WS_SEND_DATA_TOO_LARGE_ERR: - err->str = *(errors + 11); - break; - case WS_SEND_SEND_ERR: - err->str = *(errors + 12); - break; - case WS_HANDSHAKE_REMOTE_CLOSED_ERR: - err->str = *(errors + 13); - break; - case WS_HANDSHAKE_RECV_ERR: - err->str = *(errors + 14); - break; - case WS_HANDSHAKE_BAD_STATUS_ERR: - err->str = *(errors + 15); - break; - case WS_HANDSHAKE_NO_UPGRADE_ERR: - err->str = *(errors + 16); - break; - case WS_HANDSHAKE_NO_CONNECTION_ERR: - err->str = *(errors + 17); - break; - case WS_HANDSHAKE_BAD_ACCEPT_ERR: - err->str = *(errors + 18); - break; - default: - err->str = *errors; - break; - } - - return err; -} - -int libwsclient_send_fragment(wsclient *client, char *strdata, int len, int flags) { - wsclient_error *err = NULL; - struct timeval tv; - unsigned char mask[4]; - unsigned int mask_int; - unsigned long long payload_len; - unsigned char finNopcode; - unsigned int payload_len_small; - unsigned int payload_offset = 6; - unsigned int len_size; - unsigned long long be_payload_len; - unsigned int sent = 0; - int i, sockfd; - unsigned int frame_size; - char *data = NULL; - - - sockfd = client->sockfd; - - - if(client->flags & CLIENT_SENT_CLOSE_FRAME) { - if(client->onerror) { - err = libwsclient_new_error(WS_SEND_AFTER_CLOSE_FRAME_ERR); - client->onerror(client, err); - free(err); - err = NULL; - } - return 0; - } - if(client->flags & CLIENT_CONNECTING) { - if(client->onerror) { - err = libwsclient_new_error(WS_SEND_DURING_CONNECT_ERR); - client->onerror(client, err); - free(err); - err = NULL; - } - return 0; - } - - if(strdata == NULL) { - if(client->onerror) { - err = libwsclient_new_error(WS_SEND_NULL_DATA_ERR); - client->onerror(client, err); - free(err); - err = NULL; - } - return 0; - } - - gettimeofday(&tv, NULL); - srand(tv.tv_usec * tv.tv_sec); - mask_int = rand(); - memcpy(mask, &mask_int, 4); - payload_len = len; - if(payload_len <= 125) { - frame_size = 6 + payload_len; - payload_len_small = payload_len; - - } else if(payload_len > 125 && payload_len <= 0xffff) { - frame_size = 8 + payload_len; - payload_len_small = 126; - payload_offset += 2; - } else if(payload_len > 0xffff && payload_len <= 0xffffffffffffffffLL) { - frame_size = 14 + payload_len; - payload_len_small = 127; - payload_offset += 8; - } else { - if(client->onerror) { - err = libwsclient_new_error(WS_SEND_DATA_TOO_LARGE_ERR); - client->onerror(client, err); - free(err); - err = NULL; - } - return 0; - } - data = (char *)malloc(frame_size); - - memset(data, 0, frame_size); - *data = flags & 0xff; - *(data+1) = payload_len_small | 0x80; //payload length with mask bit on - if(payload_len_small == 126) { - payload_len &= 0xffff; - len_size = 2; - for(i = 0; i < len_size; i++) { - *(data+2+i) = *((char *)&payload_len+(len_size-i-1)); - } - } - if(payload_len_small == 127) { - payload_len &= 0xffffffffffffffffLL; - len_size = 8; - for(i = 0; i < len_size; i++) { - *(data+2+i) = *((char *)&payload_len+(len_size-i-1)); - } - } - for(i=0;i<4;i++) - *(data+(payload_offset-4)+i) = mask[i] & 0xff; - - memcpy(data+payload_offset, strdata, len); - for(i=0;i 0) { - i = _libwsclient_write(client, data+sent, frame_size - sent); - sent += i; - } - - - if(i < 0) { - if(client->onerror) { - err = libwsclient_new_error(WS_SEND_SEND_ERR); - client->onerror(client, err); - free(err); - err = NULL; - } - } - - free(data); - return sent; -} - -int libwsclient_send(wsclient *client, char *strdata) { - wsclient_error *err = NULL; - struct timeval tv; - unsigned char mask[4]; - unsigned int mask_int; - unsigned long long payload_len; - unsigned char finNopcode; - unsigned int payload_len_small; - unsigned int payload_offset = 6; - unsigned int len_size; - unsigned long long be_payload_len; - unsigned int sent = 0; - int i, sockfd; - unsigned int frame_size; - char *data; - - sockfd = client->sockfd; - - if(client->flags & CLIENT_SENT_CLOSE_FRAME) { - if(client->onerror) { - err = libwsclient_new_error(WS_SEND_AFTER_CLOSE_FRAME_ERR); - client->onerror(client, err); - free(err); - err = NULL; - } - return 0; - } - if(client->flags & CLIENT_CONNECTING) { - if(client->onerror) { - err = libwsclient_new_error(WS_SEND_DURING_CONNECT_ERR); - client->onerror(client, err); - free(err); - err = NULL; - } - return 0; - } - if(strdata == NULL) { - if(client->onerror) { - err = libwsclient_new_error(WS_SEND_NULL_DATA_ERR); - client->onerror(client, err); - free(err); - err = NULL; - } - return 0; - } - - gettimeofday(&tv, NULL); - srand(tv.tv_usec * tv.tv_sec); - mask_int = rand(); - memcpy(mask, &mask_int, 4); - payload_len = strlen(strdata); - finNopcode = 0x81; //FIN and text opcode. - if(payload_len <= 125) { - frame_size = 6 + payload_len; - payload_len_small = payload_len; - - } else if(payload_len > 125 && payload_len <= 0xffff) { - frame_size = 8 + payload_len; - payload_len_small = 126; - payload_offset += 2; - } else if(payload_len > 0xffff && payload_len <= 0xffffffffffffffffLL) { - frame_size = 14 + payload_len; - payload_len_small = 127; - payload_offset += 8; - } else { - if(client->onerror) { - err = libwsclient_new_error(WS_SEND_DATA_TOO_LARGE_ERR); - client->onerror(client, err); - free(err); - err = NULL; - } - return -1; - } - data = (char *)malloc(frame_size); - memset(data, 0, frame_size); - *data = finNopcode; - *(data+1) = payload_len_small | 0x80; //payload length with mask bit on - if(payload_len_small == 126) { - payload_len &= 0xffff; - len_size = 2; - for(i = 0; i < len_size; i++) { - *(data+2+i) = *((char *)&payload_len+(len_size-i-1)); - } - } - if(payload_len_small == 127) { - payload_len &= 0xffffffffffffffffLL; - len_size = 8; - for(i = 0; i < len_size; i++) { - *(data+2+i) = *((char *)&payload_len+(len_size-i-1)); - } - } - for(i=0;i<4;i++) - *(data+(payload_offset-4)+i) = mask[i]; - - memcpy(data+payload_offset, strdata, strlen(strdata)); - for(i=0;isend_lock); - while(sent < frame_size && i >= 0) { - i = _libwsclient_write(client, data+sent, frame_size - sent); - sent += i; - } - pthread_mutex_unlock(&client->send_lock); - - if(i < 0) { - if(client->onerror) { - err = libwsclient_new_error(WS_SEND_SEND_ERR); - client->onerror(client, err); - free(err); - err = NULL; - } - } - - free(data); - return sent; -} - -ssize_t _libwsclient_read(wsclient *c, void *buf, size_t length) { -#ifdef HAVE_LIBSSL - if(c->flags & CLIENT_IS_SSL) { - return (ssize_t)SSL_read(c->ssl, buf, length); - } else { -#endif - return recv(c->sockfd, buf, length, 0); -#ifdef HAVE_LIBSSL - } -#endif -} - -ssize_t _libwsclient_write(wsclient *c, const void *buf, size_t length) { -#ifdef HAVE_LIBSSL - if(c->flags & CLIENT_IS_SSL) { - return (ssize_t)SSL_write(c->ssl, buf, length); - } else { -#endif - return send(c->sockfd, buf, length, 0); -#ifdef HAVE_LIBSSL - } -#endif -} - - diff --git a/wsclient.h b/wsclient.h deleted file mode 100644 index 5850aa8..0000000 --- a/wsclient.h +++ /dev/null @@ -1,167 +0,0 @@ -#ifndef WSCLIENT_H_ -#define WSCLIENT_H_ - -#include -#include -#include -#include -#include -#include - -#include "config.h" - - -#ifdef HAVE_LIBSSL -#include -#include -#include -#endif - - - -#define FRAME_CHUNK_LENGTH 1024 -#define HELPER_RECV_BUF_SIZE 1024 - -#define CLIENT_IS_SSL (1 << 0) -#define CLIENT_CONNECTING (1 << 1) -#define CLIENT_SHOULD_CLOSE (1 << 2) -#define CLIENT_SENT_CLOSE_FRAME (1 << 3) - - -#define REQUEST_HAS_CONNECTION (1 << 0) -#define REQUEST_HAS_UPGRADE (1 << 1) -#define REQUEST_VALID_STATUS (1 << 2) -#define REQUEST_VALID_ACCEPT (1 << 3) - -#define WS_FRAGMENT_START (1 << 0) -#define WS_FRAGMENT_FIN (1 << 7) - -#define WS_FLAGS_SSL_INIT (1 << 0) - -#define WS_EXIT_MALLOC -1 -#define WS_EXIT_PTHREAD_MUTEX_INIT -2 -#define WS_EXIT_PTHREAD_CREATE -3 -#define WS_EXIT_BAD_SCHEME -4 - - -#define WS_OPEN_CONNECTION_ADDRINFO_ERR -1 -#define WS_OPEN_CONNECTION_ADDRINFO_EXHAUSTED_ERR -2 -#define WS_RUN_THREAD_RECV_ERR -3 -#define WS_DO_CLOSE_SEND_ERR -4 -#define WS_HANDLE_CTL_FRAME_SEND_ERR -5 -#define WS_COMPLETE_FRAME_MASKED_ERR -6 -#define WS_DISPATCH_MESSAGE_NULL_PTR_ERR -7 -#define WS_SEND_AFTER_CLOSE_FRAME_ERR -8 -#define WS_SEND_DURING_CONNECT_ERR -9 -#define WS_SEND_NULL_DATA_ERR -10 -#define WS_SEND_DATA_TOO_LARGE_ERR -11 -#define WS_SEND_SEND_ERR -12 -#define WS_HANDSHAKE_REMOTE_CLOSED_ERR -13 -#define WS_HANDSHAKE_RECV_ERR -14 -#define WS_HANDSHAKE_BAD_STATUS_ERR -15 -#define WS_HANDSHAKE_NO_UPGRADE_ERR -16 -#define WS_HANDSHAKE_NO_CONNECTION_ERR -17 -#define WS_HANDSHAKE_BAD_ACCEPT_ERR -18 -#define WS_HELPER_ALREADY_BOUND_ERR -19 -#define WS_HELPER_CREATE_SOCK_ERR -20 -#define WS_HELPER_BIND_ERR -21 -#define WS_HELPER_LISTEN_ERR -22 - -typedef struct _wsclient_frame { - unsigned int fin; - unsigned int opcode; - unsigned int mask_offset; - unsigned int payload_offset; - unsigned int rawdata_idx; - unsigned int rawdata_sz; - unsigned long long payload_len; - char *rawdata; - struct _wsclient_frame *next_frame; - struct _wsclient_frame *prev_frame; - unsigned char mask[4]; -} wsclient_frame; - -typedef struct _wsclient_message { - unsigned int opcode; - unsigned long long payload_len; - char *payload; -} wsclient_message; - -typedef struct _wsclient_error { - int code; - int extra_code; - char *str; -} wsclient_error; - -typedef struct _wsclient { - pthread_t helper_thread; - pthread_t handshake_thread; - pthread_t run_thread; - pthread_mutex_t lock; - pthread_mutex_t send_lock; - char *URI; - int sockfd; - int flags; - int (*onopen)(struct _wsclient *); - int (*onclose)(struct _wsclient *); - int (*onerror)(struct _wsclient *, wsclient_error *err); - int (*onmessage)(struct _wsclient *, wsclient_message *msg); - wsclient_frame *current_frame; - struct sockaddr_un helper_sa; - int helper_sock; -#ifdef HAVE_LIBSSL - SSL_CTX *ssl_ctx; - SSL *ssl; -#endif -} wsclient; - - -//Function defs - -wsclient *libwsclient_new(const char *URI); -wsclient_error *libwsclient_new_error(int errcode); -ssize_t _libwsclient_read(wsclient *c, void *buf, size_t length); -ssize_t _libwsclient_write(wsclient *c, const void *buf, size_t length); -int libwsclient_open_connection(const char *host, const char *port); -int stricmp(const char *s1, const char *s2); -int libwsclient_complete_frame(wsclient *c, wsclient_frame *frame); -void libwsclient_handle_control_frame(wsclient *c, wsclient_frame *ctl_frame); -void libwsclient_run(wsclient *c); -void libwsclient_finish(wsclient *client); -void *libwsclient_run_thread(void *ptr); -void *libwsclient_handshake_thread(void *ptr); -void libwsclient_cleanup_frames(wsclient_frame *first); -void libwsclient_in_data(wsclient *c, char in); -void libwsclient_dispatch_message(wsclient *c, wsclient_frame *current); -void libwsclient_close(wsclient *c); -int libwsclient_helper_socket(wsclient *c, const char *path); -void *libwsclient_helper_socket_thread(void *ptr); - -//Define errors -char *errors[] = { - "Unknown error occured", - "Error while getting address info", - "Could connect to any address returned by getaddrinfo", - "Error receiving data in client run thread", - "Error during libwsclient_close", - "Error sending while handling control frame", - "Received masked frame from server", - "Got null pointer during message dispatch", - "Attempted to send after close frame was sent", - "Attempted to send during connect", - "Attempted to send null payload", - "Attempted to send too much data", - "Error during send in libwsclient_send", - "Remote end closed connection during handshake", - "Problem receiving data during handshake", - "Remote web server responded with bad HTTP status during handshake", - "Remote web server did not respond with upgrade header during handshake", - "Remote web server did not respond with connection header during handshake", - "Remote web server did not specify the appropriate Sec-WebSocket-Accept header during handshake", - NULL -}; - -int libwsclient_flags; //global flags variable - - -#endif /* WSCLIENT_H_ */